如何确定 btrfs 上的文件是否是写时复制?

如何确定 btrfs 上的文件是否是写时复制?

我知道可以cp选择--reflink控制完整副本与写入时复制“副本”。

在 btrfs 上,我可以使用ls(或其他命令)来查明一个文件是否与另一个文件共享(在写时复制意义上)某些存储?

编辑:@StéphaneChazelas 向我指出filefrag,但这对我来说失败了:

root@void:/tmp/mount# mount | tail -1
/tmp/back on /tmp/mount type btrfs (rw,relatime,space_cache)
root@void:/tmp/mount# df -h | tail -1
/dev/loop0       32M   13M   20M  38% /tmp/mount
root@void:/tmp/mount# ls -lh
total 8.0M
-rw-r--r-- 1 root root 8.0M Jan 19 08:43 one
root@void:/tmp/mount# cp --reflink=always one two
root@void:/tmp/mount# sync
root@void:/tmp/mount# ls -lh
total 16M
-rw-r--r-- 1 root root 8.0M Jan 19 08:43 one
-rw-r--r-- 1 root root 8.0M Jan 19 08:45 two
root@void:/tmp/mount# df -h | tail -1
/dev/loop0       32M   13M   20M  38% /tmp/mount
root@void:/tmp/mount# filefrag -kvx one 
Filesystem type is: 9123683e
File size of one is 8388608 (8192 blocks of 1024 bytes)
FIEMAP failed with unknown flags 2
one: FIBMAP unsupported
root@void:/tmp/mount# uname -a
Linux void 4.1.7+ #817 PREEMPT Sat Sep 19 15:25:36 BST 2015 armv6l GNU/Linux

答案1

更新(2021 年 1 月):请参阅@bitinerant 的评论:“btrfs-debug-tree 现已过时;使用 btrfs inform-internal dump-tree”


我不知道如何通过ls命令找到它。但如果你真的想要它,你可以使用btrfs-progs/btrfs-调试树

引用链接=始终,文件将共享一个公共数据块。这个公共数据块(又名扩展区)的引用数超过 1。

  1. 首先,您需要找到文件一和文件二的objectid

     #./btrfs-debug-tree  /dev/xvdc
     (Check under FS_TREE)
       <snip>
         item 8 key (256 DIR_INDEX 4) itemoff 15842 itemsize 33
             location key (259 INODE_ITEM 0) type FILE
             namelen 3 datalen 0 name: one
         item 9 key (256 DIR_INDEX 5) itemoff 15809 itemsize 33
             location key (260 INODE_ITEM 0) type FILE
             namelen 3 datalen 0 name: two
       </snip>
    

从上面我们可以看到它的259(一)260(二)

  1. 现在找到它的参考文献。来自范围树。下面的命令将查找两个文件之间共享的数据块。

     # ./btrfs-debug-tree  /dev/xvdc | grep -A2 "refs 2"
             extent refs 2 gen 9 flags DATA
             extent data backref root 5 objectid 260 offset 0 count 1
             extent data backref root 5 objectid 259 offset 0 count 1
    

奖励:创建另一个参考:

# cp --reflink=always one three

验证引用计数是否增加 1。

# ./btrfs-debug-tree   /dev/xvdc | grep -A3 "refs 3"
        extent refs 3 gen 9 flags DATA
        extent data backref root 5 objectid 260 offset 0 count 1
        extent data backref root 5 objectid 261 offset 0 count 1
        extent data backref root 5 objectid 259 offset 0 count 1

这里数据块在objectid指向的三个文件之间共享259,260,261

答案2

只需使用:

$ btrfs filesystem du .
       Total   Exclusive  Set shared  Filename
    1.11GiB     1.11GiB           -  ./file1
    1.12GiB     1.12GiB           -  ./file2
    1.31GiB       0.00B           -  ./file3
    3.54GiB     2.23GiB     1.31GiB  .

在此示例中,“file3”是引用链接副本,因为它不消耗任何独占空间。

答案3

@pwaller的回答显示可以比较每个文件的数据范围列表,以查看两个文件是否共享相同的范围。 filefrage2fsprogs包装中可以(几乎)做到这一点。 filefrag -v FILE1 FILE2将显示 FILE1 和 FILE2 是否具有相同的范围,在这种情况下它们是彼此的重新链接。

在脚本中以编程方式执行此操作比较困难,因为filefrag会输出文件名。为此,我有一个修补副本,其中filefrag进行了两项更改:

  1. 输出设备ID
  2. 如果只指定一个文件名,则不输出文件名

filefrag通过这些更改,可以比较两次调用的输出。如果相同,则这两个文件是彼此的引用链接。

最后一个警告:如果 的输出与filefragregex 匹配inline|unknown_loc|delalloc,则该文件无法重新链接,因为它没有数据块。为了处理这种情况,我通过检查该模式来包装修补程序filefrag,如果找到它,则将文件名本身附加到输出中(以使每个文件名的输出唯一,以便它不会与不同文件名的输出匹配)。请参阅@StéphaneChazelas 的评论这里更多细节。

我提交了拉取请求(https://github.com/tytso/e2fsprogs/pull/87)和一个问题(https://github.com/tytso/e2fsprogs/issues/88) 为了这。

答案4

至少xfs如果文件没有被更改,则filefrag设置一个shared标志。

例如:

 >filefrag -e foobar
 Filesystem type is: 58465342
 File size of filesystems.docker is 1344 (1 block of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
 0:        0..       0:  348117738.. 348117738:      1:             last,eof
 foo: 1 extent found

 >cp --reflink=auto foo bar
 >filefrag -e foo
 Filesystem type is: 58465342
 File size of filesystems.docker is 1344 (1 block of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
 0:        0..       0:  348117738.. 348117738:      1:             last,shared,eof
 foo: 1 extent found

警告:我不确定如果文件的一部分被更改以便只有一些块是公共的,会发生什么。

警告 2:我不知道这是否适用于 btrfs(如果适用,请评论或编辑)

相关内容