深入理解Linux文件系统之ext2路径名查找
扫描二维码
随时随地手机看文章
1.准备文件系统镜像
所用工具:dd、mkfs.ext2、hexdump、dumpe2fs、mount等工具1)制作100k大小镜像文件$ dd if=/dev/zero of=ext2.img bs=1k count=100
记录了100 0 的读入
记录了100 0 的写出
102400 bytes (102 kB, 100 KiB) copied, 0.00125457 s, 81.6 MB/s
2)格式化为ext2文件系统格式$ mkfs.ext2 ext2.img
mke2fs 1.44.1 (24-Mar-2018)
丢弃设备块: 完成
创建含有 100 个块(每块 1k)和 16 个inode的文件系统
正在分配组表: 完成
正在写入inode表: 完成
写入超级块和文件系统账户统计信息: 已完成
3)查看文件系统信息$ dumpe2fs ext2.img
dumpe2fs 1.44.1 (24-Mar-2018)
Filesystem volume name:
Last mounted on: <not available>
Filesystem UUID: 3680e1d5-7f58-4324-9cbd-c7d382f0c3df
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: ext_attr resize_inode dir_index filetype sparse_super large_file
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 16
Block count: 100
Reserved block count: 5
Free blocks: 79
Free inodes: 5
First block: 1
Block size: 1024
Fragment size: 1024
Blocks per group: 8192
Fragments per group: 8192
Inodes per group: 16
Inode blocks per group: 2
Filesystem created: Wed May 26 15:23:33 2021
Last mount time: n/a
Last write time: Wed May 26 15:23:33 2021
Mount count: 0
Maximum mount count: -1
Last checked: Wed May 26 15:23:33 2021
Check interval: 0 ()
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: 5b0daa29-c2a0-4ab1-b09e-50992d3b070d
组 0:(块 1-99)
主 超级块位于 1,组描述符位于 2-2
块位图位于 3 ( 2)
Inode 位图位于 4 ( 3)
Inode表位于 5-6 ( 4)
79 个可用 块,5 个可用inode,2 个目录
可用块数: 21-99
可用inode数: 12-16
这实际是是读取文件系统的超级块和块组描述符信息。我们可以看的创建的文件系统的总体信息:Filesystem magic number:0xEF53 表示为ext2文件系统Inode count: 16 表示文件系统inode个数为16Block count: 100 表示文件系统块个数为100 Free blocks: 79 表示文件系统空闲块个数为79Free inodes: 5 表示文件系统空闲inode个数为5 First block: 1 第一个数据块编号为1(编号0保留为引导块) Block size: 1024 文件系统块大小为1kBlocks per group: 8192 每个块组8192个块Inodes per group: 16 每个块组个inode Inode blocks per group: 2 每个块组2个inode块 First inode: 11 分配的第一个inode号为11(除根inode外,根inode号为2)Inode size: 128 inode大小为128字节块组的信息(这里只有一个块组) 1 - 99号 超级块块编号为 1 块组描述符块编号为 2
块位图块编号为 3 inode位图块编号为 4inode表位于5和6块
79 个可用 块,5 个可用inode,2 个目录 (一个为根目录一个为lost found,存放坏块) 可用块数:21-99 可用inode数:12-164)挂载文件系统并创建文件
创建一个挂载点目录:
$ mkdir root_dir
挂载:
$ sudo mount -t ext2 ext2.img root_dir
查看文件:
$ ls -la
总用量 17
drwxr-xr-x 3 root root 1024 5月 26 15:23 .
drwxrwxr-x 3 hanch hanch 4096 5月 26 15:28 ..
drwx------ 2 root root 12288 5月 26 15:23 lost found
可以发现有三个目录: .
..
lost found
实际上是根目录的数据块的内容(包含各个目录项)。下面我们来创建一个目录,目录下创建文件:$ sudo mkdir dir
$ cd dir/
$ su
# echo hello > test.txt
现在目录树是这样的:$ tree
.
├── dir
│ └── test.txt
└── lost found [error opening dir]
2 directories, 1 file
后面我们会通过解析文件系统镜像来观察如何查找 /dir/test.txt 文件的现在关注一下相关的索引节点:$ cd dir
$ ls -lai
总用量 3
12 drwxr-xr-x 2 root root 1024 5月 26 15:57 .
2 drwxr-xr-x 4 root root 1024 5月 26 15:56 ..
13 -rw-r--r-- 1 root root 6 5月 26 15:57 test.txt
可以发现 /dir目录下:当前工作目录下索引节点为12(dir目录的),上一级目录的索引节点为2(根目录),test.txt文件的所有节点为13。记住这几个索引节点后面我们会通过解析文件系统镜像来获得。2.解析文件系统镜像
1)dump文件系统镜像$ hexdump -C ext2.img
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000400 10 00 00 00 64 00 00 00 05 00 00 00 4f 00 00 00 |....d.......O...|
00000410 05 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................|
00000420 00 20 00 00 00 20 00 00 10 00 00 00 ae f8 ad 60 |. ... .........`|
00000430 ae f8 ad 60 01 00 ff ff 53 ef 00 00 01 00 00 00 |...`....S.......|
00000440 75 f7 ad 60 00 00 00 00 00 00 00 00 01 00 00 00 |u..`............|
...
*
00018c00 0c 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................|
00018c10 0c 00 02 02 2e 2e 00 00 0d 00 00 00 e8 03 08 01 |................|
00018c20 74 65 73 74 2e 74 78 74 00 00 00 00 00 00 00 00 |test.txt........|
00018c30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00019000
根据之前dumpe2fs的信息我们知道:镜像文件中(均为16进制显示)00000000 开始的1k大小 保留的引导块 块1 00000400 开始的1k大小 保存磁盘的超级块 (dumpe2fs的部分信息从这里获得) 块2 00000800 开始的1k大小 保存块组描述符 (dumpe2fs的部分信息从这里获得)块3 00000c00 开始的1k大小 保存块位图 块4 00001000 开始的1k大小 保存 Inode 位图 块5 块6 00001400 开始的2k大小 保存 Inode表 剩下的为数据块磁盘中的文件系统对象结构在内核如下文件定义:fs/ext2/ext2.h
磁盘超级块:
struct ext2_super_block {
__le32 s_inodes_count; /* Inodes count */
__le32 s_blocks_count; /* Blocks count */
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count; /* Free blocks count */
__le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size; /* Fragment size */
__le32 s_blocks_per_group; /* # Blocks per group */
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group; /* # Inodes per group */
...
}
磁盘块组描述符:
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];
};
磁盘inode:
struct ext2_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks; /* Blocks count */
...
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
...
};
磁盘目录项:
struct ext2_dir_entry_2 {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[]; /* File name, up to EXT2_NAME_LEN */
};
大家可以对照磁盘镜像文件和磁盘数据结构定义来解析出文件系统的超级块和块组描述符信息(可以发现和dumpe2fs工具显示的是一致的,例如镜像文件00000400 处四字节为10 00 00 00 是小端存储,所以为0x00000010=16);3.路径名查找
下面开始我们的重头戏:查找文件系统中的 /dir/test.txt 文件。我们知道,使用文件系统给我最直观也是最大的好处是:用户可以通过一个路径名来访问文件,那么一个文件系统究竟如何来找到我们所需要的文件呢?下面我们详细来看ext2文件系统如何查找指定的文件的?(实际的内核中路径名查找比较复杂,考虑很多情况,如dentry cache查找、解析软链接文件、上级目录、挂载点等,当然如果目录分量是挂载点就会步进到相应文件系统的根目录,后面文件系统挂载专题会讲解,这里以简单的路径解析来让大家有个深刻的认识)。1)查找根目录
万事开头难,对于访问一个目录上挂载的文件系统,内核路径名查找会判断并找到挂载的文件系统的根目录,这个过程在文件系统挂载的时候,会从磁盘上读取并在内存构建超级块实例,然后进行的最重要的一步是读取文件系统的根inode:fs/ext2/super.c
ext2_fill_super
->root = ext2_iget(sb, EXT2_ROOT_INO) //EXT2_ROOT_INO为2,系统定义好的
->raw_inode = ext2_get_inode(inode->i_sb, ino,