了解稀疏文件、dd、seek、inode 块结构

for*_*are 7 filesystems dd inode sparse-files

在工作中,我们使用稀疏文件作为来宾磁盘映像的 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 虚拟机上运行,​​但已与 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
Run Code Online (Sandbox Code Playgroud)

该文件/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%
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我们可以看到所谓的大小是 33 字节,但分配的大小是 8 KB(文件系统块大小是 4K)。

3. 诸如此类的程序如何ls区分“声称的”大小和分配的大小?

我想知道在分配大小时是否存储在 inode 中的“所谓”数字是通过遍历直接和间接块来计算的 - 尽管这不正确,因为通过遍历计算需要时间和工具,例如ls快速返回,即使对于非常大的文件.

4. 我可以使用哪些工具来查询 inode 信息?

我知道stat,但它似乎没有打印出 inode 中所有字段的值...

5. 有没有可以遍历直接和间接块的工具?

查看磁盘上的每个地址以及内容以进一步了解数据的存储方式会很有趣

如果我在上面的其他命令之后运行以下命令,文件将/tmp/sparse被截断:

%>dd of=/tmp/sparse bs=1 count=0 seek=5
%>hexdump sparse
0000000 0000 4942 004c
0000005
Run Code Online (Sandbox Code Playgroud)

6.为什么dd截断我的文件并且可以dd或其他工具写入文件中间?

最后,稀疏文件似乎是预分配空间的好主意,但似乎没有文件系统或操作系统级别保证 a 命令不会截断或任意增大文件。

7. 是否有防止稀疏文件收缩/增长的机制?如果不是,为什么稀疏文件有用?


虽然上面的每个问题都可能是一个单独的 SO 问题,但我无法剖析它们,因为它们都与潜在的理解有关。

meu*_*euh 8

一些快速答案:首先,您没有创建稀疏文件。试试这些额外的命令

dd if=/tmp/BIL of=/tmp/sparse seek=1000
ls -ls /tmp/sparse
Run Code Online (Sandbox Code Playgroud)

您将看到大小为 512003 字节,但只占用 8 个块。空字节必须占据整个块,并且位于块边界上,以便它们在文件系统中可能是稀疏的。

  1. 为什么第二次出现的“BIL”出现乱序?

    因为你在一个小端系统上,你正在用shorts写输出。使用字节,就像 cat 一样。

  2. cat 和其他工具如何知道以正确的顺序打印?

    他们处理字节。

  3. ls 之类的程序如何区分“声称的”大小和分配的大小?

    ls依此类推,使用stat(2)返回 2 个值的系统调用:

    st_size;             /* total size, in bytes */ 
    blkcnt_t  st_blocks; /* number of 512B blocks allocated */
    
    Run Code Online (Sandbox Code Playgroud)
  4. 我可以使用哪些工具来查询 inode 信息?

    状态很好。

  5. 有没有可以遍历直接和间接块的工具?

    在 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
    
    Run Code Online (Sandbox Code Playgroud)

    您还可以使用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
    
    Run Code Online (Sandbox Code Playgroud)
  6. 为什么 dd 会截断我的文件,并且 dd 或其他工具可以写入文件中间?

    是的,dd可以写到中间。添加conv=notrunc.

  7. 是否有防止稀疏文件收缩/增长的机制?如果不是,为什么稀疏文件有用?

    不,因为它们占用的空间更少。

文件的稀疏性应该对程序完全透明,这有时意味着当程序更新文件时稀疏性可能会丢失。

一些复制实用程序具有保留稀疏性的选项,例如tar --sparse, rsync --sparse

请注意,您可以通过使用cp --sparse=always和相反的方式将文件中适当对齐的零块显式转换为稀疏,将稀疏空间转换为实零,使用cp --sparse=never.