本文节选自《实验指导手册》第二版第14.1章,下载《实验指导手册》:登陆“奔跑吧linux社区”微信公众号,输入“奔跑吧2”获取下载地址。

有趣的文件系统实验

20220404_104546_015.jpg
入门篇第二版第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节点被使用了)

20220404_104546_018.jpg

  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 十六进制数

thtyh.png

接下来分析超级块的内容。

dd if=ext2.img bs=1 count=1024 skip=1024 | od -t x1 -Ax
20220404_104546_016.jpg

对照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命令显示十进制。

20220404_104546_017.jpg

  1. 分析组描述符
    组描述符位于在超级块后面的数据块。组描述符的数据结构如下。

/*

  • 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
640 (3).png

从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。

  1. 分析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命令来查看。

640.png

从stat命令可以看出test.txt使用的inode节点号为14。
那么,我们需要读取第14个inode节点的struct ext2_inode数据结构的内容。
那么第14个inode节点在inode表的位置,计算公式如下:

         (14 – 1) * 128 = 1664

           1664 – 1024 = 640 = 0x280

所以,第14个inode节点,位于inode表中第二个数据块的0x280地址处。使用dd命令来读取第6个数据块的内容。

640 (1).png

那么地址0x280处开始的数据就是第14号inode节点的内容了。

20220404_104546_018.jpg

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个数据块里。

640 (2).png

总结,我们从这个实验完成了对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,和我们前面的分析结论一样。

640 (4).png

下载实验指导手册
入门篇配套的实验指导手册pdf版本是基于开源精髓,大家可以免费下载,免费传阅,自由打印。如果小伙伴需要纸质版本,请自行打印。

20220404_104546_019.jpg
20220404_104546_020.jpg
20220404_104546_021.jpg

下载《实验指导手册》:登陆“奔跑吧linux社区”微信公众号,输入“奔跑吧2”获取下载地址。

20220404_104546_022.jpg


奔跑吧Linux社区
4 声望4 粉丝

奔跑吧Linux社区,为广大小伙伴布道Linux开源!


引用和评论

0 条评论