要約

  • NFSはパス名でファイルを探し、後続操作にはサーバー発行の不透明なファイルハンドルを使う。クライアントは値を保存して返せるが、inode、記憶位置、サーバーをまたぐ識別子として解釈してはならない。
  • NFSv4は永続ハンドルと揮発ハンドルを区別した。永続ハンドルは対象の存続中、再起動や移行を越えて固定される。揮発ハンドルは、サーバーが開示する条件で期限切れになり得る。
  • NFS4ERR_STALEは対象の消滅または利用不能を、NFS4ERR_FHEXPIREDは対象が残っている可能性を含む一時参照の連続性喪失を表す。復旧は古い値の解読ではなく、ルートから名前を引き直す作業になる。

改名されたファイルを何で追うのか

クライアントがあるファイルを開いた後、別の利用者がその名前を変える。あるいは、一つのファイルに二つのハードリンクがある。このときパスは一つの対象の固定的な身分証ではない。現在の名前空間をどう歩くかを表す案内である。

NFSv2を定めた1989年のRFC 1094は、すでに案内と参照を分けていた。クライアントは別のMOUNTプロトコルから最初のルートハンドルを受け取り、ディレクトリのハンドルと一つの名前をLOOKUPへ渡す。返されたハンドルを次の探索やGETATTR、READ、WRITEに使った。

当時のハンドルは32バイト固定で、「opaque」とされた。不透明とは、暗号化や秘密性の保証ではない。クライアントが値の内部を契約として読めないという意味だ。サーバーが装置番号、inode、表の位置などを材料にしても、それはクライアントが依存できるNFS形式にはならない。

RFC 1813のNFSv3では、nfs_fh3は可変長になった。LOOKUPだけでなくCREATE、LINK、READDIRPLUSなどもハンドルを返す。サーバーは個々のファイルを区別するために必要な情報を入れられる。一方、クライアントが得るのは再提示できる参照であって、サーバー内部の設計図ではない。

同じなら同じ、違っても別とは限らない

不透明な値にも比較規則はある。同じサーバーから得た二つのハンドルが等しければ、同じファイルを指す。しかし異なるハンドルが別ファイルを指すとは限らない。オブジェクトとバイト列を一対一に対応させる義務はサーバーにない。

RFC 1813は、比較を性能上の最適化と位置づけ、正しさの根拠にしてはならないとする。NFSv4も同じ考えを保った。ハードリンクでつながった二つの名前は同じハンドルを返すのが望ましいが、不一致だけでクライアント独自のオブジェクト境界を作ることはできない。

この限定は、キャッシュの役割を整える。同じ値なら重複作業を避けられる。違う値を見たときに、二つの操作が絶対に同じ対象へ届かないと断定する権限まではない。まして異なるサーバーの値を世界共通のハッシュのように扱えない。

永続性は無限寿命ではない

NFSv4のRFC 3010は、ファイルハンドルを永続と揮発に分けた。RFC 7530とRFC 8881にも、この区別が引き継がれている。

永続ハンドルは、対象が存続する間は固定される。サーバーが再起動しても無効にならず、オブジェクトが移行しても参照の連続性を守る。ストレージの置き場所が変わっても、クライアントに内部配置を知らせる必要はない。

ただし「永続」は「不死」ではない。対象が削除された場合や、そのファイルシステムが利用できなくなった場合、サーバーはNFS4ERR_STALEを返す。古い内部位置が再利用されても、旧ハンドルを新しい対象へ黙って結び直さないことが重要である。

すべての環境が同じ保証を実現できるわけではない。階層型ストレージ、移行機構、OSの制約、再起動で失われる表などでは、参照の寿命が条件付きになる。NFSv4は揮発ハンドルを認め、fh_expire_typeによって失効条件をサーバーに示させる。

仕様には、起動時刻、表のスロット、世代番号を組み合わせる例がある。スロットが再利用されれば旧世代を拒否できる。しかし、これは実装例であって必須の符号化ではない。共通化されるのは、内部形式ではなく外から確認できる失効の振る舞いである。

STALEとFHEXPIREDが語る範囲

NFS4ERR_STALEは、期待した対象へ古い参照が届かないことを表す。オブジェクトが削除された、または永続参照の属するファイルシステムが利用不能になった、といった場合である。

NFS4ERR_FHEXPIREDは、揮発ハンドルそのものの連続性が終わったことを示す。再起動で対応表が消えた、世代が変わった、保証範囲を越えて移行した、といった事情があり得る。それでもファイルは残っているかもしれない。

この違いを消すと、上位層は事実以上のことを言わされる。期限切れを削除と同一視すれば、参照を失っただけなのにデータ消失と報告する。すべてを一時障害として再試行すれば、削除済み対象を永遠に探す。二つのエラーは不確実性をなくすのではなく、どこまで分かっているかを正確に伝える。

ルートから引き直しても、過去には戻れない

NFSv4では特殊なルートハンドルが用意され、PUTROOTFHで出発点を選び、LOOKUPで名前を順にたどれる。クライアントが構成要素を記録していれば、揮発ハンドルの期限切れ後に、新しいハンドルを取得する復旧が可能だ。

しかし、それは新しい観測である。他の利用者が改名や削除を行ったかもしれない。古い名前の場所に別のファイルが作られたかもしれない。同じパスをたどっても、元の対象、置換された対象、または何もないという三つの結果がある。

したがって属性、ロック、キャッシュ、保留中の操作を再検証しなければならない。特に変更操作は、名前を再解決できたというだけで再送が安全になるわけではない。アクセス権も別問題である。有効なハンドルを持つことは、読み書きの許可を意味しない。サーバーが各操作を認可する。

NFSの歴史が示したのは、万能識別子の作り方ではない。サーバーは内部対応を管理し、その連続性を宣言する。標準は不透明性、限定された等値、寿命の種類、明示的な失敗という最小限の共通ルールを置く。クライアントは名前の証拠を残し、証明できなくなった連続性を勝手に補わない。

パスが変わっても対象は残り得る。対象が残ってもハンドルは期限切れになり得る。ハンドルが有効でも操作は拒否され得る。この三つを混ぜないことが相互運用性を支えた。

出典