「Stale file handle」の対処 - NFSマウントの再接続
「Stale file handle」とは何が起きているのか?
結論: NFS クライアントが握っているファイルハンドルが、サーバ側の実体と一致しなくなった状態(
ESTALE)。パスではなくハンドルで識別する NFS 特有の現象で、サーバ側の変更が引き金になる。
NFS マウント上で ls や cat、ファイル保存が次のように弾かれる。
ls: cannot access '/mnt/nfs/data': Stale file handle
NFS はファイルをパスではなくファイルハンドルで識別する。ハンドルは大まかに次の 3 要素で構成される。
- fsid — エクスポートしているファイルシステムの識別子
- inode 番号 — 対象ファイル / ディレクトリの inode
- generation 番号 — inode が使い回されたときの世代判別
クライアントはマウント時やファイルアクセス時にこのハンドルをキャッシュし、以降の操作で再利用する。サーバ側でハンドルが指す実体が消える・変わると、次回アクセスでカーネルが ESTALE(Stale file handle)を返す。
ポイント: これはディスク障害ではなく「クライアントが古い参照を握り続けている」状態。多くはクライアント側の再マウントで復旧する。サーバを触る前に、まずクライアント側を疑う。
なぜ Stale file handle が発生するのか?
結論: サーバ側でファイルハンドルの指す実体が変わったときに起きる。「ファイルの削除・再作成」「エクスポート変更」「サーバ再起動での fsid 変化」「バックアップ復元による inode/generation 変化」が四大原因。
代表的な引き金を、現場での遭遇頻度順に挙げる。
- A. サーバ側でファイル / ディレクトリを削除・再作成(最頻出)— クライアントが開いている最中に、別経路でファイルが消されて作り直されると、inode / generation が変わりハンドルが失効する
- B. エクスポート設定の変更 —
/etc/exportsを編集してexportfs -rした、エクスポートパスやオプションを変えた、といった操作でハンドルの前提が崩れる - C. サーバ再起動で fsid が変化 —
/etc/exportsにfsid=を明示していないと、再起動時にサーバが自動採番する fsid が変わることがあり、既存ハンドルが無効になる - D. バックアップ / スナップショットからの復元 — 復元でファイルの inode や generation 番号が変わると、同じパスでもハンドルは別物になる
A と D は「パスは同じなのに中身(inode)が別物にすり替わった」ケース。ファイル名で見ると正常に見えるため原因究明が難しい。ESTALE が出たら「サーバ側で実体が入れ替わった可能性」をまず疑う。
まず状況を確認する
結論: どの NFS マウントで起きているか、どのプロセスがそのマウントを掴んでいるかを先に特定する。
findmntでマウント、lsof/fuserで利用プロセスを洗い出す。
1. どの NFS マウントか特定する
$ findmnt -t nfs,nfs4
TARGET SOURCE FSTYPE OPTIONS /mnt/nfs 192.168.10.5:/export nfs4 rw,relatime,vers=4.2,...
2. ESTALE を再現確認する
$ ls /mnt/nfs ls: reading directory '/mnt/nfs': Stale file handle
3. そのマウントを掴んでいるプロセスを洗い出す
再マウントには対象マウントを誰も使っていない状態が必要。掴んでいるプロセスを先に特定する。
$ lsof +D /mnt/nfs 2>/dev/null $ fuser -vm /mnt/nfs
自分のシェルがマウント配下に cd しているだけでも busy になる。まず cd / でマウント外に出てから再マウントを試す。これだけで umount が通ることも多い。
どう復旧するのか?(クライアント側)
結論: 基本は「アンマウント → 再マウント」でハンドルを取り直す。busy で失敗する場合は遅延アンマウント(
umount -l)、それでも駄目なら強制(umount -f)を段階的に試す。
手順 1: 通常のアンマウント+再マウント
$ cd / $ sudo umount /mnt/nfs $ sudo mount /mnt/nfs
/etc/fstab にエントリがあれば mount /mnt/nfs だけで再マウントできる。これで多くのケースは解決する。
手順 2: busy で失敗する場合は遅延アンマウント
target is busy で umount が失敗するときは、参照中のプロセスを止められないか確認したうえで遅延アンマウントを使う。
$ sudo umount -l /mnt/nfs # lazy: 参照が切れ次第デタッチ $ sudo mount /mnt/nfs
-l(lazy)はマウントポイントを名前空間から即座に切り離し、実際の解放は最後の参照が消えたタイミングで行う。busy 環境でも再マウントへ進める。
手順 3: サーバ応答が無く固まる場合は強制アンマウント
サーバがダウン・到達不能で I/O がハングしている場合は force を使う。
$ sudo umount -f /mnt/nfs
umount -f は未書き込みデータを失う可能性がある。書き込み中のアプリがある場合は、可能な限り先にそれを停止する。force / lazy は最終手段として段階的に使うこと。
手順 4: 個別ファイルだけ ESTALE の場合
マウント全体ではなく特定のファイル / ディレクトリだけが Stale なら、そのディレクトリから出て入り直すだけで解消することがある。
$ cd / $ cd /mnt/nfs/data # ハンドルを取り直す
それでも残る場合は手順 1〜3 の再マウントに進む。
サーバ側で確認すべきこと
結論: クライアント再マウントで直らない、または全クライアントで多発するならサーバ側を疑う。エクスポート状態と fsid の整合性を確認する。
エクスポート状態を確認する
$ sudo exportfs -v
エクスポートパス・オプションが意図通りか確認する。/etc/exports を変更した直後なら、反映漏れがないか exportfs -ra で再エクスポートする。
$ sudo exportfs -ra
fsid の固定を確認する
サーバ再起動のたびに Stale が出るなら、fsid の自動採番が変動している可能性が高い。/etc/exports で明示固定する。
# /etc/exports(サーバ側) /export 192.168.10.0/24(rw,sync,fsid=0,no_subtree_check)
fsid=0 は NFSv4 の擬似ルート用。複数エクスポートには一意な数値(fsid=1, fsid=2, ...)または UUID を割り当てる。変更後は exportfs -ra で反映する。
再発を防ぐには?
結論: サーバ側で
fsidを明示固定し、クライアントが使用中のファイルをサーバ直接操作で削除・再作成しない運用にするのが基本。マウントオプションでハングを緩和することもできる。
fsid=を明示固定する — 再起動で fsid が変わる事故を防ぐ最も効果的な対策- 使用中ファイルをサーバ側で直接いじらない — 削除・置換はクライアント経由か、クライアントが参照していないタイミングで行う
- エクスポート変更はメンテ枠で —
/etc/exports変更や再エクスポートはクライアントの再マウントとセットで計画する soft/hardの選択を理解する —hard(既定)はサーバ復帰まで再試行し続けるためデータ整合性に有利だが、障害時にハングしやすい。softはタイムアウトで諦めるためハングしにくいが書き込みデータを失うリスクがある。用途で選ぶ
コピペ用:クライアント側の復旧テンプレ
# 1. マウント外へ出る cd / # 2. どのマウントで起きているか・誰が掴んでいるか findmnt -t nfs,nfs4 fuser -vm /mnt/nfs # 3. 再マウント(busy なら -l、ハングなら -f) sudo umount /mnt/nfs || sudo umount -l /mnt/nfs sudo mount /mnt/nfs
まとめ
- Stale file handle (
ESTALE) は NFS クライアントが古いファイルハンドルを握り続けている状態で、ディスク障害ではない - 原因はサーバ側の実体変化(削除・再作成 / エクスポート変更 / fsid 変化 / 復元)
- 復旧の基本はクライアント側の再マウント。busy なら
umount -l、ハングならumount -fを段階的に - 全クライアントで多発・再起動のたびに発生するならサーバ側の
fsid固定を確認する