【読書メモ】絵で見てわかるLinuxカーネルの仕組み

絵で見てわかるLinuxカーネルの仕組み を読み始めました
Linuxのコアプログラムであるカーネルの処理をわかりやすく説明しようとする()本です
図は出てきますが、今のところ文章に依存して説明している印象です
ややタイトル詐欺
冒頭でカーネルのコードの読み方、どこから読んだらいいか、とか出てくるので沼に引きずりこもうとする筆者の手が見えました
事実を列挙しているタイプの本なので、あんまり蘊蓄としての面白さは望めないかもです…
推しのカーネルモジュール見つけたい

CFS:デフォルトのスケジューリングアルゴリズム
実行中プロセスに実行時間を均等に割り振る。処理順は今までの処理時間の短い順に。
nice値を見て実行優先度も変わる、nice値が1減ると割り当て時間が約1割増える。
EEVDF:Linux6.6から導入されたスケジューラ、CFSよりレイテンシが短くなるらしい。
リアルタイムスケジューラ:1から99までの優先度付きでプロセスを実行。
定期実行する時間厳守なプロセスに対して設定すること。やりすぎると時間不足でハングする。
デッドラインスケジューラ:処理制限時間がある最重要プロセスを実行。
事前に割り当て時間を設定できる。期限の近いものから処理する。Forkできない。
これ、仕事で作業の進め方、振り分け方の判断に使えそうかも
この作業はリアルタイムだな、みたいな。

メモリ管理の章に入りました
ユーザープロセスが利用できるmallocと、カーネルが利用するBuddy/スラブアロケータまでの話(mallocはカーネルで使えないので)
malloc
- glibcが提供
- システムコールとしてbrk()またはmmap()を実行(128KB以下の場合にbrk())
- brk()は初回特典で132KBの領域を確保する(余分に確保してシステムコールを減らしたいため)
- メモリ領域はリクエストした段階では確保されない(1GBをmallocしても、576KBしか実際には消費されない)
- ユーザープロセスが余分に確保しがちなため
- 書き込みがあれば実際に確保する
- これにより物理的なメモリ上限以上の確保:オーバーコミット が可能になる
- メモリ不足になったらあの手この手でメモリ解放しようとする。最終手段はOOM Killer
- OOM Killerが暴走する事があったらしい
アロケータ
- Buddyで大雑把(4KB単位)で確保
- それをスラブなりvmallocなりで再管理
- スラブアロケータの実装はSLABとSLUBとSLOBがある 違いは未知
- 空きスラブオブジェクトは、次の空きスラブオブジェクトのアドレス情報が入っている、これでメタ情報の管理を省いている(工夫〜 こういうの好きだからもっと知りたい)

スラブアロケータにおける開放時の動作の説明と、セキュリティオプション
あとvmallocの話
スラブアロケータは連結リストみたいな感じで未使用領域を管理している、
開放時にはリストの先頭に開放した領域が追加される
※メモリアドレスの大小関係は無視する
セキュリティオプションとして、
- 未使用領域の連結をメモリアドレスによらずランダムにする
- 次の未使用領域のアドレスを乱数とXORして難読化する
がある
→これにより、未使用の領域に悪意あるコードを先行書き込みしての任意コード実行を難しくしている
スラブアロケータは実質SLUBしかない、他のは廃盤
- 元祖スラブのSLABは使われていない
- フットプリントが少ないSLOBはSLUB-TINYとして残っているが、メモリが16MB以上の環境では非推奨(組み込み用)
vmalloc は、仮想アドレスを持ったメモリ領域を確保する
物理的は連続していないメモリ領域も確保できる
ページ(4KB)単位で取得した上、ガードページ(確保した以上のメモリ領域にコードを差し込もうとするのを防ぐためのページ)を確保する
素人目に見てメモリ上のフットプリントが大きい…

ファイルシステムの章に入りました
- Linuxのルートディレクトリ配下の構成はFHSという標準に書いてあるらしい
- イニシャルRAMディスクでブート→ストレージをマウント の流れで起動される
- 最初にストレージを読みに行くわけではないので、bin, sbinは本質的にはどこにあってもいい(だから/usr/binの下に置くのが主流にできた) 互換性維持のため、binとsbinは残ってる
- procとかsysは別のファイルシステム、そらそうか
- VFSによって、複数のファイルシステムを共通のインターフェースにしている(だからシェルで同じ見た目になる)
- VFSがキャッシュとかメタデータをinodeで管理してる 感謝
- ext4はjdb2の層でジャーナリングしている
- 書き込み途中の状態にあるファイルを管理することで、不正な状態にあるファイルを見つけやすくする
- ext2にはこれがなくて、復旧のために全スキャンが必要だった
- dev/randomは、Linux5.5までシステムのエントロピー収集を待つ必要があった
- これにより、DoS攻撃によってエントロピーが枯渇して性能低下することがあった
- 5.6からこれを簡略化し、性能が上がっている(エントロピーの収集能力が上がったのもある)
だいぶ前に、HAMMER2っていうファイルシステムを見たいというだけでDragonflyBSDをインストールする遊びをしたことがあります(苦しんだのでお勧めはしません)
これも復旧能力が高いんだとか(仕様はよくわかってない)

ブロックIO(ストレージデバイス)の章を読みました
HDD向け:セクタが連続しているか、回転方向に沿って並んでいるほど読み込みが短時間で終わる→IOスケジューラがバッファにリクエストを溜めてIO処理を短縮
SSD向け:SATAならIOスケジューラがまだ働いてる、でも各CPUで処理するように構成変更
NVMeだとIOスケジューラがかえって邪魔なので無効化されている
その他のブロックデバイス
- ファイルをストレージ扱い(loop)
- メモリの一部をファイルに(brd, zram)
- zramは圧縮して格納するのでメモリ消費量が減らせる、組み込み向け
- 複数のストレージを組み合わせてコストと性能を両立(bcache)→死ぬほどチューニングむずそう
あとRAIDの話

デバイスマッパの章を読んだんですが、正直ピンときません
Linuxでちょこちょこ遊ぶ程度だと遭遇しなかったというか…たぶんディストリビューションがいい感じに設定している部分なので
ざっくり掴んだイメージで言うと、ブロックデバイス(≒ストレージ)上に特殊な機能を持ったブロックデバイスを配置できる機能です
パーティションに分ける、みたいなノリで、ある領域を暗号化したり、壊れている風の動作をさせてテスト用にしたり…
ここまで生っぽいLinux触る機会が今後あるかわかんないけど、何かそういう事ができる、程度に思っておきます(なんかちょっと組み込みに近接してる気がする)

LVMとネットワークの章を読みました
もっとLinuxのコアな話が読めるかと思ったら、やたら具体的な管理ツールの話が続いててちょっと期待外れな状態に…
LVM:物理ストレージを束ねて、それを仮想ストレージに再分配するツール。
複数のストレージの物理的な問題を考えずに済むし、耐障害性も上がるんだろう、きっと
ネットワークの章は、TCP/IPの4階層モデル(知ってるな〜の話)とXDPの話でした
XDP:浅い理解としては、ネットワーク通信をユーザー層でも処理することで、高機能化とカーネル側の負荷軽減による性能向上を図る、というもののようです
ごめん、インフラ屋さんじゃないからよくわからん…

セキュリティの章を読みました
アクセス制御、ファイル暗号化やLOCKDOWNまで
chmodとかケーパビリティ設定(root権限を機能で分類したもの)により、権限を設定するDAC(任意アクセス制御)と、
Linuxカーネルの機能を利用したMAC(強制アクセス制御)の2つがある 後者のほうが厳しい
ファイル暗号化は、ディスク上にファイルを暗号化して保管、ファイルシステムで参照する時に復号して読む
物理的にハードディスクを読もうとしても無駄。BitLockerとかがこれ(たぶん)
Intel系ならTPM(win11の性能要件にもなったやつ)
ARM系ならTrustZoneがある
TPMは専用チップ、TrustZoneは仮想環境内で実行(CPUは通常プロセスと共用)という違いがあり、結果的にTPMのほうが遅い。
その他、USBデバイスのブロックやLOCKDOWNによるカーネル機能へのアクセスのブロックなんかも軽く説明されます。
あー考えることが多すぎてようわかん

仮想化技術の章に入りました
ホストOSを仲介させるのかさせないのか
周辺機器をどこまでエミュレートするのか
基本的にはオーバーヘッドの抑制を主軸に進む
処理負荷の重い要素は切除して機能制限を発生させつつも、それなりな効率で動作することを目指す
PCIeデバイスをパススルーさせたり(VFIO)、CPUのコアを仮想環境ごとに固定して割り当てたり(CPU Affinity, CPU Isolation)
で、もっとシンプルに仮想化を実現しようとしてコンテナ型に(次の章)

コンテナ仮想化の話とか
もういい加減細かくて面白くもなくなってきたのでざっと読み
Dockerが使うファイルシステム:overlayがよくわからん
lowerdirとupperdirがあって、mergedirで統合されて見える
Dockerコンテナ内のファイルは確かに別ディレクトリに格納されてる(マウントは別の話)のでまあ分かるか…と思いつつ
upperとlowerなんて意識したことない…
コンテナ内のシステムコールは権限を細かく設定できる。
makedirさせない、みたいなこともできるし、
権限逸脱したらプロセスを強制停止させることもできる。
クラウド開発とかで、悪意あるコード実行をブロックするのに使ってそう。めっちゃセキュアなルールを求められたとき用に覚えといて損はないかも。
その後、ASanとかトラブルシューティングの話になった。最近調査してるlighttpdの更新履歴にもあった気がする。
メモリ違反を検出するやつ。
総評、「絵で見てわかる」と言いつつ大半が文字に依存している。絵はあるが、特筆すべきほど分かりやすさに貢献しているのは稀で書籍タイトルに入れるほどの意味は感じない。
後半はLinuxカーネルからの派生機能の説明になっていくので、原始的な技術説明を求めていた感情的には少し損。
※Linux環境を細かく調整する必要があるなら、概要把握のために読んでもいいと思う。