このページの目次
VFS 応用
カバー範囲: page cache と VFS の相互作用 → inode 状態マシン → ファイルロック (POSIX/OFD) → fsync/fdatasync の保証 → sendfile/splice/vmsplice によるゼロコピー カーネルバージョン: 2.6 ~ 6.x
Page Cache と VFS の相互作用
inode と address_space の関係
// inode->i_mapping は、そのファイルの page cache を指す
// これは address_space 構造体であり、メモリ内のそのファイルの全キャッシュページを管理する
// ほとんどの場合、inode->i_mapping は内蔵の inode->i_data を指す:
;
// ブロックデバイスの裸の読み書きの場合:
;
inode 状態マシン
// include/linux/fs.h
// inode のライフサイクル:
// alloc_inode() → I_NEW
// insert_inode_locked() → inode ハッシュに追加
// unlock_new_inode() → I_NEW をクリアし、待機中のプロセスをウェイクアップ
// ... アクティブ期間 ...
// iput() → i_count == 0 → evict() → I_FREEING → destroy_inode()
ファイルロック
POSIX ロック (fcntl)
// POSIX 勧告的/強制ロック
;
; // 非ブロッキング
; // ブロッキング待機
; // 照会
// 実装: fs/locks.c
// ロックは inode->i_flctx (file_lock_context) にアタッチされる
// 競合検出: posix_locks_conflict() → conflict チェーンを走査
// プロセスが fd をクローズすると、フォーク関係に関係なく、すべての POSIX ロックが自動的に解放される
OFD ロック (Open File Description, 3.15 以降)
// POSIX ロックの問題点: 同一プロセス内の異なる fd は、それぞれロックを保持できない
// OFD ロックの解決策: ロックは「プロセス」ではなく「オープンファイル記述子 (file)」にアタッチされる
;
// fork シナリオ:
// POSIX: 子プロセスは親プロセスのロックを継承する (同一 PID であるため)
// OFD: 子プロセスはロックを継承しない (異なる file であるため、必ずしも継承されない)
FLOCK (BSD ロック)
; // 共有ロック
; // 排他ロック
; // ロック解除
// POSIX ロックとの違い:
// FLOCK は file にアタッチされる (inode でもプロセスでもない)
// 同一 file に対する複数の flock 呼び出しは自動的に結合される
// fork 時に flock が継承される (file が共有されるため)
// 勧告的ロックのみ (強制ロックは存在しない)
fsync / fdatasync: 永続性の保証
// fs/sync.c
→ →
├─ // 1. ダーティな page cache の書き戻し
│ └─ →
│ → 各ダーティな folio に対して a_ops-> を呼び出し
│ └─ // 書き戻しの完了を待機
│
└─
└─ f_op-> // 2. ファイルシステム: ジャナルの書き込み / 強制フラッシュ
→ ext4: jbd2 トランザクションのコミット + blkdev_issue_flush
→ XFS: 強制ログのディスクへの書き出し + flush
→ NFS: COMMIT 操作
// fdatasync (FDATASYNC): データ部分のみをフラッシュ (i_atime/i_mtime は対象外)
// → vfs_fsync_range(file, start, end, 1)
// → ファイルシステムはタイムスタンプの同期をスキップできる
ゼロコピー: sendfile / splice / vmsplice
// sendfile(): ファイルからソケットへ、ユーザー空間を経由しない
→
└─ → パイプバッファ ← ファイル内容
└─ → パイプバッファ → ソケット
// splice(): 2つの fd の間でパイプ経由の転送 (カーネル空間内)
; // fd → パイプ
; // パイプ → fd
// vmsplice(): ユーザー空間メモリからパイプへ (splice と組み合わせて使用)
;
// ユーザーメモリのページが「カーネルに譲渡」される (もはやユーザー空間のものではない)
// → パイプがこれらのページを参照 → splice でソケットへ転送 → ゼロコピーで NIC へ送信
DMA ゼロコピーの経路
デバッグ
# inode キャッシュの統計
# プロセスのファイルロックの表示
# fsync の動作を追跡
参考と拡張
- カーネルドキュメント:
Documentation/filesystems/locks.rst,Documentation/filesystems/vfs.rst - LWN:
- "Better file locking with OFD locks" (lwn.net/Articles/586904/)
- "Splice and sendfile" (lwn.net/Articles/178199/)
- ソースファイル:
fs/locks.c— POSIX/OFD/FLOCK の実装fs/sync.c— fsync/fdatasyncfs/splice.c— splice/sendfile/vmsplicefs/inode.c— inode のライフサイクル
キーワード: VFS, inode state, POSIX lock, OFD lock, FLOCK, fsync, fdatasync, sendfile, splice, zero-copy