このページの目次
VFS — 仮想ファイルシステム層
カバー範囲: VFS オブジェクトモデル (super_block/inode/dentry/file) → システムコールパス (open/read/write/close) → file_operations → RCUパスウォーク → マウントメカニズム カーネルバージョン: 2.6 ~ 6.x
概要
VFS (Virtual File System / Virtual Filesystem Switch) は、Linuxにおける「すべてはファイルである」という理念の基盤です。VFSは抽象化されたオブジェクトと操作インターフェースのセットを定義しており、ext4、NFS、procfsなど全く異なるファイルシステムをユーザー空間に対して一貫して公開することを可能にします。read() システムコールを実行する際、それがローカルディスク上にあるのかネットワークマウントされているのかを意識する必要はありません。VFS層が正しいファイルシステム実装へとルーティングを行います。
VFSの核心的な設計哲学はオブジェクト指向のC言語実装です。各VFSオブジェクト内部には *_operations 関数テーブルが埋め込まれており、ファイルシステムはこの関数テーブルを埋めることで「インターフェースを実装」します。
VFSの4大オブジェクト
super_block: 「このファイルシステムは何なのか?」 — マウントポイントごとに1つのsuper_blockが存在
inode: 「このファイルは何か?」 — ファイル/ディレクトリごとに1つ(ディスクまたはメモリ上に存在)
dentry: 「このパス名は誰を指しているのか?」 — パス名からinodeへのキャッシュマッピング
file: 「この開かれたファイルはどこにあるのか?」 — open() ごとに1つ作成され、現在のオフセットを含む
super_block
// include/linux/fs.h
;
inode
;
dentry — パス名キャッシュ
;
ネガティブdentry: d_inode == NULL。これは「このパス名は存在しないことが確認済み」であることを意味します。見つからないファイルを検索した際などに生成されます。open("/tmp/noexist") のたびに再探索を行わなければならなければ、膨大なIOの無駄になります。
file — 開かれたファイルの記述
;
システムコールパス
open(): パス名からfileへ
flowchart TD
SYSCALL["open() システムコール"] --> GETNAME["getname()<br/>ユーザー空間からパス名をコピー"]
GETNAME --> GETFD["get_unused_fd_flags()<br/>fd番号を割り当て"]
GETFD --> DO_OPEN["do_filp_open()<br/>核心的なパス解析"]
DO_OPEN --> PATH["path_openat()"]
PATH --> WALK["link_path_walk()<br/>パスをコンポーネントごとに走査"]
WALK --> LOOKUP{"lookup_fast()<br/>dcacheを参照 (RCU walk)"}
LOOKUP -->|"ヒット"| DENTRY["dentryを返す<br/>ロックなし、極めて高速 ✅"]
LOOKUP -->|"ミス"| SLOW["lookup_slow()<br/>i_op->lookup()を呼び出し<br/>ディスク/inodeブロックから探索<br/>新しいdentryを割り当て → dcacheに追加"]
DENTRY --> LAST{"最終コンポーネントか?"}
SLOW --> LAST
LAST -->|"はい"| DO_LAST["do_last()"]
LAST -->|"いいえ、次のコンポーネントへ"| LOOKUP
DO_LAST --> CASE{"ファイルの状態は?"}
CASE -->|"既に存在"| VFS_OPEN["vfs_open()<br/>→ f_op->open()"]
CASE -->|"O_CREAT"| VFS_CREATE["vfs_create()<br/>→ i_op->create()"]
CASE -->|"O_TMPFILE"| TMPFILE["無名一時ファイルを作成"]
VFS_OPEN --> INSTALL["fd_install()<br/>fileをfdtableにインストール"]
VFS_CREATE --> INSTALL
TMPFILE --> INSTALL
INSTALL --> RET["fdを返す ✅"]
classDef sys call fill:#e3f2fd,stroke:#1565c0
classDef step fill:#f3e5f5,stroke:#7b1fa2
classDef decision fill:#fff3e0,stroke:#ef6c00
classDef done fill:#e8f5e9,stroke:#2e7d32
class SYSCALL syscall
class GETNAME,GETFD,DO_OPEN,PATH,WALK,DENTRY,SLOW,VFS_OPEN,VFS_CREATE,TMPFILE,INSTALL step
class LOOKUP,LAST,CASE decision
class RET done
RCU Path Walk — VFSのパフォーマンスの秘密
従来のパス解析 (2.6 より前):
各コンポーネントごとにロックを取得 → 競合が高くなる → マルチコアでのパフォーマンスが劣る
RCU path walk (2.6.38以降):
1. RCU読取りロックの下でdcacheを走査
2. dentryとinodeの読み取りのみが必要(書き込みは不要)
3. すべてのコンポーネントがdcache内にある場合 → 全体でロック不要
4. dcacheにないコンポーネントに出会った場合 → ref-walk(ロック付き)にフォールバック
パフォーマンス: マルチコアシステムにおいてopen()のスループットが数倍向上
実装: fs/namei.c の link_path_walk() 内に2つのロジック(RCU/REF)が存在
read(): page cacheからの読み込み
// fs/read_write.c
→ →
├─
├─ f_op-> または f_op-> を呼び出し
│ └─ 通常ファイルの場合:
│ └─
│ ├─ 各ページアラインされた範囲に対して:
│ │ ├─ →
│ │ │ ├─ page cacheヒット →
│ │ │ └─ page cacheミス →
│ │ │ └─ ブロック層から読み込み → ページをpage cacheに挿入
│ │ └─ →
│ └─ f_pos を更新
└─ 読み込んだバイト数を返す
write(): page cacheへの書き込み + バックグラウンド書き戻し
└─ f_op-> →
└─
├─
│ ├─ 各ページアラインされた範囲に対して:
│ │ ├─ → page cacheページを検索または作成
│ │ ├─ →
│ │ └─
│ └─ f_pos を更新
│
└─ 書き戻しはいつ行われるか?
ここではありません! generic_file_write_iter は単にpage cacheに書き込むだけです
実際のwritebackはバックグラウンドのflusherスレッドによって非同期で行われます
file_operations
// include/linux/fs.h
;
ファイルシステムは一部のみを埋め込むことも可能です。VFSがデフォルトの実装で補完します。例えば read_iter はなく read がある場合、VFSが自動的にラップします。
マウントメカニズム
// fs/namespace.c
// mount は、ファイルシステムをVFSツリー上の一点に付着させます:
;
// mount /dev/sda1 /mnt の場合:
// 1. /dev/sda1 のスーパーブロックを読み取り → super_block を作成
// 2. vfsmount を作成 → mnt_root = super_block->s_root
// 3. /mnt にマウント → /mnt のdentry がマウントポイントとなる
// 4. パス走査中にマウントポイントに到達 → vfsmount->mnt_root に切り替えて継続
// namespace:
// 各プロセスはマウントネームスペースに属する
// CLONE_NEWNS → 新しいマウントネームスペース(コンテナの基盤)
デバッグ
# VFS統計
# nr_dentry, nr_unused, age_limit
# 現在のマウント
# ファイルシステムタイプ
# open/read/write のトレース
参考と拡張
- カーネルドキュメント:
Documentation/filesystems/vfs.rst,Documentation/filesystems/path-lookup.rst - LWN:
- "Pathname lookup in Linux" (lwn.net/Articles/649115/)
- "RCU-walk: faster pathname lookup" (lwn.net/Articles/649294/)
- ソースコードファイル:
fs/namei.c— パスウォーク、open()fs/open.c— do_sys_open()fs/read_write.c— vfs_read/vfs_writeinclude/linux/fs.h— super_block, inode, dentry, file, file_operationsfs/namespace.c— マウントメカニズムfs/dcache.c— dentryキャッシュ
キーワード: VFS, super_block, inode, dentry, file, file_operations, RCU path walk, dcache, negative dentry, mount namespace