48
ファイルシステム(2) 2014/07/27 Yoshihiro YUNOMAE 1

Ext4 filesystem(2)

Embed Size (px)

DESCRIPTION

Investigation on ext4 filesystem of current Linux This slide focuses on addition of ext4 extents. EXT4 filesystem(1): http://www.slideshare.net/YoshihiroYunomae/f-36905134

Citation preview

Page 1: Ext4 filesystem(2)

ファイルシステム(2)2014/07/27

Yoshihiro YUNOMAE

1

Page 2: Ext4 filesystem(2)

今回のメイン• extentに管理されている物理ブロックの取得

• 初期化・未初期化 • extentの分割 • extentの追加

• extentがぎっしり詰まっているところにextentを追加したらどうなる?

2

Page 3: Ext4 filesystem(2)

extentの復習 (http://www.slideshare.net/

YoshihiroYunomae/f-36905134)

Page 4: Ext4 filesystem(2)

ext4_map_blocks()!-> ext4_ext_map_blocks() // extent用! -> ext4_ext_handle_unwritten_extents()! -> ext4_ext_convert_to_initialized() ! -> ext4_split_extent()! -> ext4_split_extent_at()! -> ext4_ext_insert_extent()! -> ext4_create_new_leaf()

4

ext4_map_blocks()• ext4用のlblockからpblockを取得する関数

• pblockの取得のことをmapという • map中はi_data_semのwrite lockがかかる

• i_dataがこの操作中に変わることがあるため

i_data_sem wlock

Page 5: Ext4 filesystem(2)

extentにおけるmap• 論理ブロックは1つのextentに管理される範囲内か

• 2つ以上にまたがっていたら隣のextentも気にしなければならない • 簡単のため、またがった状況は考えない

• 論理ブロックは初期化されているか • 1つのextentで管理される論理ブロックは、               全て初期化さてれいる or 全く初期化されていないのどちらか

• 周囲の論理ブロックは初期化されているか • 前後の論理ブロックとマージ出来るならマージ

• extentを追加しようと思ったときに、そのブロック内に空きがあるか

5

lblk

1 eof_blockextent Nの管理領域

mapped blocks initialized blocks uninitialized blocks

Page 6: Ext4 filesystem(2)

extentの初期化済・未初期化• 正確にはwritten/unwrittenが正しい

• initialized/uninitializedを使わないようにしようという動きもある (http://www.spinics.net/lists/linux-ext4/msg42877.html)

• ここではwritten: 初期化済, unwritten: 未初期化 という意味 • ext4_extent構造体extのee_len(16bit)のMSBがunwritten(未初期化)フラグ

• EXT_INIT_MAX_LEN = (1UL << 15)

6

static inline int ext4_ext_is_unwritten(struct ext4_extent *ext) { return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN); } static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) { return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ? le16_to_cpu(ext->ee_len) : (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN)); }

Page 7: Ext4 filesystem(2)

ext4_ext_map_blocks()• extent用のmapするブロックを取得する関数

• extentでないときはext4_ind_map_blocks() • mapするブロックが複数にまたがっていないとき、ブロックが初期化済か 未初期化かで処理がわかれる。 • 初期化済 & 未初期化に変更: ext4_ext_convert_initialized_extent()

• fallocate(2)でzero埋めするとき(FALLOC_FL_ZERO_RANGE)に使用 • 初期化済: そのままそのブロックを使用 • 未初期化: ext4_ext_handle_unwritten_extents()

• ここでは未初期化の場合を考える

7

Page 8: Ext4 filesystem(2)

8

ext4_map_blocks()!-> ext4_ext_map_blocks() // extent用! -> ext4_ext_handle_unwritten_extents()! -> ext4_ext_convert_to_initialized() ! -> ext4_split_extent()! -> ext4_split_extent_at()! -> ext4_ext_insert_extent()! -> ext4_create_new_leaf()!! ! ! ! ! ! ! -> ext4_ext_split()!! ! ! ! ! ! ! -> ext4_ext_grow_indepth()

Page 9: Ext4 filesystem(2)

ext4_ext_handle_unwritten_extents()• 以下の条件を満たしたときに、この関数を実行

• あるextentsで管理している論理ブロック内に、mapしようとしている 論理ブロックが存在(またがっていない)

• そのextentsで管理している論理ブロックは初期化されていない • ext4_map_blocks()で使われるフラグによって様々な関数に分岐し、実際に

mapするブロック数(allocated)を取得 • ここではbuffered read/writeを想定

• ext4_ext_convert_to_initialized()を実行して、その結果をallocatedとして返す

• et4_ext_convert_to_initialized()の結果によっては、要求したブロック数に対して多くアロケーションする場合があり(前後のextentとマージした場合など)、その場合は要求したブロック数に修正する

9

Page 10: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()• ここから先は、初期化されない論理ブロックと、初期化される論理ブロック

(mapする論理ブロック)を分ける作業 • 可能であれば前後のextentとマージしてしまう • extentを2つあるいは3つにsplit

• 今からmapする論理ブロックがextentのどの位置にあるか、また前後の論理ブロックの状態(初期化済か未初期化)で、マージするか分裂するか決定 !

• m_lblk: mapする最初の論理ブロック(mapped logical block) • map_len: mapする論理ブロック数 • ee_block: extentの最初の論理ブロック • ee_len: extentの使用論理ブロック数

10

Page 11: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()• ここから先は、初期化されない論理ブロックと、初期化される倫理ブロック

(mapする論理ブロック)を分ける作業 • 可能であれば前後のextentとマージしてしまう!• extentを2つあるいは3つにsplit

• 今からmapする論理ブロックがextentのどの位置にあるか、また前後の論理ブロックの状態(初期化済か未初期化)で、マージするか分裂するか決定 !

• m_lblk: mapする最初の論理ブロック(mapped logical block) • map_len: mapする論理ブロック数 • ee_block: extentの最初の論理ブロック • ee_len: extentの使用論理ブロック数

11

Page 12: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()• 前方のextentとマージする条件

• L0: extentの最初からmap • L1: extentの範囲内(mal_len >= ee_lenはextentの削除を意味) • L2: 前方にextentが存在 • C1: 前方のextentが初期化済 • C2, C3: 前方のextetのブロックと論理的・物理的に連続 • C4: マージした後もextentの最大サイズを超えない

12

if ((map->m_lblk == ee_block) && /*L0*/ (map_len < ee_len) && /*L1*/ (ex > EXT_FIRST_EXTENT(eh))) { /*L2*/ … if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/ ((prev_lblk + prev_len) == ee_block) && /*C2*/ ((prev_pblk + prev_len) == ee_pblk) && /*C3*/ (prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/

Page 13: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()• 後方のextentとマージする条件

• L0: extentの最後までmap • L1: extentの範囲内(mal_len >= ee_lenはextentの削除を意味) • L2: 後方にextentが存在 • C1: 後方のextentが初期化済 • C2, C3: 後方のextetのブロックと論理的・物理的に連続 • C4: マージした後もextentの最大サイズを超えない

13

} else if (((map->m_lblk + map_len) == (ee_block + ee_len)) && /*L0*/ (map_len < ee_len) && /*L1*/ ex < EXT_LAST_EXTENT(eh)) { /*L2*/ … if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/ ((map->m_lblk + map_len) == next_lblk) && /*C2*/ ((ee_pblk + ee_len) == next_pblk) && /*C3*/ (next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/

Page 14: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()• ee_len(extentの長さ) <= ゼロ初期化長の場合、そのextent全体をゼロ初期化

!!• s_extent_max_zeroout_kb: デフォルト32 • extent_max_zeroout_kbというsysfsファイルが用意されている

• /sys/fs/ext4/sda1/extent_max_zeroout_kb !

• 周囲とマージ出来る場合はマージする • ext4_ext_try_to_merge()

14

max_zeroout = sbi->s_extent_max_zeroout_kb >> (inode->i_sb->s_blocksize_bits - 10);

Page 15: Ext4 filesystem(2)

マージ処理• マージのための条件 ext4_can_extents_be_merged()より

• 前後のextentが両方とも初期化済あるいは未初期化であること • 前のextentの論理ブロックが後のextentの論理ブロックとつながること • 前後のextentの論理ブロックの長さの合計がextentの管理最大数を超えないこと

• 前のextentの物理ブロックが後のextentの論理ブロックとつながること

15

Page 16: Ext4 filesystem(2)

マージ処理

16

static void ext4_ext_try_to_merge() { … int merge_done = 0; … if (ex > EXT_FIRST_EXTENT(eh)) /* 左側のextentとマージ */ merge_done = ext4_ext_try_to_merge_right(inode, path, ex - 1); ! if (!merge_done) /* 右側のextentとマージ */ (void) ext4_ext_try_to_merge_right(inode, path, ex); ! /* inode->i_dataの中に収められるなら収める */ ext4_ext_try_to_merge_up(handle, inode, path); }

Page 17: Ext4 filesystem(2)

マージ処理

17

static int ext4_ext_try_to_merge_right() { … int merge_done = 0; … while (ex < EXT_LAST_EXTENT(eh)) { if (!ext4_can_extents_be_merged(inode, ex, ex + 1)) break; … ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) + ext4_ext_get_actual_len(ex + 1)); … if (ex + 1 < EXT_LAST_EXTENT(eh)) { … memmove(ex + 1, ex + 2, len); } le16_add_cpu(&eh->eh_entries, -1); merge_done = 1; … } return merge_done; }

Page 18: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()• ここから先は、初期化されない論理ブロックと、初期化される倫理ブロック

(今からmapする論理ブロック)を分ける作業 • 可能であれば前後のextentとマージしてしまう • extentを2つあるいは3つにsplit!

• 今からmapする論理ブロックがextentのどの位置にあるか、また前後の論理ブロックの状態(初期化済か未初期化)で、マージするか分裂するか決定 !

• m_lblk: mapする最初の論理ブロック(mapped logical block) • map_len: mapする論理ブロック数 • ee_block: extentの最初の論理ブロック • ee_len: extentの使用論理ブロック数

18

Page 19: Ext4 filesystem(2)

ext4_ext_convert_to_initialized()

19

• ここまで来たということは、ee_len > max_zeroout • splitには4つのパターンが存在(ここでは4パターンにするだけ) 1. 3つに分かれるパターン(真ん中に書き込まれる論理ブロックが存在) 2. 2つに分かれ、前半部分がmax_zerooutより小さいなら最初から0初期化 3. 2つに分かれ、後半部分がmax_zerooutより小さいなら最後まで0初期化 4. 2つに分かれるが初期化されない(両方ともmax_zerooutより大きい)

mapped blocks

max_zeroout ee_len

1 2

43

Page 20: Ext4 filesystem(2)

20

ext4_map_blocks()!-> ext4_ext_map_blocks() // extent用! -> ext4_ext_handle_unwritten_extents()! -> ext4_ext_convert_to_initialized() ! -> ext4_split_extent()! -> ext4_split_extent_at()! -> ext4_ext_insert_extent()! -> ext4_create_new_leaf()!! ! ! ! ! ! ! -> ext4_ext_split()!! ! ! ! ! ! ! -> ext4_ext_grow_indepth()

Page 21: Ext4 filesystem(2)

ext4_split_extent()• extent全体をsplitする関数

• 実際にsplitするのはext4_split_extent_at()

21

// mapped blocksがextent内 P.19 1, 2の右側 if (map->m_lblk + map->m_len < ee_block + ee_len) { … flags1 = flags | EXT4_GET_BLOCKS_PRE_IO; /* 後で出てくる */ … err = ext4_split_extent_at(handle, inode, path, map->m_lblk + map->m_len, split_flag1, flags1); … // 分岐しているが実際は全パターンで通過 p.19, 1-4の左側 if (map->m_lblk >= ee_block) { … err = ext4_split_extent_at(handle, inode, path, map->m_lblk, split_flag1, flags);

Page 22: Ext4 filesystem(2)

ext4_split_extent_at()• あるextentをsplitする関数

• P.19の2の左側のときはsplitする必要がないので前方のextentとマージ出来るならマージしてしまう

• それ意外のときはsplitする右側部分をnewexと定義し、ext4_ext_store_pblock()を実行

22

Page 23: Ext4 filesystem(2)

ext4_split_extent_at()

23

static int ext4_split_extent_at(…, ext4_lblk_t split,…) { … struct ext4_extent newex; struct ext4_extent *ex2 = NULL; … if (split == ee_block) { // P.19 2の左側だったら・・・ … ext4_ext_try_to_merge(handle, inode, path, ex); … goto out; } … ex2 = &newex; ex2->ee_block = cpu_to_le32(split); ex2->ee_len = cpu_to_le16(ee_len - (split - ee_block)); ext4_ext_store_pblock(ex2, newblock); … err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);

Page 24: Ext4 filesystem(2)

ext4_map_blocks()!-> ext4_ext_map_blocks() // extent用! -> ext4_ext_handle_unwritten_extents()! -> ext4_ext_convert_to_initialized() ! -> ext4_split_extent()! -> ext4_split_extent_at()! -> ext4_ext_insert_extent()! -> ext4_create_new_leaf()!! ! ! ! ! ! ! -> ext4_ext_split()!! ! ! ! ! ! ! -> ext4_ext_grow_indepth()

24

Page 25: Ext4 filesystem(2)

ext4_ext_insert_extent()• 新しいextentを追加する関数 • 前後のextentとマージ出来るならマージしてしまう • もしマージ出来ないなら、今あるdepthにextentを追加するための空きがあるかチェック • 空きがあったら新しいextentを作成する • 空きが無かったらext4_create_new_leaf()を実行し、空きスペースを作る

• 空きスペースが出来たら、新しいextentを作成する if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) /* 今のdepthに空きがある */ goto has_space; … /* 今のdepthに空きが無い */ err = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags, path, newext); … has_space: /* 後で説明 */

Page 26: Ext4 filesystem(2)

ext4_create_new_leaf()• 新しいextentを割り込んで挿入するために、leafに空きを作る関数 • ext4_ext_find_extent()から取得したpath配列から、各深さに対して空のindexを探し出す • 出来るだけ深いところから(leafから)indexの空きを探し出す

!!!!!!!

• もし空のindexがあった場合、ext4_ext_split()でindexを追加する • もし全ての深さに空のindexが無かった場合、ext4_ext_grow_index()で   1段深くする

• 結果空きのindexが出来るのでext4_ext_split()でindexを追加する26

i = depth = ext_depth(inode); curp = path + depth; // 最初はleafから // eh_entries < eh_max ? while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) { i--; curp--; }

Page 27: Ext4 filesystem(2)

ext4_create_new_leaf()

27

static int ext4_ext_create_new_leaf()!{!…!repeat:!! // indexの空きを検索(前ページ)!…! if (EXT_HAS_FREE_INDEX(curp)) {!! // 空き領域にindexを追加! err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! } else {! // 1段深くする! err = ext4_ext_grow_indepth(handle, inode, mb_flags, newext);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! /*! * only first (depth 0 -> 1) produces free space;! * in all other cases we have to split the grown tree! */! depth = ext_depth(inode);! if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {! /* now we need to split */! goto repeat;! }! }!…!

Page 28: Ext4 filesystem(2)

ext4_create_new_leaf()

28

static int ext4_ext_create_new_leaf()!{!…!repeat:!! // indexの空きを検索(前ページ)!…! if (EXT_HAS_FREE_INDEX(curp)) {!! // 空き領域にindexを追加! err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! } else {! // 1段深くする! err = ext4_ext_grow_indepth(handle, inode, mb_flags, newext);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! /*! * only first (depth 0 -> 1) produces free space;! * in all other cases we have to split the grown tree! */! depth = ext_depth(inode);! if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {! /* now we need to split */! goto repeat;! }! }!…!

Page 29: Ext4 filesystem(2)

ext4_ext_split()

29

hdr

index

index

empty

extent

extent

depth=0 (i_data) depth=1 depth=at

… … …

depth

path[1].p_idx path[depth].p_extここに 新しいextentを加えたい

Page 30: Ext4 filesystem(2)

ext4_ext_split()

extent

extent

depth最も深いところの

目的のleaf以下の長さをはかって・・・

m

30

Page 31: Ext4 filesystem(2)

ext4_ext_split()

31

extent

extent

depth

eh_entry=m

newblock

上書きされないように新しいブロックに待避

memmove m

m

Page 32: Ext4 filesystem(2)

ext4_ext_split()

32

eh_entry - m

extent

extent

empty

depth

eh_entry=m

newblock

上書きされないように新しいブロックに待避

m

Page 33: Ext4 filesystem(2)

ext4_ext_split()

33

extent

extent

empty

depthnewblock0

depth - 1

newblock1

newblock0用

memmove

空きindexのある 深さの前まで続ける

Page 34: Ext4 filesystem(2)

ext4_ext_insert_index() (ext4_ext_split()の延長)

34

挿入したいextentの 論理ブロックはei_blockの前?

eh_entry++

newblockへ

eh_entry++

newblockへ

前 後

empty

depth=at

or

memmove

Page 35: Ext4 filesystem(2)

35

eh_entry++

newblockNへ

depth=at depth-1

at+1

extent

extent

depth

ext4_ext_split()の結果1

Page 36: Ext4 filesystem(2)

36

eh_entry++

newblockNへ

depth=atdepth

(newblock0)

depth - 1 (newblock1)

newblock0用

at+1 (newblockN)

at+2用

ext4_ext_split()の結果2

… ………

Page 37: Ext4 filesystem(2)

ext4_create_new_leaf()

37

static int ext4_ext_create_new_leaf()!{!…!repeat:!! // indexの空きを検索(前ページ)!…! if (EXT_HAS_FREE_INDEX(curp)) {!! // 空き領域にindexを追加! err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! } else {! // 1段深くする! err = ext4_ext_grow_indepth(handle, inode, mb_flags, newext);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! /*! * only first (depth 0 -> 1) produces free space;! * in all other cases we have to split the grown tree! */! depth = ext_depth(inode);! if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {! /* now we need to split */! goto repeat;! }! }!…!

Page 38: Ext4 filesystem(2)

ext4_ext_grow_indepth()

38

hdr

index

index

extent

extent

depth=0 (i_data) depth=1 depth=k

… … …

depth

全て埋まっているので、 新しく深くしなければならない

Page 39: Ext4 filesystem(2)

ext4_ext_grow_indepth()

39

hdr

index

index

depth=0 (i_data) newblock

hdr

memmoveeh_maxの更新

Page 40: Ext4 filesystem(2)

ext4_ext_grow_indepth()

40

hdr

newblockへ

depth=0 (i_data)

depth=0のヘッダの更新 eh_entry=1 eh_depth++

新しい空きが出来た -> ext4_ext_split()を実行 ※indexが元々無い場合、 これで終了

newblock

hdr

Page 41: Ext4 filesystem(2)

ext4_create_new_leaf()

41

static int ext4_ext_create_new_leaf()!{!…!repeat:!! // indexの空きを検索(前ページ)!…! if (EXT_HAS_FREE_INDEX(curp)) {!! // 空き領域にindexを追加! err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! } else {! // 1段深くする! err = ext4_ext_grow_indepth(handle, inode, mb_flags, newext);!…! ! ! ! // ext4_ext_find_extent()を使って配列pathの更新! /*! * only first (depth 0 -> 1) produces free space;! * in all other cases we have to split the grown tree! */! depth = ext_depth(inode);! if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {! /* now we need to split */! goto repeat;! }! }!…!

Page 42: Ext4 filesystem(2)

やっとextentに空きが 出来た・・・

ext4_ext_insert_extent() { … if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) /* 今のdepthに空きがある */ goto has_space; … /* 今のdepthに空きが無い */ err = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags, path, newext); … has_space: /* 後で説明 */

Page 43: Ext4 filesystem(2)

43

ext4_ext_insert_extent()

extent

extent

depth

前に挿入する場合 (後ろ全部をmemmove)

後に挿入する場合 (後ろ全部をmemmove)

Page 44: Ext4 filesystem(2)

44

ext4_ext_insert_extent()

eh_entries++

extent

extent

newext

depth

新しいextentを追加出来たので 以後はnewextを利用

Page 45: Ext4 filesystem(2)

ext4の積み残し(適当な分類)• ラスボス級(確実に1回以上かかる)

• ジャーナリング(jbd/jbd2) • 中ボス級(1回で終わるかも)

• マウントオプション • extend status tree • fallocate(2)

• 一般級(複数個まとめて出来る) • delayed / multiblock / persistent allocation • inline data / xattr

• その他 • big allocation時のsmall fileの対策? • ext4のfsckが高速化したのはなぜ? • ext4_inode構造体の更新頻度は?

45

Page 46: Ext4 filesystem(2)

Appendix1: ext4_ext_find_extent()• 目的の論理ブロックを管理している、各深さのindex(tree)/extent(leaf)を バイナリサーチで探し出す関数

• ext4_ext_path構造体の深さ分の長さを持った配列pathを更新 • p_block: index/extentのある物理ブロック • p_depth: 管理している深さ(0であればextent) • p_ext: 目的のextentのポインタ(p_depth==0のときのみ存在) • p_idx: 目的のextentを管理しているある深さのindexへのポインタ

(p_depth>0) • p_hdr: ある深さのheaderへのポインタ • p_bh: index/extentのある物理ブロックのバッファヘッダへのポインタ

• pathの配列順所は深さと逆 • path[max_depth].p_depth == 0 • path[0].p_depth == max_depth

46

Page 47: Ext4 filesystem(2)

Appendix2: i_size以上の管理• max_zerooutを取得する前に、以下のようなソースあり。

!!

• EXT4_EXT_MAY_ZEROOUT: もしENOSPCでsplitに失敗したらそのextentを初期化するフラグ

• i_size以上の領域に初期化済のブロックがあると、fsckで不正なinode sizeだとされてしまうため、eof_blockより大きいextentにはENOSPCでsplit出来なくても初期化しない

• 一昔前(4年前)ではinode->i_size以上のブロック領域をextentで管理出来た • EXT4_INODE_EOFBLOCKS (inode用), EXT4_EOFBLOCKS_FL(user空間用) • しかしこの機能はもはや使われていない

• カーネル内ではEXT4_INODE_EOFBLOCKSをチェックして特別な処理をする機能は無い

• fsckもEXT4_EOFBLOCKS_FLをremove

47

split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0;

Page 48: Ext4 filesystem(2)

buffered writeのprocdedure

ext4_write_begin()! -> _ext4_get_block() // EXT4_GET_BLOCKS_CREATE(buffered write)! -> ext4_map_blocks()! -> ext4_ext_map_blocks()// ext4_es_lookup_extent()×! -> ext4_ext_handle_unwritten_extents() // m_lblkがextentの管理内!                       & extentはunwritten!! ! ! ! ! ! ! add EXT4_GET_BLOCKS_METADATA_NOFAIL! -> ext4_ext_convert_to_initialized() ! -> ext4_split_extent() // mapがextentの管理の途中から開始!! ! ! ! ! ! ! ! ! mapがextentと同一長さでない!! ! ! ! ! ! ! & ee_len * blocksize > extent_max_zeroout_kb! (extent_max_zeroout_kbはデフォルト32、sysfsでも変更可能)! -> ext4_split_extent_at()! -> ext4_ext_insert_extent()! -> ext4_create_new_leaf()

48