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

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

在工作中,我们使用稀疏文件作为来宾磁盘映像的 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 个块。空字节必须占据整个块,并且位于块边界上,以便它们在文件系统中可能是稀疏的。

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

    因为您使用的是小端系统,并且您正在以简短的形式编写输出。像 cat 一样使用字节。

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

    他们以字节为单位工作。

  3. 像 ls 这样的程序如何辨别“所谓的”大小和分配的大小?

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

    st_size;             /* total size, in bytes */ 
    blkcnt_t  st_blocks; /* number of 512B blocks allocated */
    
  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
    

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

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

  7. 是否有机制可以防止稀疏文件缩小/增大?如果没有,为什么稀疏文件有用?

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

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

一些复制实用程序具有保留稀疏性的选项,例如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(尽管正在开发中)。

相关内容