本文节选自《实验指导手册》第二版第14.1章,下载《实验指导手册》:登陆“奔跑吧linux社区”微信公众号,输入“奔跑吧2”获取下载地址。
   
   有趣的文件系统实验   
   
入门篇第二版第14章是新增的一章,讲文件系统相关的入门知识。实验14-1非常有趣,群里有小伙伴问笨叔,这个实验怎么做啊?这个实验是这样的:
使用dd命令创建磁盘文件file.img并格式化为ext2文件系统,然后通过mout命令挂载到Linux主机文件系统。
(1)查看文件系统的信息,比如数据块的数量、数据块的大小、inode 个数、空闲数据块的数量等信息,并画出文件系统的布局图。
(2)在文件系统中创建文件test.txt,写入一些数据。查看test.txt文件的inode编号,统计test.txt文件占用了哪几个数据块。
(3)使用dd或hexdump命令导出file.img磁盘文件的二进制数据并且分析超级块。读者可以对照Linux内核中的ext2_super_block数据结构来分析磁盘文件的二进制数据。
   实验详解   
我们在QEMU+runninglinuxkernel平台上做实验。我们首先保证RLK系统能支持ext2文件系统。
修改arch/arm64/configs/debian_defconfig文件支持ext2文件系统。
   CONFIG_BLK_DEV_LOOP=y
CONFIG_EXT2_FS=y
   
然后重新编译内核,并运行。
   $ ./run_rlk_arm64.sh build_kernel
$ ./run_rlk_arm64.sh run
   
使用dd命令来创建一个ext2.img文件。
   benshushu:benshushu# dd if=/dev/zero of=ext2.img bs=4K count=64
64+0 records in
64+0 records out
262144 bytes (262 kB, 256 KiB) copied, 0.0176809 s, 14.8 MB/s
   
格式化。
   benshushu:benshushu# mkfs.ext2 ext2.img
mke2fs 1.45.0 (6-Mar-2019)
Discarding device blocks: done                           
Creating filesystem with 256 1k blocks and 32 inodes

Allocating group tables: done                           
Writing inode tables: done                           
Writing superblocks and filesystem accounting information: done
   
我们先挂载该文件系统。
   benshushu:#mkdir /home/benshushu/ext2
benshushu:ext2# mount -t ext2 -o loop ext2.img /home/benshushu/ext2
   
我们在ext2文件系统中新建一个test.txt文件,然后在该文件里输入一个字符串“I am benshushu”。
   
上面准备工作完成之后,我们来开始分析这个文件系统了。首先使用dumpe2fs命令来查看这个ext2.img文件系统的布局情况。
   benshushu:benshushu# dumpe2fs ext2.img
dumpe2fs 1.45.0 (6-Mar-2019)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          d56e86f3-afd6-4edd-b1a3-3d7c366655bf
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      ext_attr resize_inode dir_index filetype sparse_super large_file
Filesystem flags:         unsigned_directory_hash
Default mount options:    user_xattr acl
Filesystem state:         not clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              32
Block count:              256
Reserved block count:     12
Free blocks:              233
Free inodes:              21
First block:              1
Block size:               1024
Fragment size:            1024
Blocks per group:         8192
Fragments per group:      8192
Inodes per group:         32
Inode blocks per group:   4
Filesystem created:       Fri Mar 12 08:40:28 2021
Last mount time:          n/a
Last write time:          Fri Mar 12 09:09:16 2021
Mount count:              2
Maximum mount count:      -1
Last checked:             Fri Mar 12 08:40:28 2021
Check interval:           0 (<none>)
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:              128
Default directory hash:   half_md4
Directory Hash Seed:      b3cabb7f-5a1e-4a8e-97fb-83b381ccab58


Group 0: (Blocks 1-255)
  Primary superblock at 1, Group descriptors at 2-2
  Block bitmap at 3 (+2)
  Inode bitmap at 4 (+3)
  Inode table at 5-8 (+4)
  232 free blocks, 20 free inodes, 2 directories
  Free blocks: 23-30, 32-255
  Free inodes: 12-13, 15-32
   
从上述日志可以知道这个迷你型的空闲分区的如下信息。
   

       
  • 一共有256个数据块。

       
  • 每个数据块的大小为1KB。

       
  • 最多支持32个inode。

       
  • 第1个数据块开始存储数据。

       
  • 空闲的inode为21个。

       
  • 空闲的数据块为233个。

       
  • 预留的数据块为12个。

       
  • 每一组(group)可以有8192个空闲块。
    ext2文件系统还把分区分成了组(Group),这个ext.img中只有一个组,这个组包含了非常重要的文件系统布局信息,如图14.4所示。

       
  • 超级块(superblock)在第1个块。

       
  • 组描述符(Group descriptors)在第2个块。

       
  • 块位图(Block bitmap)在第3个块。

       
  • inode位图(Inode bitmap)在第4个块。

       
  • inode表(Inode table)在第5~8个块,一共占用4个块。

       
  • 第8~10个块为预留的块。

       
  • 第23~255个块为空闲的数据块,可组成数据区。(中间第31、32个数据块是被使用了)

       
  • 第12~31个inode节点为空闲的。(第14个inode节点被使用了)



       

  •    
   1. 分析超级块的信息   
第0个数据块通常是引导块,暂时没有用来存储数据,里面全是0的数据,我们可以使用dd命令来查看。
   dd if=ext2.img bs=1 count=1024 skip=0 | od -t x1 -Ax
   
这里首先使用dd命令来读取ext2.img的内容,其中
   

       
  • bs:设置读入/输出的块大小为bytes个字节

       
  • count:读取多少个块数据

       
  • skip:从输入文件开头跳过多少个块后再开始读取数据。

       
   
另外od命令用来显示数据的内容,其格式为:
od [-A 地址进制] [-t 显示格式] 文件名
   

       
  • A  :按指定的进制来显示地址:

       
  • d 十进制

       
  • 八进制(系统默认值)

       
  • x 十六进制

       
  • n 不打印位移值

       
  • t 指定数据的显示格式,主要的参数有:

       
  • c ASCII字符或反斜杠序列

       
  • d 有符号十进制数

       
  • f 浮点数

       
  • 八进制(系统默认值为02)

       
  • u 无符号十进制数

       
  • x 十六进制数

       
   
   下来分析超级块的内容。

     dd if=ext2.img bs=1 count=1024 skip=1024 | od -t x1 -Ax
   
   
对照struct ext2_super_block数据结构,我们可以知道:
   

       
  • s_inodes_count的值为0x20,即32,表示inode节点的个数

       
  • s_blocks_count的值为0x100,即256,一共有多少个块

       
  • s_r_blocks_count的值为0xc,即12,保留的块有多少个。

       
  • s_free_blocks_count的值为0xe9,即空闲的数据块,233个。

       
  • s_free_inodes_count的值为0x15,即21,表示空闲的inode节点个数。

       
  • s_first_data_block的值为0x1,即有效数据是从第1个数据块开始。

       
  • s_log_block_size的值为0,那么计算方法为:2^0 * 1024 = 1024 字节

       
  • s_log_frag_size的值为0,计算方法和s_log_block_size。

       
  • s_blocks_per_group的值为8192,表示每个组有多少个数据块。

       
  • 剩下的成员,大家可以继续来分析。

       
   
按照上面的方法,大家可以对照来找到struct ext2_super_block数据结构每个成员的值。如果看十六进制比较不方便,可以让od命令显示十进制。
   
   2. 分析组描述符   
组描述符位于在超级块后面的数据块。组描述符的数据结构如下。
   /*
* Structure of a blocks group descriptor
*/

struct ext2_group_desc
{
    __le32  bg_block_bitmap;        /* Blocks bitmap block */
    __le32  bg_inode_bitmap;        /* Inodes bitmap block */
    __le32  bg_inode_table;     /* Inodes table block */
    __le16  bg_free_blocks_count;   /* Free blocks count */
    __le16  bg_free_inodes_count;   /* Free inodes count */
    __le16  bg_used_dirs_count; /* Directories count */
    __le16  bg_pad;
    __le32  bg_reserved[3];
};
   
接下来分析组描述符的内容。
   dd if=ext2.img bs=1 count=1024 skip=2048 | od -t d -Ax
   
   
从dd打印的内容可知:
   

       
  • bg_block_bitmap的值为3,表示块位图(Block bitmap)在第3个块。

       
  • bg_inode_bitmap的值为4,表示inode位图(Inode bitmap)在第4个块。

       
  • bg_inode_table的值为5,表示inode表(Inode table)在第5块。

       
  • bg_free_blocks_count成员是16位,它的值为0xe8,即232个空闲数据块。

       
  • bg_free_inodes_count成员也是16位数据,它的值为0x14,即20个空闲的inode节点。

       
  • bg_used_dirs_count表示已经存在的目录,目前为0。

       
   3. 分析inode表   
Inode表是在第5个数据块,一共有4个数据块存储inode表。Ext2文件系统使用struct ext2_inode数据结构来表示一个inode节点,其中struct ext2_inode数据结构的大小为128字节。
   
那为啥要使用4个数据块来存储inode表呢?
从3.1节分析超级块可知,这个ext2文件系统最多支持32个inode节点,那么
                      128 * 32 = 4096
   
正好是4个数据块。
   
接下来我们需要通过stat命令来确定test.txt的inode节点号。
进入ext2目录,使用stat命令来查看。
   
   
从stat命令可以看出test.txt使用的inode节点号为14。
那么,我们需要读取第14个inode节点的struct ext2_inode数据结构的内容。
那么第14个inode节点在inode表的位置,计算公式如下:
                (141) * 128 = 1664

               16641024 = 640 = 0x280
   
所以,第14个inode节点,位于inode表中第二个数据块的0x280地址处。使用dd命令来读取第6个数据块的内容。
   
   
那么地址0x280处开始的数据就是第14号inode节点的内容了。
   
   
Ext2文件系统采用直接和间接索引的方式来索引数据块,详见《奔跑吧linux内核 入门篇》第二版第14.2.2章内容。
   /*
* Structure of an inode on the disk
*/

struct ext2_inode {
      …
    __le32  i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
…   
}
   
i_block数组是位于struct ext2_inode数据结构中第40个字节开始的地方。
从上图可知,0x280 + 40 = 0x2A8,也就是说i_block数组存储在0x2ab地址处,这个值为0x1f,就31,也就是test.txt数据存储在第31个数据块里。
   
我们马上使用dd命令来查看,发现“I am benshushu”字符串果然存储在第31个数据块里。
   
   
总结,我们从这个实验完成了对ext2文件系统的静态分析和动态分析,相信会对大家理解文件系统有帮助。
   4. e2fsprogs工具   
e2fsprogs是一个Ext2(及Ext3/4)文件系统工具(Ext2Filesystems Utilities),它包含了诸如创建、修复、配置、调试ext2文件系统等的标准工具。我们可以使用这个工具来分析某个文件是占用的哪些数据块,不过我们还是建议大家学习前面的分析方法。
    首先在QEMU+runninglinuxkernel里安装e2fsprogs工具。
   benshushu:benshushu# apt update
benshushu:benshushu# apt install e2fsprogs
   
e2fsprogs工具里内置了很多有用的工具,我们接下来使用叫做debugfs的小工具。
直接输入debugfs打开这个小工具。
   benshushu:benshushu# debugfs
debugfs 1.46.2 (28-Feb-2021)
   
然后使用open子命令来打开文件系统。
   debugfs:  open ext2.img
   
使用block子命令来查看test.txt文件占用了哪些数据块。
   debugfs:  blocks test.txt
31
   
Debugfs命令很快找出test.txt文件占用的是第31个数据块,和我们前面的分析结论一样。
另外,我们还可以使用imap子命令来查看test.txt文件的inode节点情况。
   debugfs:  imap test.txt
Inode 14 is part of block group 0
    located at block 6, offset 0x0280
   
从上述信息可知,test.txt文件使用的是第14个inode节点,位于Group 0中的第6个数据块,偏移为0x280,和我们前面的分析结论一样。
   
   下载实验指导手册   
入门篇配套的实验指导手册pdf版本是基于开源精髓,大家可以免费下载,免费传阅,自由打印。如果小伙伴需要纸质版本,请自行打印。
   
   
   
   
下载《实验指导手册》:登陆“奔跑吧linux社区”微信公众号,输入“奔跑吧2”获取下载地址。
   
   

本文源自微信公众号:奔跑吧Linux社区,不代表用户或本站观点,如有侵权,请联系nick.zong@aspencore.com 删除!