原文:ext2 / ext3 結構分析(第 1 部分)
http://bbs.chinaunix.net/thread-3669811-1-1.html
《ext2 / ext3 結構分析》
字數2-20000...分開發吧。。
---------------------------------------------------------------------------------------------------------------------------------------
實驗機器:虛擬機器 + red hat 9
先看 ext2/ext3 檔案系統 基本結構
由於機器面對的是 位元組流,因此必須對 位元組流 進行結構化定義,檔案系統亦如此。
下面介紹 ext2/ext3 檔案系統的結構。
ext2/ext3 結構圖:
2012-02-11 20:10 上傳
下載附件
(17.42 KB)
Part 1. Super block,1024 B itself / take up 1 block size
The superblock contains all the information about the configuration of the filesystem. The information in
the superblock contains fields such as the total number of inodes and blocks in the filesystem and how
many are free, how many inodes and blocks are in each block group, when the filesystem was mounted
(and if it was cleanly unmounted), when it was modified, what version of the filesystem it is and which
OS created it.
The primary copy of the superblock is stored at an offset of 1024 bytes from the start of the device, and it
is essential to mounting the filesystem. Since it is so important, backup copies of the superblock are
stored in block groups throughout the filesystem.
The first version of ext2 (revision 0) stores a copy at the start of every block group, along with backups
of the group descriptor block(s). Because this can consume a considerable amount of space for large
filesystems, later revisions can optionally reduce the number of backup copies by only putting backups in
specific groups (this is the sparse superblock feature). The groups chosen are 0, 1 and powers of 3, 5 and
7.
Revision 1 and higher of the filesystem also store extra fields, such as a volume name, a unique
identification number, the inode size, and space for optional filesystem features to store configuration
info.
All fields in the superblock (as in all other ext2 structures) are stored on the disc in little endian format,
so a filesystem is portable between machines without having to know what machine it was created on.
struct ext3_super_block {
/*00*/
__u32 s_inodes_count; /* inodes 計數 */
__u32 s_blocks_count; /* blocks 計數 */
__u32 s_r_blocks_count; /* 保留的 blocks 計數 */
__u32 s_free_blocks_count; /* 閒置 blocks 計數 */
/*10*/
__u32 s_free_inodes_count; /* 閒置 inodes 計數 */
__u32 s_first_data_block; /* 第一個資料 block */
__u32 s_log_block_size; /* block 的大小 */
__s32 s_log_frag_size; /* 可以忽略 */
/*20*/
__u32 s_blocks_per_group; /* 每 block group 的 block 數量 */
__u32 s_frags_per_group; /* 可以忽略 */
__u32 s_inodes_per_group; /* 每 block group 的 inode 數量 */
__u32 s_mtime; /* Mount time */
/*30*/
__u32 s_wtime; /* Write time */
__u16 s_mnt_count; /* Mount count */
__s16 s_max_mnt_count; /* Maximal mount count */
__u16 s_magic; /* Magic 簽名 */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
__u16 s_minor_rev_level; /* minor revision level */
/*40*/
__u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* 可以忽略 */
__u32 s_rev_level; /* Revision level */
/*50*/
__u16 s_def_resuid; /* Default uid for reserved blocks */
__u16 s_def_resgid; /* Default gid for reserved blocks */
__u32 s_first_ino; /* First non-reserved inode */
__u16 s_inode_size; /* size of inode structure */
__u16 s_block_group_nr; /* block group # of this superblock */
__u32 s_feature_compat; /* compatible feature set */
/*60*/
__u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
/*68*/
__u8 s_uuid[16]; /* 128-bit uuid for volume */
/*78*/
char s_volume_name[16]; /* volume name */
/*88*/
char s_last_mounted[64]; /* directory where last mounted */
/*C8*/
__u32 s_algorithm_usage_bitmap; /* 可以忽略 */
__u8 s_prealloc_blocks; /* 可以忽略 */
__u8 s_prealloc_dir_blocks; /* 可以忽略 */
__u16 s_padding1; /* 可以忽略 */
/*D0*/
__u8 s_journal_uuid[16]; /* uuid of journal superblock */
/*E0*/
__u32 s_journal_inum; /* 記錄檔的 inode 號數 */
__u32 s_journal_dev; /* 記錄檔的裝置號 */
__u32 s_last_orphan; /* start of list of inodes to delete */
/*EC*/
__u32 s_reserved[197]; /* 可以忽略 */
};
0.
無論分區的 block size 是多大,Super block 總是始於 儲存裝置的 位移1024 B 處!
同時, Super block 使用小端儲存!
這2點保證了可移植性!
1.
block 的大小 = 1 << (s_log_block_size+10),單位Byte
由 3. 得到,s_log_block_size = 0, 1 << 10 = 2^10 = 1024
2.
注意 s_magic,這個位在 ext2 和 ext3 是相同的,
這個位 類似於 TCP/IP 協議中多工 幻數,這說明了ext2 和 ext3 的相容性很好。
3.
dumpe2fs 這個命令本身就是用來查看 super block 的
我們先看一下這個分區的 block 大小:
# dumpe2fs /dev/sda1
.......
Inode count: 24096
Block count: 96358
.......
First block: 1
Block size: 1024
.......
簡單截取 4 個資訊:
Inode count: 24096 代表 inode 總數;
Block count: 96358 代表 block 總數;
Block size: 1024 代表分區的 block 大小;
First block: 1 代表 /dev/sda1 這個裝置是從第一個 block 開始寫資料的,
4.
查看 硬碟內容,可以使用 dd 命令,
這裡說明 /dev/sda1 的第 0 個 block 沒有使用:
dd if=/dev/sda1 bs=1024 count=1 skip=0 | xxd | less 驗證,將會看到全為 0
skip=0 強調是第 0 個,不跳
由於 1 個 Super Block 是 1024B,我們執行下面的命令,看看這 1024B 的內容:
# dd if=/dev/sda1 bs=1024 count=1 skip=1 | xxd | less
0000000: 205e 0000 6678 0100 d112 0000 aa47 0100 ^..fx.......G..
0000010: f65d 0000 0100 0000 0000 0000 0000 0000 .]..............
0000020: 0020 0000 0020 0000 d807 0000 6685 344f . ... ......f.4O
0000030: 6685 344f 2800 ffff 53ef 0100 0100 0000 f.4O(...S.......
0000040: f92a 254f 0000 0000 0000 0000 0100 0000 .*%O............
0000050: 0000 0000 0b00 0000 8000 0000 0400 0000 ................
0000060: 0600 0000 0100 0000 981f fa3c b538 4a2b ...........<.8J+
0000070: ba5e 9c83 ceeb 34fe 2f62 6f6f 7400 0000 .^....4./boot...
0000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
all 0s ...
00000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000e0: 0800 0000 0000 0000 0000 0000 125f b5b3 ............._..
00000f0: 29d5 46c5 99a4 7da6 c8af 233a 0200 0000 ).F...}...#:....
0000100: 0000 0000 0000 0000 f92a 254f 0000 0000 .........*%O....
0000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
all 0s ...
00003f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
可以看出,根據 ext3_super_block 結構體,以及英文介紹得知 superblock 格式是 小端 的,
第一個便是 u32,205e 0000,即 5e20,十進位 24096,inode 總數
第二個也是 u32,6678 0100,即 17866,十進位 96358,block 總數
這 2 個數字與 dumpe2fs /dev/sda1 相符
5.
拷貝備份
英文介紹中說,Super Block 的備份在 ext2 中,是在所有的 group block 中的 Super block 中備份,而後的版本只在
0,1,3,5,7, 以及3 5 7的指數的 group block 號中的 Super Block 做拷貝,如 9,25,49,...
下面會說明,這個 block group 的個數受到限制。
可以實驗證實:
# dumpe2fs /dev/sda1 (已省略大量資訊)
Group 0: (Blocks 1-8192)
Group 1: (Blocks 8193-16384)
Group 2: (Blocks 16385-24576)
Group 3: (Blocks 24577-3276
Group 4: (Blocks 32769-40960)
Group 5: (Blocks 40961-49152)
Group 6: (Blocks 49153-57344)
Group 7: (Blocks 57345-65536)
Group 8: (Blocks 65537-7372
Group 9: (Blocks 73729-81920)
Group 10: (Blocks 81921-90112)
Group 11: (Blocks 90113-96357)
然後依次執行
# dd if=/dev/sda1 bs=1024 count=1 skip=1 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=8193 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=16385 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=24577 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=32769 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=40961 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=49153 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=57345 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=65537 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=73729 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=81921 | xxd | less
# dd if=/dev/sda1 bs=1024 count=1 skip=90113 | xxd | less
可以發現 Group 0, 1, 3, 5, 7, 9 資料全是一樣的,
一個 super block 雖然存在於所有的 block group X 中,但是只有 block group 0 有效,
部分 super block 是備份,部分 super block 沒有使用。
6.
計算 block group 的數量
我們發現,group 從 0 到 11,一共 12 塊兒,那這個數值是怎麼得來的?
我們應該用另外一種想法,去思考如果是你,你如何儲存 group block 的塊兒個數。
直接儲存 數值12 嗎?這樣就缺乏靈活性了,因為 12 這個數值是由其他值得到的,
檔案系統儲存的就是中繼資料,而 12 不再是中繼資料了。
顯然,用 使用的 block 數 / 每塊兒佔用的 block 數,就能得到一共有多少 group block 了。
2nd 資料域,總數是:s_blocks_count
9th 資料域,每個 group 所佔 blocks:s_blocks_per_group
6th 資料域,第一個資料區塊兒:s_first_data_block
根據前面的16進位 的 super block 得到:(注意小端存放)
s_blocks_count = 6678 0100 = 16678H = 91768
s_blocks_per_group = 0020 0000 = 2000H = 8192
s_first_data_block = 0100 0000 = 1
所以得到 向下取整(91768-1-1)/ 8192 是 11,因此必須要有 11 塊兒,
至於剩下的 block 就再分給 一個 block group 了。所以 前 11塊兒 block group 都有 s_blocks_per_group 個 block。
所以得到公示:
block group 的塊兒數 = (s_blocks_count - s_first_data_block-1)/ s_blocks_per_group 取整+1
Part 2. Block Group Descriptor Table,n*32 B itself / take up 1 block size
The block group descriptor table is an array of block group descriptor, used to define parameters of all
the block groups. It provides the location of the inode bitmap and inode table, block bitmap, number of
free blocks and inodes, and some other useful information.
The block group descriptor table is located on the first block following the superblock. This would be the
third block on a 1KiB block file system, or the second block for 2KiB and larger block file systems.
Shadow copies of the block group descriptor table are also stored with every copy of the superblock.
struct ext3_group_desc {
__u32 bg_block_bitmap; /* block 指標指向 block bitmap */
__u32 bg_inode_bitmap; /* block 指標指向 inode bitmap */
__u32 bg_inode_table; /* block 指標指向 inodes table */
__u16 bg_free_blocks_count; /* 閒置 blocks 計數 */
__u16 bg_free_inodes_count; /* 閒置 inodes 計數 */
/*10*/
__u16 bg_used_dirs_count; /* 目錄計數 */
__u16 bg_pad; /* 可以忽略 */
__u32 bg_reserved[3]; /* 可以忽略 */
};
0.
tabel 表的組成
0 號 block group desc,能找到 block group 0 的剩下的資訊;
1 號 block group desc,能找到 block group 1 的剩下的資訊;
.......
11號 block group desc,能找到 block group 11 的剩下的資訊,
把 block group 0-11 中的 Block gourp descriptor 合在一起就組成了 desc Table,
故在 block group 0 的這個 table 中,匯聚了後面所有的 block group 1-X 的 Block gourp descriptor。
1.
拷貝備份
與 Super block 的備份原則一樣,哪個 block group 中備份了 super block,那個 block group 也備份這個 table 表。
驗證:
# dumpe2fs /dev/sda1 (已省略大量資訊)
Group 0: (Blocks 1-8192)
Group 1: (Blocks 8193-16384)
Group 2: (Blocks 16385-24576)
Group 3: (Blocks 24577-3276
Group 4: (Blocks 32769-40960)
Group 5: (Blocks 40961-49152)
Group 6: (Blocks 49153-57344)
Group 7: (Blocks 57345-65536)
Group 8: (Blocks 65537-7372
Group 9: (Blocks 73729-81920)
Group 10: (Blocks 81921-90112)
Group 11: (Blocks 90113-96357)
# dd if=/dev/sda1 count=1 bs=1024 skip=2 | xxd | less
# dd if=/dev/sda1 count=1 bs=1024 skip=8194 | xxd | less
# dd if=/dev/sda1 count=1 bs=1024 skip=16386 | xxd | less
.......
即每個 skip 多加 1 即可,第一個 block 是 Super Block 用的,第二個就是 desc table
通過 Super block 和 Group des table 的備份原則,結合我的分區的情況,畫圖如下:
2012-02-11 20:11 上傳
下載附件
(37.61 KB)
如此一來,即使 block group 0 的 Super Block 或 Group Desc Table 壞了,仍擁有備份。
2.
block group 個數受限
整個 desc table 總大小不能超過 1個 block 的大小。
本例中 block 塊兒大小為 1024B,每個 desc 是32B,所以最多能容納 1024/32 = 32個
對於 4K 的 block,則最多容納 1024B*4 / 32B = 128個
3.
內部的 3 個重要指標
我們拿出 block group 0 的 table:
# dd if=/dev/sda1 bs=1024 count=1 skip=2 | xxd | less
0000000: 0300 0000 0400 0000 0500 0000 0000 bd07 ................
0000010: 0200 0000 0000 0000 0000 0000 0000 0000 ................
0000020: 0320 0000 0420 0000 0520 0000 e919 d807 . ... ... ......
0000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000040: 0140 0000 0240 0000 0340 0000 491e c907 .@...@...@..I...
0000050: 0100 0000 0000 0000 0000 0000 0000 0000 ................
0000060: 0360 0000 0460 0000 0560 0000 011f d807 .`...`...`......
0000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000080: 0180 0000 0280 0000 0380 0000 031f d807 ................
0000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000a0: 03a0 0000 04a0 0000 05a0 0000 011f d807 ................
00000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000c0: 01c0 0000 02c0 0000 03c0 0000 031f d807 ................
00000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000e0: 03e0 0000 04e0 0000 05e0 0000 011f d807 ................
00000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000100: 0100 0100 0200 0100 0300 0100 031f d807 ................
0000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000120: 0320 0100 0420 0100 0520 0100 011f d807 . ... ... ......
0000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000140: 0140 0100 0240 0100 0340 0100 031f d807 .@...@...@......
0000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000160: 0160 0100 0260 0100 0360 0100 6817 d807 .`...`...`..h...
0000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
all 0s
00003f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
由於 2. 得知當 block size 為 1024B 時,最多包含 32 個 32B 的描述表,
現在只有 12 個 block group,所以只佔用了 1024B 的 37.5% (11/32)
我們就拿出第一個進行分析:
0000000: 0300 0000 0400 0000 0500 0000 0000 bd07 ................
0000010: 0200 0000 0000 0000 0000 0000 0000 0000 ................
對用 結構體 ext3_group_desc 的成員,
__u32 bg_block_bitmap = 0300 0000 = 3 /* block 指標指向 block bitmap */
__u32 bg_inode_bitmap = 0400 0000 = 4 /* block 指標指向 inode bitmap */
__u32 bg_inode_table =0500 0000 = 5 /* block 指標指向 inodes table */
__u16 bg_free_blocks_count = 0 /* 閒置 blocks 計數 */
__u16 bg_free_inodes_count = bd07 = 48391 /* 閒置 inodes 計數 */
__u16 bg_used_dirs_count = 2 /* 目錄計數 */
__u16 bg_pad; /* 可以忽略 */
__u32 bg_reserved[3]; /* 可以忽略 */
內部的 3 個指標分別是前 3 個成員,他們儲存的數值不是地址,而是 block 號
下面我們分別進入這些 block 並分析。
Part 3. Block Bitmap,take up 1 block size
The “Block Bitmap” is normally located at the first block, or second block if a superblock backup is
present, of the block group. Its official location can be determined by reading the “bg_block_bitmap” in
its associated group descriptor.
Each bit represent the current state of a block within that block group, where 1 means “used” and 0
“free/available”. The first block of this block group is represented by bit 0 of byte 0, the second by bit 1
of byte 0. The 8th block is represented by bit 7 (most significant bit) of byte 0 while the 9th block is
represented by bit 0 (least significant bit) of byte 1.
文檔已經說得很清楚了,在某個的 block group 中:
1 表示 佔用,0 表示 可用
第1個 block 用 byte 0 的 bit 0
第2個 block 用 byte 0 的 bit 1
第8個 block 用 byte 0 的 bit 7
第9個 block 用 byte 1 的 bit 0
這個地區就是一個 block 的 bit 大地圖,用 0 1 來代表是否佔用
有了它才能知道哪個 block 是可寫資料的
0.
block 數量受限
顯然,1Byte = 8bits,而 Block Bitmap 佔用 1 個 block_size,所以整個 Block bitmap
能存放的 Block 開關狀態位有 block_size * 8 個,
因此,
每個 block group 中,能分配的 block 的上限 = block_size * 8
每個 block group 中,最大空間 = block_size * 8 * block_size
1.
偷窺看看
從 Desc table 中看到,block group 0 的 Block bitmap 在 號碼為 3 的 block,進去看看:
# dd if=/dev/sda1 count=1 bs=1024 skip=3 | xxd | less
0000000: ffff ffff ffff ffff ffff ffff ffff ffff ................
all ffffs
00003f0: ffff ffff ffff ffff ffff ffff ffff ffff ................
意思是說,/dev/sda1 中的 block group 0 已經全部用完了(沒有分配的 inode 就浪費了)
# dumpe2fs /dev/sda1
Group 0: (Blocks 1-8192)
Primary superblock at 1, Group descriptors at 2-2
Block bitmap at 3 (+2), Inode bitmap at 4 (+3)
Inode table at 5-255 (+4)
0 free blocks, 1981 free inodes, 2 directories
Free blocks:
Free inodes: 28-2008
觀察到,
Group 0: (Blocks 1-8192) 滿足 1. 的計算方法,1K*8 = 8192
Free blocks: 已經沒有了
Free inodes: 28-2008 倒還有一堆沒用
Part 4. Inode Bitmap,take up 1 block size
The “Inode Bitmap” works in a similar way as the “Block Bitmap”, difference being in each bit
representing an inode in the “Inode Table” rather than a block.
There is one inode bitmap per group and its location may be determined by reading the
“bg_inode_bitmap” in its associated group descriptor.
When the inode table is created, all the reserved inodes are marked as used. In revision 0 this is the first
11 inodes.
作用和 Block Bitmap 一樣,都是一個超級大的 bit 地圖,
只不過 inode bitmap 用 0 1 標記的是一個 inode,即下面的結構。
保留的 inode 會被標記成 1
因為並非所有的 block group 都會預設成佔用全部的 inode
0.
inode 數量受限
道理同 block bitmap
每個 block group 中,能分配的 inode 數量上限 = block_size * 8
限制 inode Table 的大小,下面可知,每個 inode 128 B,
最大 inode Table 支援 128B * block_size * 8
1.
偷窺看看
從 Desc table 中看到,block group 0 的 inode bitmap 在 號碼為 4 的 block:
# dd if=/dev/sda1 count=1 bs=1024 skip=4 | xxd | less
0000000: ffff ff07 0000 0000 0000 0000 0000 0000 ................
all 0s
00000f0: 0000 0000 0000 0000 0000 00ff ffff ffff ................
all ffffs
00003f0: ffff ffff ffff ffff ffff ffff ffff ffff ................
# dumpe2fs /dev/sda1
Group 0: (Blocks 1-8192)
Primary superblock at 1, Group descriptors at 2-2
Block bitmap at 3 (+2), Inode bitmap at 4 (+3)
Inode table at 5-255 (+4)
0 free blocks, 1981 free inodes, 2 directories
Free blocks:
Free inodes: 28-2008
既然沒有 free block了,那就意味著這個 block group 就已經滿了。
我們能看 Free inodes: 28-2008,
從上面的 16進位 代碼中讀出:
FFFF FF07 就是
11111111 11111111 11111111 00000111
之所以這樣,是因為這個和小端格式有關
這個 bitmap 儲存的就是 inode,即下一部分資料。