読者です 読者をやめる 読者になる 読者になる

はわわーっ

はわわわわっ

ext4のめも

linux filesystem

ext4のディスクレイアウトを見てみる。

参考


とりあえず、先頭から。

% sudo hexdump -C /dev/dm-0 | head
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  00 e0 e9 00 00 5c a7 03  99 c4 2e 00 9f ae 81 03  |.....\..........|
00000410  4b 7e e6 00 00 00 00 00  02 00 00 00 02 00 00 00  |K~..............|
00000420  00 80 00 00 00 80 00 00  00 20 00 00 26 bd 7a 55  |......... ..&.zU|
00000430  26 bd 7a 55 09 00 ff ff  53 ef 01 00 01 00 00 00  |&.zU....S.......|
00000440  22 c9 73 55 00 00 00 00  00 00 00 00 01 00 00 00  |".sU............|
00000450  00 00 00 00 0b 00 00 00  00 01 00 00 3c 00 00 00  |............<...|
00000460  46 02 00 00 7b 00 00 00  46 40 20 46 a2 41 43 4f  |F...{...F@ F.ACO|
00000470  85 c1 93 22 8d 68 5b 57  00 00 00 00 00 00 00 00  |...".h[W........|

先頭1024Bは0。でoffset 0x400からスーパーブロック。0x438の2バイトが0xef53になってればext4
スーパーブロックはサイズ1ブロックなので1024バイト。

スーパーブロックのダンプ。

% sudo hexdump -C -s 0x400 -n 1024 /dev/dm-0
00000400  00 e0 e9 00 00 5c a7 03  99 c4 2e 00 9f ae 81 03  |.....\..........|
00000410  4b 7e e6 00 00 00 00 00  02 00 00 00 02 00 00 00  |K~..............|
00000420  00 80 00 00 00 80 00 00  00 20 00 00 26 bd 7a 55  |......... ..&.zU|
00000430  26 bd 7a 55 09 00 ff ff  53 ef 01 00 01 00 00 00  |&.zU....S.......|
00000440  22 c9 73 55 00 00 00 00  00 00 00 00 01 00 00 00  |".sU............|
00000450  00 00 00 00 0b 00 00 00  00 01 00 00 3c 00 00 00  |............<...|
00000460  46 02 00 00 7b 00 00 00  46 40 20 46 a2 41 43 4f  |F...{...F@ F.ACO|
00000470  85 c1 93 22 8d 68 5b 57  00 00 00 00 00 00 00 00  |...".h[W........|
00000480  00 00 00 00 00 00 00 00  2f 00 61 72 67 65 74 00  |......../.arget.|
00000490  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 f1 03  |................|
000004d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000004e0  08 00 00 00 00 00 00 00  68 1d 58 00 d0 4c a1 84  |........h.X..L..|
000004f0  88 45 4d 03 b3 61 9a 6b  75 5a 7b 80 01 01 00 00  |.EM..a.kuZ{.....|
00000500  0c 00 00 00 00 00 00 00  22 c9 73 55 0a f3 02 00  |........".sU....|
00000510  04 00 00 00 00 00 00 00  00 00 00 00 ff 7f 00 00  |................|
00000520  00 80 d0 01 ff 7f 00 00  01 00 00 00 ff ff d0 01  |................|
00000530  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000540  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 08  |................|
00000550  00 00 00 00 00 00 00 00  00 00 00 00 1c 00 1c 00  |................|
00000560  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000570  00 00 00 00 04 00 00 00  29 d5 7a 0f 00 00 00 00  |........).z.....|
00000580  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000800

その後に、グループディスクリプタがくる。グループディスクリプタのブロック数は1ブロックより多くなる時もある。ここが何ブロック使っているかは別途計算。

まず、ブロック数を計算する。これはスーパーブロックのs_blocks_count_lo(offset 0x4/size 4)とs_blocks_count_hi(offset 0x150/size 4)を合わせる。
今の場合、s_blocks_count_hiが0でs_blocks_count_loが0x3a75c00なので、ブロック数は0x3a75c00。
これをs_blocks_per_group(offset 0x20/size 4)で割るとブロックグループの数になる。
s_blocks_per_groupが0x8000なのでブロックグループ数は1870。

% echo $(( 0x3a75c00 / 0x8000 ))
1870

で、グループディスクリプタの構造体のサイズを調べる。これはs_feature_incompat(offset 0x60/size 4)のINCOMPAT_64BIT(bit 0x80)を見る。このビットが有効ならグループディスクリプタのサイズは64B、そうでなければ32Bらしい。今の場合は32バイト。

グループディスクリプタが使っているブロック数は((ブロックグループ数 * ディスクリプタのサイズ) / ブロックサイズ) + 1で計算できる。
ブロックサイズはs_log_block_size(offset 0x18/size 4)を元に2^(10+s_log_block_size)になる。
今の場合、ブロックサイズは4096B(0x1000)で、ブロック数は15。

% echo $(( ((1870 * 32) / 0x1000) + 1 ))
15

グループディスクリプタの次にくるのがReserved GDT Blocksで、グループディスクリプタの予約領域。
この予約領域のブロック数はスーパーブロックのs_reserved_gdt_blocks(offset 0xce/size 2)で、
今の場合は0x3f1。

このあとに、データブロックビットマップ、inodeビットマップ、inode tableが来てデータブロックがある。

データブロックビットマップ、inodeビットマップ、inode tableはグループディスクリプタに開始位置が書いてある。
グループ0のグループディスクリプタを見てみる。

% sudo hexdump -C -s 0x1000 -n 32 /dev/dm-0
00001000  01 04 00 00 11 04 00 00  21 04 00 00 d9 5b f1 1f  |........!....[..|
00001010  02 00 04 00 00 00 00 00  00 00 00 00 f1 1f 8e 74  |...............t|
00001020

今の場合はグループディスクリプタの構造体サイズが32Bなので、bg_block_bitmap_lo(offset 0x0/size 4)とbg_inode_bitmap_lo(offset 0x4/size 4)とbg_inode_table_lo(offset 0x8/size 4)を見る。
それぞれ0x401、0x411、0x421が開始位置。

ビットマップはとりあえずおいといて、inode tableを見る。
inode構造体のサイズはスーパーブロックのs_inode_size(offset 0x58/size 2)にあって、今の場合は0x100B。
ひとつのブロックグループにいくつのinodeがあるのかはs_inodes_per_group(offset 0x28/size 4)で、今の場合は0x200。

特別なinodeが0から11まであって、inode 2がroot directoryになっている。
inode 2のアドレスはinodeサイズ * (inode番号 - 1) + inode table開始位置なので0x100 * (2 - 1) + 0x421000 = 421100。

% sudo hexdump -C -s 0x421100 /dev/dm-0 | head
00421100  ed 41 00 00 00 10 00 00  17 e4 8d 55 9f 32 86 55  |.A.........U.2.U|
00421110  9f 32 86 55 00 00 00 00  00 00 17 00 08 00 00 00  |.2.U............|
00421120  00 00 08 00 3f 00 00 00  0a f3 01 00 04 00 00 00  |....?...........|
00421130  00 00 00 00 00 00 00 00  01 00 00 00 21 24 00 00  |............!$..|
00421140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00421180  1c 00 00 00 a4 ed 29 6e  a4 ed 29 6e 30 b5 eb cd  |......)n..)n0...|
00421190  27 c9 73 55 00 00 00 00  00 00 00 00 00 00 00 00  |'.sU............|
004211a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

ファイルとかディレクトリの中身にアクセスするには、i_block(offset 0x28/size 60)を見る。

エクステントが有効になっているかどうかで、たどり方が変わる。
スーパーブロックのs_feature_incompatのINCOMPAT_EXTENTSビットが有効で、かつ、inodeのi_flagsのEXT4_EXTENTS_FLが有効になっていれば、そのinodeはエクステントが有効。

今の場合、エクステント有効で、i_blockは

% sudo hexdump -C -s 0x421128 -n 60 /dev/dm-0 | head
00421128  0a f3 01 00 04 00 00 00  00 00 00 00 00 00 00 00  |................|
00421138  01 00 00 00 21 24 00 00  00 00 00 00 00 00 00 00  |....!$..........|
00421148  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00421164

になっている。

先頭12Bがヘッダになっていて、最初の2Bがマジックナンバーで0xf30a。
eh_depth(offset 0x6/size 2)が0なので、エクステントインデックスは使われていない。

エクステントインデックスがないので続きはエクステント。
ee_start_hi(offset 0x6/size 2)とee_start_lo(offset 0x8/size 4)が開始位置のブロック番号。
ee_len(offset 0x4/size 2)がエクステントが使うブロック数。

なので0x2421のブロックから1ブロックぶんがこのエクステントの内容。

% sudo hexdump -C -s 0x2421000 /dev/dm-0 | head
02421000  02 00 00 00 0c 00 01 02  2e 00 00 00 02 00 00 00  |................|
02421010  0c 00 02 02 2e 2e 00 00  0b 00 00 00 14 00 0a 02  |................|
02421020  6c 6f 73 74 2b 66 6f 75  6e 64 00 00 01 00 2c 00  |lost+found....,.|
02421030  0c 00 04 02 62 6f 6f 74  01 00 e4 00 0c 00 03 02  |....boot........|
02421040  65 74 63 00 01 00 26 00  10 00 05 02 6d 65 64 69  |etc...&.....medi|
02421050  61 00 00 00 01 00 a2 00  0c 00 03 02 76 61 72 00  |a...........var.|
02421060  01 00 5e 00 0c 00 03 02  62 69 6e 00 01 00 24 00  |..^.....bin...$.|
02421070  0c 00 03 02 64 65 76 00  01 00 58 00 0c 00 04 02  |....dev...X.....|
02421080  68 6f 6d 65 01 00 c4 00  0c 00 03 02 6c 69 62 00  |home........lib.|
02421090  01 00 28 00 10 00 05 02  6c 69 62 36 34 00 00 00  |..(.....lib64...|

ルートディレクトリのディレクトリエントリが見えている。