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
1.1k
Btrfsの構造
naota
5
2.7k
Other Decks in Technology
See All in Technology
JEDAI Meetup! Databricks AI/BI概要
databricksjapan
0
150
OpenID Connect for Identity Assurance の概要と翻訳版のご紹介 / 20250219-BizDay17-OIDC4IDA-Intro
oidfj
0
280
次世代KYC活動報告 / 20250219-BizDay17-KYC-nextgen
oidfj
0
260
Nekko Cloud、 これまでとこれから ~学生サークルが作る、 小さなクラウド
logica0419
2
980
SA Night #2 FinatextのSA思想/SA Night #2 Finatext session
satoshiimai
1
140
「海外登壇」という 選択肢を与えるために 〜Gophers EX
logica0419
0
710
転生CISOサバイバル・ガイド / CISO Career Transition Survival Guide
kanny
3
1k
表現を育てる
kiyou77
1
220
人はなぜISUCONに夢中になるのか
kakehashi
PRO
6
1.7k
君も受託系GISエンジニアにならないか
sudataka
2
440
白金鉱業Meetup Vol.17_あるデータサイエンティストのデータマネジメントとの向き合い方
brainpadpr
6
770
The Future of SEO: The Impact of AI on Search
badams
0
200
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
182
22k
Git: the NoSQL Database
bkeepers
PRO
427
64k
How to Ace a Technical Interview
jacobian
276
23k
The Invisible Side of Design
smashingmag
299
50k
BBQ
matthewcrist
87
9.5k
Rails Girls Zürich Keynote
gr2m
94
13k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Side Projects
sachag
452
42k
Docker and Python
trallard
44
3.3k
The World Runs on Bad Software
bkeepers
PRO
67
11k
Speed Design
sergeychernyshev
27
790
Designing on Purpose - Digital PM Summit 2013
jponch
117
7.1k
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: 関数の終わり