![如何确定 btrfs 上的文件是否是写时复制?](https://linux22.com/image/81581/%E5%A6%82%E4%BD%95%E7%A1%AE%E5%AE%9A%20btrfs%20%E4%B8%8A%E7%9A%84%E6%96%87%E4%BB%B6%E6%98%AF%E5%90%A6%E6%98%AF%E5%86%99%E6%97%B6%E5%A4%8D%E5%88%B6%EF%BC%9F.png)
我知道可以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。
首先,您需要找到文件一和文件二的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(二)。
现在找到它的参考文献。来自范围树。下面的命令将查找两个文件之间共享的数据块。
# ./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的回答显示可以比较每个文件的数据范围列表,以查看两个文件是否共享相同的范围。 filefrag
从e2fsprogs
包装中可以(几乎)做到这一点。
filefrag -v FILE1 FILE2
将显示 FILE1 和 FILE2 是否具有相同的范围,在这种情况下它们是彼此的重新链接。
在脚本中以编程方式执行此操作比较困难,因为filefrag
会输出文件名。为此,我有一个修补副本,其中filefrag
进行了两项更改:
- 输出设备ID
- 如果只指定一个文件名,则不输出文件名
filefrag
通过这些更改,可以比较两次调用的输出。如果相同,则这两个文件是彼此的引用链接。
最后一个警告:如果 的输出与filefrag
regex 匹配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(如果适用,请评论或编辑)