本文以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: 《none》
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
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 (《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: 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個數為16 Block count: 100表示文件系統塊個數為100 Free blocks: 79 表示文件系統空閑塊個數為79 Free inodes: 5 表示文件系統空閑inode個數為5 First block: 1 第一個數據塊編號為1(編號0保留為引導塊) Block size: 1024 文件系統塊大小為1k Blocks 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位圖塊編號為 4
inode表位于5和6塊
79 個可用 塊,5 個可用inode,2 個目錄 (一個為根目錄一個為lost+found,存放壞塊) 可用塊數:21-99 可用inode數:12-16
4)掛載文件系統并創建文件
創建一個掛載點目錄:
$ 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, &bh); //根據inode號查找磁盤inode
核心算法如下:
-》block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb) //獲得塊組 編號
gdp = ext2_get_group_desc(sb, block_group, NULL); //獲得塊組描述符
offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb); //計算出在 塊組的 inode表中的inode偏移
block = le32_to_cpu(gdp-》bg_inode_table) + (offset 》》 EXT2_BLOCK_SIZE_BITS(sb)); //計算出在文件系統中的塊號
bh = sb_bread(sb, block)) //組合成submit_bh 讀取這個塊到bh
*p = bh; //賦值bh 用于返回
offset &= (EXT2_BLOCK_SIZE(sb) - 1); //計算出塊中偏移
return (struct ext2_inode *) (bh-》b_data + offset); //返回inode中位置
簡述ext2通過inode號找到并讀取磁盤inode核心算法:
1.根據inode號計算出所在的塊組block_group
2.根據inode號計算出塊組中的inode表中的字節偏移offset
3.根據inode號計算出磁盤inode在文件系統中的塊號block
4.根據塊號block 通過sb_bread讀取緩沖區塊到內存
5.根據inode表中的字節偏移offset 計算出 磁盤inode在塊中偏移
6.通過讀取的緩沖區和磁盤inode在塊中偏移 最終返回磁盤inode結構
我們已知:
每個塊組inode個數:EXT2_INODES_PER_GROUP(sb) = 16
磁盤inode大小:EXT2_INODE_SIZE(sb) = 128
塊大小的bit表示:EXT2_BLOCK_SIZE_BITS(sb) = 10
所以計算根inode塊號:
ino=2 跟inode時:
塊組編號: block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb) = (2 - 1) / 16 = 0
inode表中的根inode偏移 : offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb
= ( 1 % 16 ) * 128 = 128 =0x80 (第2個inode 也就是0x1480處)
文件系統中的根inode所在塊號 : block = le32_to_cpu(gdp-》bg_inode_table) + (offset 》》 EXT2_BLOCK_SIZE_BITS(sb))
= 5 + (128 》》 10) = 5
根inode所在塊中偏移:offset &= (EXT2_BLOCK_SIZE(sb) - 1) = 128 = 0x80
inode中位置 = bh-》b_data + offset = 所在塊 + 0x80
所以:根inode所在的鏡像文件中偏移為:5 * 0x400 + 0x80 = 0x1400 + 0x80 = 0x1480
查看0x1480偏移處內容如下(即是根目錄的磁盤inode內容):
*
00001480 ed 41 00 00 00 04 00 00 54 ff ad 60 44 ff ad 60 |.A.。。。。.T.。`D.。`|
00001490 44 ff ad 60 00 00 00 00 00 00 04 00 02 00 00 00 |D.。`。。。。。。。。。。。。|
000014a0 00 00 00 00 01 00 00 00 07 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
000014b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
*
對照ext2文件系統磁盤inode結構,可知i_block為磁盤inode結構的偏移40B處,內容即為0x07(ext2通過i_block來查找文件在磁盤中的位置)。
于是我們知道,根目錄數據塊的塊號 為0x7(鏡像中字節偏移為 0x400 * 7= 1c00),這個數據塊中保存的是根目錄中包含的所有目錄和文件的目錄項(我們知道這里為“?!?、“。?!?、“dir”、“lost+found”四個目錄項)。
根目錄數據塊的內容:
*
00001c00 02 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |。。。。。。。。。。。。。。。。|
00001c10 0c 00 02 02 2e 2e 00 00 0b 00 00 00 14 00 0a 02 |。。。。。。。。。。。。。。。。|
00001c20 6c 6f 73 74 2b 66 6f 75 6e 64 00 00 0c 00 00 00 |lost+found.。。。。。|
00001c30 d4 03 03 02 64 69 72 00 00 00 00 00 00 00 00 00 |。。。.dir.。。。。。。。。|
00001c40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
*
根據目錄項ext2_dir_entry_2 結構我們可以查詢到文件名為dir的目錄項,從而獲取dir目錄的inode號,為0x0c(和我們之前通ls -lai顯示的dir目錄inode號12是一致)。
2)查找dir目錄
和上面查詢根inode一樣的原理,計算過程如下:
dir目錄所在塊組編號: block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb) = (12 - 1) / 16 = 0
dir目錄所在inode表中的inode偏移 : offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb
= ( 11 % 16 ) * 128 = 1408(0x580)
文件系統中的dir目錄的inode所在塊號 : block = le32_to_cpu(gdp-》bg_inode_table) + (offset 》》 EXT2_BLOCK_SIZE_BITS(sb))
= 5 + (1408 》》 10) = 5 +1 =6
dir目錄的inode所在塊號中偏移:offset &= (EXT2_BLOCK_SIZE(sb) - 1) = 1408(0x580)& (0x400 -1) = 0x180
inode中位置 = bh-》b_data + offset = 所在塊 + 0x180
所以:dir目錄inode所在的鏡像文件中字節偏移為:6 * 0x400 + 0x180 = 0x1800 + 0x180 = 0x1980
查看0x1980偏移處內容如下(即是dir目錄的磁盤inode內容):
*
00001980 ed 41 00 00 00 04 00 00 84 ff ad 60 66 ff ad 60 |.A.。。。。。。。。`f.。`|
00001990 66 ff ad 60 00 00 00 00 00 00 02 00 02 00 00 00 |f.。`。。。。。。。。。。。。|
000019a0 00 00 00 00 02 00 00 00 63 00 00 00 00 00 00 00 |。。。。。。。.c.。。。。。。|
000019b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
*
對照ext2文件系統磁盤inode結構,可知i_block為磁盤inode結構的偏移40B處,內容即為0x63。
于是我們知道,dir目錄數據塊的塊號 為0x63(偏移為 0x400 * 0x63= 0x18c00),這個數據塊中保存的是dir目錄中包含的所有目錄和文件的目錄項(我們知道這里為“?!薄ⅰ?。?!?、“test.txt”三個目錄項)。
dir目錄數據塊的內容:
*
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 |。。。。。。。。。。。。。。。。|
*
對照目錄項ext2_dir_entry_2 結構,查找文件名為test.txt的inode號,即為0x0d(和我們之前通ls -lai顯示的dir目錄inode號13是一致)。
于是我們知道,test.txt文件的inode號為0x0d(13)。
2)查找test.txt文件
和上面查詢根inode一樣的原理,計算過程如下:
test.txt文件inode所在塊組 編號: block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb) = (13 - 1) / 16 = 0
test.txt文件inode在 inode表中的inode偏移 : offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb
= ( 12 % 16 ) * 128 = 1536(0x600)
文件系統中的test.txt文件inode所在塊號 : block = le32_to_cpu(gdp-》bg_inode_table) + (offset 》》 EXT2_BLOCK_SIZE_BITS(sb))
= 5 + (1536 》》 10) = 5 +1 =6
test.txt文件inode所在塊號中偏移:offset &= (EXT2_BLOCK_SIZE(sb) - 1) = 1408(0x600)& (0x400 -1) = 0x200
inode中位置 = bh-》b_data + offset = 所在塊 + 0x200
所以:test.txt文件inode所在的鏡像文件中偏移為:= 6 * 0x400 + 0x200 = 0x1800 + 0x200 = 0x1a00
查看 0x1a00偏移處內容如下(即是test.txt文件的磁盤inode內容):
00001a00 a4 81 00 00 06 00 00 00 85 ff ad 60 66 ff ad 60 |。。。。。。。。。。。`f.。`|
00001a10 66 ff ad 60 00 00 00 00 00 00 01 00 02 00 00 00 |f.。`。。。。。。。。。。。。|
00001a20 00 00 00 00 01 00 00 00 15 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
00001a30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
*
對照ext2文件系統磁盤inode結構,可知i_block為磁盤inode結構的偏移40B處,內容即為0x15。
于是我們知道,test.txt文件數據塊的塊號 為0x15(偏移為0x15 * 0x400 = 0x5400)。
查看 0x5400偏移處內容如下(test.txt文件數據塊的內容):
*
00005400 68 65 6c 6c 6f 0a 00 00 00 00 00 00 00 00 00 00 |hello.。。。。。。。。。。|
00005410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |。。。。。。。。。。。。。。。。|
*
最終可以看到文件數據為“hello”。
4)查找過程圖解
以下為 dir/test.txt查找過程:
已知根目錄inode號(ext2為2) -》 查找根目錄磁盤inode(文件系統掛載時查找) -》 查找根目錄的數據塊 -》 查找dir目錄的目錄項找到其inode號 (為12) -》 查找dir目錄的磁盤inode -》 查找dir目錄的數據塊 -》 查找test.txt文件的inode號(為13) -》 查找test.txt文件的磁盤inode -》 查找test.txt文件的數據塊
下面為查找圖解:
4.總結
對于ext2文件系統,路徑名查找中,實際上是解析路徑名的各個分量,查找每個分量的目錄項,然后通過目錄項找到inode號,通過inode號找到對應的磁盤inode,然后通過磁盤inode獲得目錄/文件的數據塊, 最終查找到對應目錄/文件的磁盤inode,而磁盤inode的i_block中保存著文件的邏輯塊號和磁盤的邏輯塊號映射關系,讀寫文件時就可以訪問到整個文件。
編輯:jq
-
數據
+關注
關注
8文章
6715瀏覽量
88316 -
磁盤
+關注
關注
1文章
355瀏覽量
25095 -
文件系統
+關注
關注
0文章
280瀏覽量
19831
原文標題:深入理解Linux文件系統之ext2路徑名查找
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論