このページの目次
NFS (Network File System)
カバー範囲: NFSv3/v4 プロトコル → SUNRPC レイヤー → クライアント/サーバーアーキテクチャ → キャッシング (属性/デレゲーション) → pNFS → Kerberos セキュリティ → nfsd カーネルバージョン: 2.6 ~ 6.x
概要
NFS は Unix/Linux において最も伝統的なネットワークファイルシステムです。NFSv4 (2003年) は v3 に対する大幅な書き換えであり、ステート管理 (ロックとデレゲーション)、複合操作 (compound RPC)、擬似ファイルシステム (pseudo-fs)、およびより強力なセキュリティモデルを導入しました。
Linux の NFS 実装は、2つの独立したモジュールに分かれています。
- nfsd (サーバー,
fs/nfsd/): ローカルファイルシステムをネットワークにエクスポート - nfs (クライアント,
fs/nfs/): リモートファイルシステムをマウント
SUNRPC レイヤー
NFS はトランスポート層として SUNRPC (ONC RPC) を使用します。
// net/sunrpc/
// RPC クライアント: リクエストを送信し、応答を待機
;
// RPC トランスポート:
// TCP (デフォルト): 信頼性あり、組み込みフロー制御
// UDP: 軽量だがパケット損失のリスクあり (v3 のみ)
// RDMA: 高性能 (InfiniBand/RoCE)
NFS クライアント
マウントと擬似ファイルシステム
NFSv3 マウント:
mount -t nfs server:/export/path /mnt
→ MOUNT プロトコル (portmapper) を使用して初期 filehandle を取得
→ 以降の操作は NFS プロトコル (ポート 2049) を使用
NFSv4 マウント:
mount -t nfs4 server:/ /mnt
→ 擬似ファイルシステム: サーバー側でルートエクスポートを行い、クライアントはトラバーサルによってサブエクスポートに到達
→ 補助的な MOUNT プロトコルは不要
→ /etc/exports における fsid=0 はルートエクスポートを示す
属性キャッシュ
// NFS クライアントはファイル属性 (stat, 権限など) をキャッシュ
// キャッシュの有効期限は acregmin/acregmax/acdirmin/acdirmax で制御
// close-to-open 一貫性:
// これは NFS のデフォルトの一貫性モデルです:
// 1. open() → 属性の再検証を強制 (GETATTR)
// 2. 未開封のファイル: キャッシュ期間中は属性を再利用
// 3. close() → 変更をすべて書き戻し
// 4. 別のクライアントが同じファイルを open → 変更全体を確認可能
// NFSv4 デレゲーション (委譲):
// サーバーはファイルの読み書き権限を「委譲」できる
// クライアントが読み取り/書き取りを独占 → ローカルキャッシュの属性とデータ → RPC ゼロ!
// 別のクライアントがアクセスしようとする → サーバーはまずデレゲーションを取り消し (revoke) → 最初のクライアントがサーバーにフラッシュ
// 分散システムにおけるリース (lease) メカニズムに類似
Page Cache と書き戻し
NFS クライアントの page cache:
読み込み: page cache ヒット → RPC を発行せず → ローカルでサービス提供
書き込み: まず page cache に書き込み → 非同期 WRITE RPC → バックグラウンドで書き戻し
NFS COMMIT:
fsync → COMMIT RPC → サーバーが安定したストレージへの書き込みを保証
→ サーバーは NFS write delegation を使用して高速化する場合がある
NFSv4.1+ pNFS (Parallel NFS):
メタデータは MDS (Metadata Server) を経由
データは DS (Data Server) に直接アクセス
→ MDS の帯域幅ボトルネックを回避
NFS サーバー (nfsd)
// fs/nfsd/
// カーネル NFS サーバー: nfsd カーネルスレッドプール
// ファイルシステムのエクスポート:
// /etc/exports:
// /export *(rw,sync,no_subtree_check)
// exportfs -a → カーネルに通知
// nfsd スレッド:
// 各 CPU につき 1 つの nfsd カーネルスレッド
// nfsd のループ: RPC リクエストの取得 → NFS 操作の実行 → 応答の返却
// スレッド数: /proc/fs/nfsd/threads
// NFSv4 ステート:
// サーバーはクライアントのステート (オープン中のファイル、ロック、デレゲーション) を維持
// ステートストレージ: /var/lib/nfs/nfsdcltrack (または v4.2+ ではファイルシステムベース)
// クライアントがクラッシュ → lease 時間後にステートが自動的に回収
セキュリティモデル
NFSv3:
AUTH_SYS (UNIX クレデンシャル: uid/gid/補助グループ) に基づく
→ クライアントが提供する uid/gid を信頼 (不安全!)
→ root_squash による緩和 (root を nobody にマッピング)
→ sec=sys (デフォルト), sec=krb5 (オプション)
NFSv4:
Kerberos 5 (RPCSEC_GSS) をサポート
sec=krb5: 認証のみ
sec=krb5i: 認証 + 完全性 (改ざん防止、署名)
sec=krb5p: 認証 + 完全性 + 機密性 (データ暗号化)
必須要件: NFSv4.2 以降のサーバーは sec=krb5 をサポートする必要がある
TASK_KILLABLE と NFS
// NFS は TASK_KILLABLE が導入された主要な動機の一つ
// 古典的な問題: NFS がマウントされているがサーバーに到達できない
// → プロセスが NFS マウントポイントにアクセス → TASK_UNINTERRUPTIBLE (D 状態) に移行
// → SIGKILL が無効 (D 状態はシグナルに応答しない!)
// → 再起動するしかない
//
// TASK_KILLABLE による解決 (5.x 以降):
// 一部の待機パスでは wait_event_killable() を使用
// → 待機中に fatal_signal_pending() をチェック
// → SIGKILL で中断可能
// ただし、すべての NFS パスが KILLABLE に変更されたわけではない
デバッグ
# NFS クライアント統計
# NFS サーバー統計
# NFS マウントオプションの確認
|
|
# NFS RPC のトレース
参考資料と拡張
- カーネルドキュメント:
Documentation/filesystems/nfs/ - RFC: RFC 7530 (NFSv4), RFC 5661 (NFSv4.1/pNFS), RFC 7862 (NFSv4.2)
- ソースコード:
fs/nfs/— クライアント実装fs/nfsd/— サーバー実装net/sunrpc/— RPC レイヤーinclude/linux/sunrpc/— RPC 型定義
キーワード: NFSv4, SUNRPC, delegation, close-to-open, pNFS, nfsd, TASK_KILLABLE, Kerberos, RPCSEC_GSS