コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
ファイルシステムとは
ディスクは memo.txt という名前を知らない
SSD も HDD も、装置としてできることは「何番目のブロックを読め」「何番目のブロックに書け」の 2 つだけです。4KB のブロックが 0 番から順に並んだ、ひたすら長い配列だと思ってください。名前という概念はどこにもありません。
一方こちらは cat /home/alice/memo.txt と打ちます。この文字列を、何番のブロックを読めばよいかという数字へ変換する。それがファイルシステムの仕事です。
対応表も、同じディスクの中に置くしかない
名前と番号の対応表を RAM だけに持つと、電源を切った瞬間に消えます。翌朝には中身が読み出せなくなるので、対応表もディスクへ書かなければなりません。ファイルシステムは、ブロックの一部を中身の保管に使い、残りを「どこに何があるか」の管理に使う、という配分をしています。
管理側に置かれるのは、おおよそ次のものです。
- ファイルごとの管理情報。大きさ、更新日時、所有者、そして中身がどのブロックに入っているかの一覧
- 名前と管理情報を結びつける表。これがディレクトリの正体
- どのブロックが空いているかの一覧
- ディスク全体の素性を記した先頭の情報
ls -l がサイズと日時を一瞬で返せるのは、中身を 1 バイトも読んでいないからです。管理情報だけを読んでいます。
1 ファイル開くのに、何度も引き直している
/home/alice/memo.txt を開く流れは、スラッシュで区切られた分だけの繰り返しになります。
- 一番上の
/の管理情報を読み、続けて/の中身のブロックを読む - その中の名前一覧から
homeを見つけ、homeの管理情報を読む - 同じことを
aliceについて繰り返す aliceの中身からmemo.txtを見つけ、その管理情報を読む- ようやく、中身が入っているブロック番号が分かる
階層が深いほど往復が増えます。それでも実用になっているのは、OS が一度読んだブロックを RAM へ取っておくためです。この控えをページキャッシュと呼びます。同じディレクトリで 2 回目の ls が速いのも、深いパスを何度叩いても速度が落ちないのも、往復のほとんどが RAM で済んでいるからです。
表の作り方は 1 つではない
名前から場所を引く、というやり方に唯一の正解はありません。想定するディスクの性質や、求める安全性に合わせて、いくつもの実装があります。
Linux はそこに VFS という共通の窓口を置きました。open や read の呼び方は、下にどの実装が居ても同じです。だから USB メモリでも、ネットワーク越しの領域でも、同じ cat がそのまま使えます。
窓口が共通なので、別々のディスクを 1 本のツリーへ束ねることもできます。あるディレクトリを入口として別のディスクを貼り付ける操作が mount で、/home だけ別のディスク、/proc はディスクを持たないカーネル製の作り物、といった構成が普通に成り立ちます。
ターミナル
df -Tプレーンテキスト
Filesystem Type 1K-blocks Used Available Use% Mounted on
/dev/nvme0n1p2 ext4 478920000 210344000 244300000 47% /
/dev/nvme0n1p1 vfat 1046508 12200 1034308 2% /boot/efi
tmpfs tmpfs 8134560 1240 8133320 1% /runType の列が、その入口から下で使われている実装です。1 本に見えるツリーが、実は何種類もの実装の寄せ集めであることが分かります。