Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
btrfs領域管理一代記
Search
naota
September 23, 2017
Technology
2
1.1k
btrfs領域管理一代記
naota
September 23, 2017
Tweet
Share
More Decks by naota
See All by naota
ファイルシステムの歴史: ジャーナリング編
naota
2
980
DockerでGentooのテスト
naota
3
1.7k
Btrfsのころしかた(だったもの)
naota
0
1k
Btrfsの構造
naota
5
2.7k
Other Decks in Technology
See All in Technology
ハイテク休憩
sat
PRO
2
170
オプトインカメラ:UWB測位を応用したオプトイン型のカメラ計測
matthewlujp
0
180
マルチプロダクト開発の現場でAWS Security Hubを1年以上運用して得た教訓
muziyoshiz
3
2.4k
組織に自動テストを書く文化を根付かせる戦略(2024冬版) / Building Automated Test Culture 2024 Winter Edition
twada
PRO
17
4.8k
Snykで始めるセキュリティ担当者とSREと開発者が楽になる脆弱性対応 / Getting started with Snyk Vulnerability Response
yamaguchitk333
2
190
社内イベント管理システムを1週間でAKSからACAに移行した話し
shingo_kawahara
0
190
kargoの魅力について伝える
magisystem0408
0
210
継続的にアウトカムを生み出し ビジネスにつなげる、 戦略と運営に対するタイミーのQUEST(探求)
zigorou
0
610
[Ruby] Develop a Morse Code Learning Gem & Beep from Strings
oguressive
1
170
なぜCodeceptJSを選んだか
goataka
0
160
PHP ユーザのための OpenTelemetry 入門 / phpcon2024-opentelemetry
shin1x1
1
490
AWS re:Invent 2024で発表された コードを書く開発者向け機能について
maruto
0
200
Featured
See All Featured
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
Navigating Team Friction
lara
183
15k
Git: the NoSQL Database
bkeepers
PRO
427
64k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
45
2.2k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
111
49k
Typedesign – Prime Four
hannesfritz
40
2.4k
Fireside Chat
paigeccino
34
3.1k
GitHub's CSS Performance
jonrohan
1030
460k
Code Reviewing Like a Champion
maltzj
520
39k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
29
2k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Transcript
btrfs領域管理一代記 牛酪亭直太
Linuxファイルシステム戦国時代 • 台頭する新興FSたち ◦ 平成13(2001)年1月: ReiserFS, Linuxに入る ◦ 同6月: JFS
◦ 平成14(2001)年: XFS • そのころのFS: Ext3, XFS, ReiserFS ◦ Ext3はLinux古来の流れを組む由緒正しき FS ▪ ext1は, 文献上のみで知られ、実 (用的に存)在はしなかったと言われている ▪ ext3を刷新したext4の開発 ◦ XFSはSGIの流れを組む(Linuxでは)比較的新しいFS • ReiserFS ◦ 初めてジャーナリングを Linuxに持ちこんだ ◦ B+treeに様々なmetadataを保管
Btrfsの建国 • 平成18(2006)年: Reiser家「お家騒動」により, 開発中のReiser4は凋落 • Btrfs創設者: Chris Mason ◦
もともとSuSEでReiserFSの開発に関わる ◦ その後、OracleにてBtrfsを立ち上げ ◦ Fusion-IOを経て、現在はFacebook所属 • 平成19(2007)年, Btrfsの誕生 ◦ [ANNOUNCE] Btrfs: a copy on write, snapshotting FS ◦ B-trees, Shadowing, and Clones [Rodeh, ToS’07] による, CoW フレンドリーなB-tree
Btrfs七勇士と家臣団 • Btrfs七勇士 ◦ checksumによるデータ保護 ◦ snapshot ◦ subvolume ◦
複数デバイスサポート ◦ 透過的圧縮 ◦ send/recvを使った効率的差分バックアップ ◦ dedupe • Btrfsを支える関数総勢1791個 • 今日のお題 find_free_extent() ◦ 指定されたサイズの空き領域を探索する関数
find_free_extent()奇々怪々 • 行数482行の大関数 ◦ その半分近くを占める 259行の大ループ • 8つのgoto label, 22のgoto文
◦ 右図のような状態遷移 (単純な上下は省略) 大ループ
通常のFSのマッピング 通常のFSはファイルアドレスと ディスク上のアドレスを直接マッピング
Btrfsのマッピング: extent空間 • 複数デバイスに対応するため, ディスクに直接マッピングしにくい
Btrfsのマッピング: extent空間 • 複数デバイスに対応するため, ディスクに直接マッピングしにくい • extent空間という「仮想領域」を 中間にはさむ • extent上のBlock
Groupが, さらにディス クにマップされる
find_free_extent()の読解ポイント • free space cache treeを知る ◦ free spaceをメモリ上で管理する tree
• クラスタを知る ◦ cacheから条件に合う領域だけを集めた tree • “loop”変数に惑わされない ◦ 4つのstageと考える ◦ stageごとにallocation戦略が変わる • アロケーションの階層をイメージする ◦ クラスタからのalloc ◦ BlockGroupからクラスタへのrefill ◦ extent空間から新しいBlockGroupのalloc ◦ 最後の手段: クラスタなしのalloc
free space cache tree: 連続領域(extent)ノード • free space cache tree
◦ 空き領域の位置とサイズを管理する赤黒木 ◦ 各BlockGroupで一つ、メモリ上に構築 ◦ 構築するにはIOが必要 • ノード ◦ キー 空き領域の開始アドレス (BGの先頭からのオフセット ) ◦ bytes 空き領域のサイズ • 一つの連続した空き領域(extent)に対して、一つのノード
free space cache tree: bitmap • 断片化した領域を保持するには、多くのノードが必要になる ◦ 一連続領域に一ノードの弊害 •
ある程度断片化したところで、extentノードをbitmapノードに変換 • bitmapノードの開始位置は128MBにalignされる ◦ 結果的に、同じアドレスをキーとして "bitmapノード"と"extentノード"とが重複する ▪ (コードがめんどくなるんよ ) ◦ 128MB = 1つのbitmapでカバーする領域 ◦ BGが大きくても1GBなので、断片化しまくっても 8つのbitmapノードで覆うことができる
クラスタ • 各BGのcacheの, さらに上位のcache ◦ metadata と dataでそれぞれ1つ • cacheは,
offsetをキーとするため, サイズを条件とした探索ができない ◦ 赤黒木なのに線形探索 ◦ 効率化のため, 一定の条件に合う領域を「クラスタ」に集めておく • クラスタは可能なかぎり、extentノードだけで作られる ◦ bitmapノードは断片化しているため , allocが成功しにくい • できる限り, このクラスタからallocを行う
クラスタとmount option • BtrfsのSSD最適化 ◦ 2つのmount option: SSD, SSD_SPREAD •
mount optionによりクラスタ作成法が変わる ◦ SSD_SPREAD ▪ alloc_size + 2M の領域を見つけだす . それ未満の領域を全て無視 ◦ metadata ▪ alloc_size の領域を1つ確保 ▪ 最低成立量: SSD: 2MB, HDD 64K ◦ data: alloc_size の領域を1つ確保. 最低成立量なし
秘技loop二刀流 • 2つの”loop” ◦ gotoラベルのloop ◦ 変数のloop • 2つの"loop"は独立している •
goto loopは"見える"forループを回す ◦ continueのようなもの • loop変数は, "見えない"ループのカウンタ ◦ goto searchで”見える”forループの後から前に戻る時にインクリメント • ここからloop変数のことを”stage”と言いかえる ◦ stageごとに、alloc戦略が変わる
アロケーションの階級社会 1. CACHING_NOWAIT ◦ クラスタからalloc ◦ 適宜クラスタを作る ◦ cacheを待たない 2.
CACHING_WAIT ◦ NOWAITと同じ ◦ cacheを待つ 3. ALLOC_CHUNK ◦ 新しいBGを作る ◦ あとはNOWAIT 4. NO_EMPTY_SIZE ◦ 最終手段 ◦ クラスタを使わない
関数冒頭, そしてループに飛び越む • last_ptr = fetch_cluster_info(fs_info, space_info, &empty_cluster); ◦ last_ptrに「最後に使ったクラスタ」を読みこむ
◦ empty_clusterには、クラスタを作る時用にほしいクラスタサイズが入る • if (last_ptr->block_group) hint_byte = last_ptr->window_start; ◦ 最後に使っていたクラスタがあれば , 引数のalloc hintは無視! • goto have_block_group; ◦ Block Groupをlockしたら、一気に大ループのどまん中に飛び越む !!!
have_block_group: • このラベルの時点で、allocを試みるBlockGroupが決まっている • if (!block_group_cache_done(block_group)) cache_block_group(block_group, 0); ◦ cacheができていなければ、
cacheするスレッドを走らせる • btrfs_alloc_from_cluster(...) ◦ クラスタからのallocを試みる ◦ 必要な領域を取得できれば -> goto checks ◦ 取得できなければ, release_cluster へ
release_cluster:/refill_cluster • release_cluster: クラスタを解放するための場所 • btrfs_return_cluster_to_free_space(NULL, last_ptr); ◦ クラスタに確保していた空き領域情報をBlockGroupのcacheに返却 •
refill_cluster: BGからクラスタに領域を確保する場所 • btrfs_find_space_cluster() ◦ クラスタを作り直す ◦ クラスタを作ったら ▪ btrfs_alloc_from_cluster()で、できたてのクラスタから alloc ◦ 作れなかった or やっぱりクラスタから allocできなかったら ▪ クラスタを解放(クラスタからallocできない時用) ▪ goto loop して、次のBlockGroupへ
checks: / loop: • checks: allocがうまくいった時にgoto ◦ 領域の確認や, メモリ上での空き容量情報を更新する •
loop: allocがうまくいかなかった時に goto ◦ いくつか変数をresetし, BlockGroupを解放して, ループをまわり次の BlockGroupへ
ループの後 • allocする領域を見つけた / 全てのBGからallocをためし終わった • まだallocできてなければ、ここで次のstageを決める ◦ stage ==
CACHING_NOWAIT ▪ cacheをkickしたBGがあれば -> 次はCACHING_WAIT ▪ なければ -> ALLOC_CHUNK ◦ stage == ALLOC_CHUNK ▪ BlockGroup (=CHUNK)を新しく1つ作る ▪ 作れたら -> goto serachで、またループ (いま作ったBGからとれるはず) ▪ 作れなかった -> 次はNO_EMPTY_SIZE
NO_EMPTY_SIZEでのループ • 最終手段のalloc ◦ クラスタのサイズ下限を撤廃 : クラスタが前より成立しやすい ! ▪ とかなってんだけど、そもそも
if (loop >= LOOP_NO_EMPTY_SIZE) goto unclustered_alloc しててクラスタ作んない • btrfs_find_space_for_alloc() ◦ 直接cacheからのalloc ◦ allocできたら -> checks へ ◦ allocできなかった, かつ、 まだcache完成してなかったら -> cacheを待ってもう一度 ◦ allocできなかった -> goto loopでつぎのBG
アロケーションの階級社会 (再掲) 1. CACHING_NOWAIT ◦ クラスタからalloc ◦ 適宜クラスタを作る ◦ cacheを待たない
2. CACHING_WAIT ◦ NOWAITと同じ ◦ cacheを待つ 3. ALLOC_CHUNK ◦ 新しいBGを作る ◦ あとはNOWAIT 4. NO_EMPTY_SIZE ◦ 最終手段 ◦ クラスタを使わない
今日のまとめ • Ext*: 平家のようなFS • XFS: SeiwaGenjIのようなFS • ReiserFS: 織田信長のようなFS
Linuxファイルシステムを天下統一するのは誰なのか アロケータを把握したいま, みなさんはもはやbtrfsの家臣も同然. btrfsを盛り立てていきましょう
何度も同じループしすぎでは? • ぼくもそう思います • ループしてる間にほかの人が、領域解放した可能性はあるので・・・
ラベルとinvariant • search: “見える”ループを使って探索, stageの開始地点 • have_block_group: allocを試みるBlockGroupを決定した • release_cluster:
クラスタからallocできなかった. クラスタを解除 • refill_cluster: BGからクラスタに領域を確保 • unclustered_alloc: クラスタを使わずBG全体からallocを試みる ◦ BGはfragmentedしており、クラスタをとれない • checks: 候補となる領域を見つけた. 要求を満たすかを確認 • loop: 次のBGに移行 • out: 関数の終わり