在工作中,我们使用稀疏文件作为来宾磁盘映像的 Oracle VM 环境的一部分。在询问了同事的一些问题(现已得到解答)后,我留下了更多有关稀疏文件的问题,也许更广泛地有关 inode 结构的问题 - 阅读 stat(2) 和 statfs(2) (在 FreeBSD 上)的手册页给人的印象是,如果我了解更多的 C,我会更容易理解,但可惜的是,我对 C 的了解充其量是最少的......
我知道其中一些取决于文件系统类型。我最感兴趣的是 FreeBSD/Solaris 和 ext4 上的 UFS - ZFS 会是一个优点,但我不会抱有希望:)
我经常使用 Solaris 10、FreeBSD 10.3 和 CentOS 6.7。此处的命令在 CentOS 6.7 VM 上运行,但已与 FreeBSD 交叉引用。如果可能的话,我有兴趣从 POSIX 的角度获得理解,如果不可能的话,我会倾向于使用 FreeBSD 而不是 Linux。
考虑以下命令集:
printf "BIL" > /tmp/BIL
dd of=/tmp/sparse bs=1 count=0 seek=10
dd if=/tmp/BIL of=/tmp/sparse bs=1 count=3 seek=10
dd if=/tmp/BIL of=/tmp/sparse bs=1 count=3 seek=17
dd of=/tmp/sparse bs=1 count=0 seek=30
dd if=/tmp/BIL of=/tmp/sparse bs=1 count=3 seek=30
该文件/tmp/BIL
应该包含 的内容(以十六进制表示)4942 004c
,因此当我查看hexdump
该文件时/tmp/sparse
,我应该会在整个文件中看到一些这种组合:
%>hexdump sparse
0000000 0000 4942 004c 0000 0000 4942 004c 0000
0000010 4200 4c49 0000 0000 0000 0000 0000 4942
0000020 004c
0000021
%>cat sparse
BILBILBILBIL%
1. 为什么第二次出现“BIL”时出现乱序?即4200 4c49
而不是4942 004c
?这是第三个dd
命令写的。
2. 其他工具如何cat
知道以正确的顺序打印?
使用ls
我们可以看到据称使用的空间和分配的块:
%>ls -ls /tmp/sparse
8.0K -rw-r--r--. 1 bil bil 33 May 26 14:17 /tmp/sparse
我们可以看到,所谓的大小是 33 字节,但分配的大小是 8 KB(文件系统块大小是 4K)。
3. 像这样的程序如何ls
区分“所谓的”大小和分配的大小?
我想知道存储在 inode 中的“所谓的”数字是否是通过遍历直接和间接块来计算的,而分配的大小是通过遍历直接和间接块来计算的 - 尽管这不可能正确,因为通过遍历进行计算需要时间和ls
快速返回等工具,即使对于非常大的文件也是如此。
4. 我可以使用什么工具来查询inode信息?
我知道stat
,但它似乎没有打印出索引节点中所有字段的值......
5. 有没有可以遍历直接和间接块的工具?
查看磁盘上的每个地址以及内容以更好地了解数据的存储方式会很有趣
如果我在上面的其他命令之后运行以下命令,该文件/tmp/sparse
将被截断:
%>dd of=/tmp/sparse bs=1 count=0 seek=5
%>hexdump sparse
0000000 0000 4942 004c
0000005
6. 为什么dd
截断我的文件并且可以dd
或其他工具写入文件的中间?
最后,稀疏文件似乎是预分配空间的好主意,但似乎没有文件系统或操作系统级别保证 a 命令不会截断或任意增长文件。
7. 是否有机制可以防止稀疏文件缩小/增长?如果没有,为什么稀疏文件有用?
虽然上面的每个问题都可能是一个单独的问题,但我无法剖析它们,因为它们都与底层理解相关。
答案1
一些快速答案:首先,您没有创建稀疏文件。尝试这些额外的命令
dd if=/tmp/BIL of=/tmp/sparse seek=1000
ls -ls /tmp/sparse
您将看到大小为 512003 字节,但只占用 8 个块。空字节必须占据整个块,并且位于块边界上,以便它们在文件系统中可能是稀疏的。
为什么第二次出现“BIL”时出现乱序?
因为您使用的是小端系统,并且您正在以简短的形式编写输出。像 cat 一样使用字节。
cat 和其他工具如何知道以正确的顺序打印?
他们以字节为单位工作。
像 ls 这样的程序如何辨别“所谓的”大小和分配的大小?
ls
依此类推,使用stat(2)
返回 2 个值的系统调用:st_size; /* total size, in bytes */ blkcnt_t st_blocks; /* number of 512B blocks allocated */
我可以使用哪些工具来查询 inode 信息?
统计数据很好。
有没有一种工具可以让我遍历直接和间接块?
在 ext2/3/4 上,您可以使用
hdparm --fibmap
以下文件名:$ sudo hdparm --fibmap ~/sparse filesystem blocksize 4096, begins at LBA 25167872; assuming 512 byte sectors. byte_offset begin_LBA end_LBA sectors 512000 226080744 226080751 8
您还可以使用
debugfs
:$ sudo debugfs /dev/sda3 debugfs: stat <1040667> Inode: 1040667 Type: regular Mode: 0644 Flags: 0x0 Generation: 1161905167 Version: 0x00000000 User: 127 Group: 500 Size: 335360 File ACL: 0 Directory ACL: 0 Links: 1 Blockcount: 664 Fragment: Address: 0 Number: 0 Size: 0 ctime: 0x4dd61e6c -- Fri May 20 09:55:24 2011 atime: 0x4dd61e29 -- Fri May 20 09:54:17 2011 mtime: 0x4dd61e6c -- Fri May 20 09:55:24 2011 Size of extra inode fields: 4 BLOCKS: (0-11):4182714-4182725, (IND):4182726, (12-81):4182727-4182796 TOTAL: 83
为什么 dd 会截断我的文件并且 dd 或其他工具可以写入文件的中间?
是的,
dd
可以写到中间。添加conv=notrunc
。是否有机制可以防止稀疏文件缩小/增大?如果没有,为什么稀疏文件有用?
不会。因为它们占用的空间更少。
文件的稀疏性对于程序来说应该是完全透明的,这有时意味着当程序更新文件时稀疏性可能会丢失。
一些复制实用程序具有保留稀疏性的选项,例如tar --sparse
, rsync --sparse
。
cp --sparse=always
请注意,您可以通过使用和 相反,将文件中适当对齐的零块显式转换为稀疏空间,将稀疏空间转换为真正的零,使用cp --sparse=never
.
答案2
在 Linux 上转储文件布局的更好工具是软件包filefrag
中包含的实用程序e2fsprogs
。这将以高效且紧凑的方式转储文件中的所有范围:
$ dd of=/var/tmp/sparse if=/dev/zero count=1
$ dd of=/var/tmp/sparse if=/dev/zero seek=1000 count=1
$ filefrag -v /var/tmp/sparse
Filesystem type is: ef53
File size of /var/tmp/sparse is 512512 (126 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 0: 3441408.. 3441408: 1:
1: 125.. 125: 3441533.. 3441533: 1: 3441409: last,eof
/var/tmp/sparse: 2 extents found
FIEMAP ioctl 可用于大多数常见的 Linux 文件系统(ext4、XFS、Btrfs 等),但尚不适用于 ZFS(尽管正在开发中)。