ext4:ディスクレイアウトのめも3 エクステント

基本的には今まで通りExt4_Disk_Layoutを見つつ。

エクステントが有効化かどうかはスーパーブロックのs_feature_incompatのbit0x40(INCOMPAT_EXTENTS)が立っているかどうかでわかる。他にもinodeのi_flagsのビット0x80000(EXT4_EXTENTS_FL)が立っていたらこのinodeはエクステントが使われているとわかる。

エクステントの構造は大きく分けて以下の3個になっている。

  • エクステントヘッダー
  • エクステントインデックス
  • エクステント

エクステントに関するデータ構造はfs/ext4/ext4.hにある。 エクステントヘッダーはstruct ext4_extent_headerで以下のような内容。

 94 /*
 95  * Each block (leaves and indexes), even inode-stored has header.
 96  */
 97 struct ext4_extent_header {
 98         __le16  eh_magic;       /* probably will support different formats */
 99         __le16  eh_entries;     /* number of valid entries */
100         __le16  eh_max;         /* capacity of store in entries */
101         __le16  eh_depth;       /* has tree real underlying blocks? */
102         __le32  eh_generation;  /* generation of the tree */
103 };

eh_magicはエクステントヘッダーを示すマジックナンバーで0xf30a。eh_depthはエクステントのツリー構造の深さなんだけど、これが0の場合はエクステントインデックスを使わずに直接エクステントを見るようになっている。

エクステントインデックスはstruct ext4_extent_idx で以下のような内容。

 82 /*
 83  * This is index on-disk structure.
 84  * It's used at all the levels except the bottom.
 85  */
 86 struct ext4_extent_idx {
 87         __le32  ei_block;       /* index covers logical blocks from 'block' */
 88         __le32  ei_leaf_lo;     /* pointer to the physical block of the next *
 89                                  * level. leaf or next index could be there */
 90         __le16  ei_leaf_hi;     /* high 16 bits of physical block */
 91         __u16   ei_unused;
 92 };

エクステントext4_extentは以下の通り。

 71 /*
 72  * This is the extent on-disk structure.
 73  * It's used at the bottom of the tree.
 74  */
 75 struct ext4_extent {
 76         __le32  ee_block;       /* first logical block extent covers */
 77         __le16  ee_len;         /* number of blocks covered by extent */
 78         __le16  ee_start_hi;    /* high 16 bits of physical block */
 79         __le32  ee_start_lo;    /* low 32 bits of physical block */
 80 };

実際のデータへのポインタになるのはこのext4_extent。

あとはstruct ext4_extent_tailというエクステントの最後に置かれるデータもあるけど。

 60 /*
 61  * This is the extent tail on-disk structure.
 62  * All other extent structures are 12 bytes long.  It turns out that
 63  * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
 64  * covers all valid ext4 block sizes.  Therefore, this tail structure can be
 65  * crammed into the end of the block without having to rebalance the tree.
 66  */
 67 struct ext4_extent_tail {
 68         __le32  et_checksum;    /* crc32c(uuid+inum+extent_block) */
 69 };

では実際のディスクイメージと合わせてみてみる。 まず、エクステントヘッダーがどこにあるのかというところだけど、これはinodeのi_blockの領域が使われている。ここはext3や、ext4でもエクステントを使わない場合はdirect/indirectブロックに使われるところ。 前回も使ったtest.txtのinodeはこのような感じで、この中にi_blockがあるのでそこだけ抜き出すと

00061b00  a4 81 00 00 90 00 00 00  35 fe e4 52 35 fe e4 52  |........5..R5..R|
00061b10  35 fe e4 52 00 00 00 00  00 00 01 00 08 00 00 00  |5..R............|
00061b20  00 00 08 00 01 00 00 00  0a f3 01 00 04 00 00 00  |................|
00061b30  00 00 00 00 00 00 00 00  01 00 00 00 41 80 00 00  |............A...|
00061b40  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

このような感じに。

00000000  0a f3 01 00 04 00 00 00 00 00 00 00 00 00 00 00 | ................
00000010  01 00 00 00 41 80 00 00 00 00 00 00 00 00 00 00 | ....A...........
00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00000030  00 00 00 00 00 00 00 00 00 00 00 00             | ............

先頭の2バイトがマジックナンバーでここはリトルエンディアンなのでひっくり返すと0xf30aに。次はeh_entriesで2バイトなのでエントリ数は1。次は2バイトのeh_maxで最大で4個のエントリが持てると。その次はeh_depthでこれも2バイトで値は0。次も2バイトでeh_generation。これはwikiページによると「Used by Lustre, but not standard ext4」となっているのでext4では未使用。 このファイルはeh_depthが0なのでエクステントインデックスは使われずに直接エクステントにアクセスできることがわかる。

それでは引き続きデータを見ていく。ここからはエクステントで最初が4バイトのee_blockで値は0。次が2バイトのee_lenで値は1。次とその次はブロックのアドレスの上位、下位ビット。最初が上位16bitで0、次が下位32bitで0x8041。 ということで、データが置かれているのはブロック0x8041ということがわかり、これにブロックサイズかけてバイト位置を出すと

masami@saga:~/codes/read_ext4$ echo "obase=16;ibase=16; 8041*1000" | bc
8041000

アドレスは0x8041000ということがわかる。長さ(ee_len)は1なので1ブロック分がこのtest.txtのデータ領域。ではディスクイメージのダンプでそのアドレスを見てみる。

08041000  61 62 63 64 65 66 67 68  0a 61 62 63 64 65 66 67  |abcdefgh.abcdefg|   <-- data of test.txt
08041010  68 0a 61 62 63 64 65 66  67 68 0a 61 62 63 64 65  |h.abcdefgh.abcde|
08041020  66 67 68 0a 61 62 63 64  65 66 67 68 0a 61 62 63  |fgh.abcdefgh.abc|
08041030  64 65 66 67 68 0a 61 62  63 64 65 66 67 68 0a 61  |defgh.abcdefgh.a|
08041040  62 63 64 65 66 67 68 0a  61 62 63 64 65 66 67 68  |bcdefgh.abcdefgh|
08041050  0a 61 62 63 64 65 66 67  68 0a 61 62 63 64 65 66  |.abcdefgh.abcdef|
08041060  67 68 0a 61 62 63 64 65  66 67 68 0a 61 62 63 64  |gh.abcdefgh.abcd|
08041070  65 66 67 68 0a 61 62 63  64 65 66 67 68 0a 61 62  |efgh.abcdefgh.ab|
08041080  63 64 65 66 67 68 0a 61  62 63 64 65 66 67 68 0a  |cdefgh.abcdefgh.|
08041090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

( ´∀`)bグッ! 

Linuxカーネル Hacks ―パフォーマンス改善、開発効率向上、省電力化のためのテクニック

Linuxカーネル Hacks ―パフォーマンス改善、開発効率向上、省電力化のためのテクニック