RFC5663 pNFS block/volume layout の訳

以下は、 RFC5663 の kanda.motohiro@gmail.com による抄訳です。手っ取り早く日本語で pNFS を理解するのが目的なので、はしょった訳になっています。ことわりなく原文の部分を省略しているところがあります。http://trustee.ietf.org/license-info/ に派生物のライセンスの規定があるのかよくわかりません。なければ、Creative Commons Attribution-Share Alike, Version 3.0 で提供します。他の nfsv4 RFC 訳は、ここを参照。

Internet Engineering Task Force (IETF) D. Black

Request for Comments: 5663 S. Fridella

Category: Standards Track EMC Corporation

ISSN: 2070-1721 J. Glasgow

Google

January 2010

パラレル NFS (pNFS) ブロック/ボリュームレイアウト

概要

パラレル NFS (pNFS) は、 Network File System バージョン4 (NFSv4) を拡張し、クライアントが、NFSv4 サーバーが使うストレージ上のデータを直接アクセスできるようにしたものです。データアクセスのためにサーバーをバイパスできることは、性能と並列度の両方を高めることができますが、クライアント側に、データアクセスのための追加の機能を必要とします。それは、使うストレージの種類に依存します。主となる pNFS の文書は、ストレージの種類に依存しない NFS 拡張を記述しました。この文書は、pNFS をブロックおよびボリュームをベースとするストレージで使うための追加の拡張(主にデータ構造)を記述します。

Status of This Memo

This is an Internet Standards Track document.

This document is a product of the Internet Engineering Task Force

(IETF). It represents the consensus of the IETF community. It has

received public review and has been approved for publication by the

Internet Engineering Steering Group (IESG). Further information on

Internet Standards is available in Section 2 of RFC 5741.

Information about the current status of this document, any errata,

and how to provide feedback on it may be obtained at

http://www.rfc-editor.org/info/rfc5663.

Copyright Notice

Copyright (c) 2010 IETF Trust and the persons identified as the

document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal

Provisions Relating to IETF Documents

(http://trustee.ietf.org/license-info) in effect on the date of

publication of this document. Please review these documents

carefully, as they describe your rights and restrictions with respect

to this document. Code Components extracted from this document must

include Simplified BSD License text as described in Section 4.e of

the Trust Legal Provisions and are provided without warranty as

described in the Simplified BSD License.

1.3 コードコンポーネントライセンス上の注意

この文書中の XDR と、それを抽出するスクリプトは、Section 4 of "Legal Provisions Relating to IETF Documents" [LEGAL] が定めるところの Code Component であり、Section 4 of "Legal Provisions Relating to IETF Documents" の条件に従ってライセンスされます。

1.4 XDR 記述(大意)

#!/bin/sh

grep '^ *///' $* | sed 's?^ */// ??' | sed 's?^ *///$??'

この文書を、上記スクリプトに与えると、コンパイル可能な XDR 記述が得られます。

2 ブロックレイアウト記述

2.1 背景とアーキテクチャ

ブロック/ボリュームストレージでサポートされる基本的なストレージの抽象化は、固定長ブロックのシーケンシャルな連続からなるストレージボリュームです。これを、論理ディスクと考えてもよろしい。ストレージシステムはこれを、物理ディスク、その一部、あるいはもっと複雑なもの(例えば、連結、ストライピング、RAID、それらの複合)として実体化します。

ブロック/ボリュームストレージ種別での pNFS レイアウトは、NFS ファイル(あるいはその一部)を、そのファイルのあるストレージボリュームのブロックにマップします。ブロックは、64ビットのオフセットと長さを持つエクステントとして表され、既存の NFSv4 offset4 and length4 タイプが使われます。クライアントが、あるブロックエクステントに、ストレージの他の部分に影響を与えることなく I/O できることは重要(特に、ライトの時)なので、エクステントは512バイト境界になくてはいけません。さらに、書き込み可能なエクステントは、NFSv4 サーバーが実際のファイルシステムを扱う時に使うブロック長(4KB, 8KB が一般的でしょう)の境界になくてはいけません。このブロック長は、NFSv4.1 layout_blksize [NFSv4.1] として見えます。読み込み可能なエクステントは、前記ブロック長の境界にあるべきですが、フラグメントを持つレガシーなファイルシステムをサポートするために512バイト境界も許容されます。

レイアウトを得るための pNFS 操作 (LAYOUTGET) は、"layoutiomode4 loga_iomode" 引数があります。これは、要求するレイアウトがリードオンリーか、読み書き可能かを指定します。リードオンリーなレイアウトは、ホールを含み、読むとゼロが返ることがあります。読み書き可能なレイアウトは、ホールを含み、そこは記憶域が確保されていますが、初期化されていないことがあります。(クライアントからは、ゼロが読め、書き込み可能です。)この文書では、さらに、コピーオンライト(例えば、ファイルシステムのスナップショットのため)を実装するクライアントも扱います。これは、1つのレイアウトの同じ範囲に対して、リードオンリーの記憶域と初期化されていない記憶域を提供することで行われます。リードは最初、リードオンリーの記憶域に対して行われます。ライトは、初期化されていない記憶域に行われます。そこを初期化した最初のライト以降は、総てのリードは、初期化が終わった書き込み可能な記憶域に対して行われます。対応するリードオンリーの記憶域はもはや使われません。

ブロック/ボリュームレイアウトのソリューションは、 pNFS クライアントのセキュリティ上の責任を増加させます。環境によっては、 NFS に要求されるセキュリティ要件が満たされないことがあります。以下に、クライアントに追加で必要となるセキュリティ上の責任を述べます。完全な議論は、Section 3, 「セキュリティ上の考察」を参照下さい。

o 典型的な場合、ストレージエリアネットワーク (SAN) ディスクアレイと、 SAN プロトコルは、アクセス制御プロトコルを提供します。(例えば、論理ユニット番号 (LUN)マッピングとマスキング)これは、個々のホストの粒度で動作します。個々のブロックではありません。このため、クライアントソフトウエアが、ブロックベースの保護を提供する必要があります。

o 同じように、SAN ディスクアレイと SAN プロトコルは、ファイル領域にかかっている NFS ロックをチェックできません。例えば、あるファイルにマンダトリーのリードオンリーロックがかかっていた場合、サーバーは、 pNFS クライアントに対してリードオンリーのレイアウトだけを許可するようにすることができます。しかし、そのレイアウトでリードだけを行い、ライトをしないのは、それぞれの pNFS クライアントに任されています。

ブロック/ボリュームストレージシステムは、一般的に、そのようなファイルベースのセキュリティを強制できないため、 pNFS クライアントがそのようなポリシーに準拠することが信用できない環境では、 pNFS ブロック/ボリュームストレージレイアウトは使うべきではありません。

2.2 GETDEVICELIST and GETDEVICEINFO

2.2.1 ボリューム識別子

ストレージアレイのようなストレージシステムは、複数の物理ネットワークポートを持ち、それらは共通のネットワークにつながっていないことがあります。この結果、 pNFS クライアントは、同じストレージボリュームに対して、異なるネットワークの異なるポートから、同時にマルチパスのアクセスをすることがあります。

それらネットワークは同じ技術を使っていないかもしれません。例えば、同じボリュームを iSCSI とファイバーチャネル経由でアクセスするのもありえます。これにより、ボリューム識別子としてネットワークアドレスを使うのはダメです。なので、この pNFS ブロックレイアウトでは、ボリュームを識別するのにその内容を使います。例えば、ボリュームマネージャが使うラベル(の一意な部分)を比較する、などです。ボリュームの識別は、格納されたデータの特定の部分を、不透明なバイト列と比較することで行います。複数の部分が使われることもあります。このレイアウトをサポートするすべてのブロック pNFS システムは、以下に示すデータ構造を使って実行することができる、内容による一意なボリューム識別方法をサポートしなくてはいけません。

/// struct pnfs_block_sig_component4 { /* disk signature component */

/// int64_t bsc_sig_offset; /* byte offset of component

/// on volume*/

/// opaque bsc_contents<>; /* contents of this component

/// of the signature */

/// };

///

"pnfs_block_sig_component4" 構造の "bsc_contents" フィールドは、ゼロ終了する文字列として解釈されてはいけません。途中にゼロ値のバイトがあるかもしれません。境界の制限はありません。(bsc_sig_offset も、長さも、4の倍数でなくてもよろしい。)bsc_sig_offset は符号付き数であり、正ならばボリュームの開始からのバイトオフセットを、負ならば、ボリュームの終端からのバイトオフセットを示します。

負のオフセットは、デバイスラベルがボリューム終端から固定オフセットにあるシステムの場合の、クライアント実装を簡単にするために許されました。サーバーがシグネチャーを記述するために負のオフセットを使うときは、クライアントとサーバーが異なるボリューム長を見ることはあってはいけません。動的にボリューム長を変えることのできるシステムでは、クライアントにとって常に、ボリューム終端から指定オフセットのところにデバイスラベルが見えることを保証できるのでない限り、負のオフセットを使うべきではありません。

シグネチャーは、"PNFS_BLOCK_MAX_SIG_COMP" (以下に定義します)以下のシグネチャーコンポーネントの配列です。クライアントは、すべてのシグネチャーコンポーネントがブロックデバイスの単一セクターに存在すると仮定してはいけません。

pNFS クライアントのブロックレイアウトドライバーは、このボリューム識別子を使って、 pnfs_block_volume_type4 PNFS_BLOCK_VOLUME_SIMPLE deviceid4s を、自分から見える LUN にマップします。

2.2.2 ボリュームトポロジー

pNFS ブロックサーバーのボリュームトポロジーは、以下のデータ構造で示すベースボリュームタイプの任意の組み合わせです。トポロジーの個々のコンポーネントは配列に含まれ、コンポーネントは配列のインデックスを使って、他のコンポーネントを参照します。

/// enum pnfs_block_volume_type4 {

/// PNFS_BLOCK_VOLUME_SIMPLE = 0, /* volume maps to a single

/// LU */

/// PNFS_BLOCK_VOLUME_SLICE = 1, /* volume is a slice of

/// another volume */

/// PNFS_BLOCK_VOLUME_CONCAT = 2, /* volume is a

/// concatenation of

/// multiple volumes */

/// PNFS_BLOCK_VOLUME_STRIPE = 3 /* volume is striped across

/// multiple volumes */

/// };

///

/// const PNFS_BLOCK_MAX_SIG_COMP = 16;/* maximum components per

/// signature */

/// struct pnfs_block_simple_volume_info4 {

/// pnfs_block_sig_component4 bsv_ds<PNFS_BLOCK_MAX_SIG_COMP>;

/// /* disk signature */

/// };

///

///

/// struct pnfs_block_slice_volume_info4 {

/// offset4 bsv_start; /* offset of the start of the

/// slice in bytes */

/// length4 bsv_length; /* length of slice in bytes */

/// uint32_t bsv_volume; /* array index of sliced

/// volume */

/// };

///

/// struct pnfs_block_concat_volume_info4 {

/// uint32_t bcv_volumes<>; /* array indices of volumes

/// which are concatenated */

/// };

///

/// struct pnfs_block_stripe_volume_info4 {

/// length4 bsv_stripe_unit; /* size of stripe in bytes */

/// uint32_t bsv_volumes<>; /* array indices of volumes

/// which are striped across --

/// MUST be same size */

/// };

///

/// union pnfs_block_volume4 switch (pnfs_block_volume_type4 type) {

/// case PNFS_BLOCK_VOLUME_SIMPLE:

/// pnfs_block_simple_volume_info4 bv_simple_info;

/// case PNFS_BLOCK_VOLUME_SLICE:

/// pnfs_block_slice_volume_info4 bv_slice_info;

/// case PNFS_BLOCK_VOLUME_CONCAT:

/// pnfs_block_concat_volume_info4 bv_concat_info;

/// case PNFS_BLOCK_VOLUME_STRIPE:

/// pnfs_block_stripe_volume_info4 bv_stripe_info;

/// };

///

/// /* block layout specific type for da_addr_body */

/// struct pnfs_block_deviceaddr4 {

/// pnfs_block_volume4 bda_volumes<>; /* array of volumes */

/// };

///

ーーーーーーここからーーーーーー

"pnfs_block_deviceaddr4" データ構造は、XXX

2.2.3 GETDEVICELIST and GETDEVICEINFO deviceid4

サーバーは、典型的には、 GETDEVICELIST 要求に対して、 gdlr_deviceid_list 配列に単一の "deviceid4" を入れて返します。 "deviceid4" を GETDEVICEINFO に与えると、"device_addr4" が返りそれが、ボリュームの完全な階層をエンコードしています。コピーオンライトファイルシステムの場合、 gdlr_deviceid_list 配列は2つの "deviceid4" があることがあります。1つは、リードオンリー、もうひとつは書き込み可能です。配列内の、リードとライトのデバイス ID の順は決まっていません。ボリュームは deviceid4 で一意に識別され、それを使ってレイアウトから参照されます。サーバーが、複数のデバイスアイテムを返す例は、ファイルハンドルがサーバーにおいて、複数の物理ファイルシステムにまたがるネームスペースのルートを指す場合で、それぞれのファイルシステムが異なるボリューム階層にある場合です。このときサーバー実装はそれぞれの物理ファイルシステムが使っているデバイス ID のリストを返すこともできますし、空のリストを返すこともできます。

成功した GETDEVICELIST 操作の結果、返るそれぞれの deviceid4 は、ボリュームトポロジー全体を参照するための短縮形です。これらデバイス ID は、 LAYOUTGET 操作の結果、返るエクステント中のデバイス ID とともに、 GETDEVICEINFO の入力とすることができます。"pnfs_block_deviceaddr4" をデコードした結果は、 PNFS_BLOCK_VOLUME_SIMPLE ボリュームにマップされたデータブロックのフラットな順序となります。 Section 2.2.1 「ボリューム識別子」で述べたクライアント LUN へのマッピングと組み合わせる結果、論理的ボリュームオフセットは、pNFS クライアント LUN [NFSv4.1] 上のブロックにマップすることができます。

ーーーーーーここまでーーーーーー

2.3 データ構造:エクステントとエクステントリスト

pNFS ブロックレイアウトは、論理ボリューム内の、フラットなデータブロック配列の中にある、エクステントのリストです。ボリュームトポロジーの詳細は、 GETDEVICEINFO 操作で得られます。(Section 2.2 のボリューム識別の議論を参照下さい。)ブロックレイアウトは、指定ファイルを構成する、ボリューム内の個々のブロックエクステントを記述します。エクステントに含まれるオフセットと長さは、バイト単位で表されます。

/// enum pnfs_block_extent_state4 {

/// PNFS_BLOCK_READ_WRITE_DATA = 0,/* the data located by this

/// extent is valid

/// for reading and writing. */

/// PNFS_BLOCK_READ_DATA = 1, /* the data located by this

/// extent is valid for reading

/// only; it may not be

/// written. */

/// PNFS_BLOCK_INVALID_DATA = 2, /* the location is valid; the

/// data is invalid. It is a

/// newly (pre-) allocated

/// extent. There is physical

/// space on the volume. */

/// PNFS_BLOCK_NONE_DATA = 3 /* the location is invalid.

/// It is a hole in the file.

/// There is no physical space

/// on the volume. */

/// };

///

/// struct pnfs_block_extent4 {

/// deviceid4 bex_vol_id; /* id of logical volume on

/// which extent of file is

/// stored. */

/// offset4 bex_file_offset; /* the starting byte offset in

/// the file */

/// length4 bex_length; /* the size in bytes of the

/// extent */

/// offset4 bex_storage_offset; /* the starting byte offset

/// in the volume */

/// pnfs_block_extent_state4 bex_state;

/// /* the state of this extent */

/// };

///

/// /* block layout specific type for loc_body */

/// struct pnfs_block_layout4 {

/// pnfs_block_extent4 blo_extents<>;

/// /* extents which make up this

/// layout. */

/// };

///

ブロックレイアウトは、ファイルの論理的範囲をボリューム上の物理位置にマップするエクステントのリストで構成されます。それぞれのエクステントの "bex_storage_offset" フィールドは、エクステントの "bex_vol_id" フィールドで示される論理ボリューム上の位置を示します。bex_vol_id 自身は、ファイルがある論理ボリュームの完全なトポロジーの短縮形です。この論理オフセットを、適切な、元となる SAN 論理ユニット上のオフセットにマップするのはクライアントの役目です。ほとんどのケースで、レイアウトのすべてのエクステントは同じボリュームに存在し、同じ bex_vol_id を持つでしょう。コピーオンライトファイルシステムの場合、 PNFS_BLOCK_READ_DATA エクステントは、書き込み可能エクステントと異なる bex_vol_id を持つかもしれません。

それぞれのエクステントは、ファイルの論理的範囲を特定の論理ボリュームの部分にマップします。サーバーから返されたエクステントの bex_file_offset, bex_length, and bex_state フィールドは、すべてのエクステントで有効です。それに比べ、 bex_storage_offset フィールドの解釈は、以下のように、 bex_state の値に依存します。(昇順です。)

o PNFS_BLOCK_READ_WRITE_DATA なら、 bex_storage_offset フィールドは有効で、読み書き可能な有効あるいは初期化されたデータを指します。

o PNFS_BLOCK_READ_DATA なら、(訳注。同上)リードオンリーのデータを指します。ライト操作は禁止です。そのためにはクライアントは読み書き可能なレイアウトを要求する必要があります。

o PNFS_BLOCK_INVALID_DATA なら、 bex_storage_offset フィールドは有効ですが、不正な、初期化されていないデータを指します。このデータは、初期化がされるまでは物理的にディスクから読んではいけません。このエクステントを読んだ場合、ユーザーバッファはゼロで埋められます。ただし、そこがコピーオンライトファイルシステムの PNFS_BLOCK_READ_DATA エクステントと重複している場合を除きます。ライト要求は、サーバーの使用する完全なブロック長で、ディスクに書かれなくてはいけません。ユーザーにより初期化されていないバイトはゼロに設定されなくてはいけません。PNFS_BLOCK_INVALID_DATA エクステントへの任意の書き込みは、エクステントのうち書き込まれた部分を、 PNFS_BLOCK_READ_WRITE_DATA に変えます。 pNFS クライアントは LAYOUTCOMMIT でこの変更を報告する義務があります。

o PNFS_BLOCK_NONE_DATA なら、 bex_storage_offset は無効です。このエクステントを使って書き込みはできません。リードは、 PNFS_BLOCK_INVALID_DATA と同様に、ゼロフィルとなります。 PNFS_BLOCK_NONE_DATA エクステントは、リード可能エクステントの要求の結果として返ることがあります。書き込み可能なエクステントの要求の応答には返りません。

エクステントリストは、 bex_file_offset の昇順にエクステントを保持します。それが同じの時は、エクステント状態 (bex_state) の昇順で並べます。

2.3.1 レイアウト要求とエクステントリスト

レイアウトを得るそれぞれの要求は、少なくとも3つのパラメータを持ちます。ファイルオフセット、要求長、そして最小長です。要求のステータスが成功なら、返されるエクステントリストは以下の条件を満たさなくてはいけません。

o リード可能(しかし、ライト不可能)なレイアウトの要求は、PNFS_BLOCK_READ_DATA or PNFS_BLOCK_NONE_DATA エクステントを返します。PNFS_BLOCK_INVALID_DATA or PNFS_BLOCK_READ_WRITE_DATA は返しません。

o ライト可能なレイアウトの要求は、PNFS_BLOCK_READ_WRITE_DATA or PNFS_BLOCK_INVALID_DATA を返します。PNFS_BLOCK_NONE_DATA は返しません。エクステントのオフセット範囲が、PNFS_BLOCK_INVALID_DATA と重なっていて、書き込み可能である場合は、PNFS_BLOCK_READ_DATA が返ることもあります。

o リストの最初のエクステントは、要求された開始オフセットを含まなくてはいけません。

o 要求された範囲のエクステントの合計長は、少なくても、最小長でなくてはいけません。1つの例外は、リード可能エクステントが要求され、途中でファイル終端があった場合です。

o エクステントリスト中のエクステントは、リードオンリーレイアウトの場合、論理的に連続でなくてはいけません。読み書き可能なレイアウトの場合、書き込み可能なエクステントのセット(つまり、PNFS_BLOCK_READ_DATA 以外のところ)は、論理的に連続でなくてはいけません。読み書き可能なレイアウトの中の、すべての PNFS_BLOCK_READ_DATA エクステントは、1つ以上の PNFS_BLOCK_INVALID_DATA でカバーされていなくてはいけません。エクステントがオーバーラップしていいのは、この、PNFS_BLOCK_READ_DATA and PNFS_BLOCK_INVALID_DATA のケースだけです。

o エクステントは、リスト中で、開始オフセット順に並びます。bex_file_offsets が同じときは、PNFS_BLOCK_READ_DATA が、PNFS_BLOCK_INVALID_DATA の前に来ます。

もし、最小長、loga_minlength、がゼロのとき、これは、クライアントが、オフセットloga_offset 以下の任意のレイアウトで、メタデータサーバーが「直ちに」提供可能なものをほしいという指定です。直ちに、というのは主観的なもので、レイアウトタイプと、pNFS サーバー実装に依存します。ブロックレイアウトサーバーの場合、以下のように解釈されるべきです。リード可能レイアウトは、一部のエクステントが PNFS_BLOCK_NONE_DATA 状態にあっても、常に提供可能です。書き込み可能レイアウトは、エクステントが PNFS_BLOCK_READ_WRITE_DATA 状態のとき、提供可能です。

2.3.2 レイアウトコミット

/// /* block layout specific type for lou_body */

/// struct pnfs_block_layoutupdate4 {

/// pnfs_block_extent4 blu_commit_list<>;

/// /* list of extents which

/// * now contain valid data.

/// */

/// };

///

"pnfs_block_layoutupdate4" 構造体は、クライアントにより、LAYOUTCOMMIT 操作の、ブロックプロトコル固有の引数に使われます。"blu_commit_list" フィールドは、エクステントのリストであり、以前は PNFS_BLOCK_INVALID_DATA 状態だったのが、クライアントが書き込んだ結果、PNFS_BLOCK_READ_WRITE_DATA 状態になったものです。blu_commit_list にあるすべてのエクステントの bex_state フィールドは、PNFS_BLOCK_READ_WRITE_DATA でなくてはいけません。コミットリストのエクステントは、非連続で、bex_file_offset の順でなくてはいけません。bex_storage_offset フィールドは使われません。実装者は、サーバーはファイルシステムブロック(典型的には、4KBか8KB)より小さい粒度で領域をコミットすることはできないことがあるのに注意ください。以前に述べたように、サーバーの使うブロック長は NFSv4 属性として見えます。"blu_commit_list" にあるエクステントはすべて、この境界にあり、かつその長さの倍数長でなくてはいけません。もしクライアントが、自分の操作の結果、ファイル終端が、コミットされるブロックの中間に移動したと思った場合は、クライアントはブロックをコミットする前にファイル終端からブロック終端までをセロクリアしなければいけません。そうしないと、ファイルが後にファイル終端を伸ばすことで大きくなったときに、その部分にごみ(初期化されていないデータ)が見えることになります。

2.3.3 レイアウト返却

LAYOUTRETURN 操作に、ブロックレイアウト固有のデータはありません。XXX

2.3.4 クライアントのコピーオンライト処理

2.3.5 エクステントはパーミッションです

pNFS クライアントに返されるレイアウトエクステントは、リードとライトのパーミッションです。PNFS_BLOCK_READ_DATA and PNFS_BLOCK_NONE_DATA はリードオンリー、PNFS_BLOCK_READ_WRITE_DATA and PNFS_BLOCK_INVALID_DATA は、読み書き可能です。これが、ストレージデバイスに直接 I/O を出す許可を得るためにクライアントが使うことのできる唯一の方法です。pNFS クライアントは、自分が持っているエクステントで許可される以外の直接の I/O を出してはいけません。クライアントがこれを守れば、pNFS サーバーは競合する可能性のあるストレージデバイス操作を制御することができます。サーバーは、何が競合して、どうやって回避するかを判断でき、クライアント間でエクステントを許可したり回収したりできます。

ブロック/ボリュームクラスのストレージデバイスは、読み書き操作をアトミックに実行する必要はありません。同じデータへの同時実行するリードとライトは、リードの結果、ライト前のデータとライト後のデータが混じって読めるかもしれません。オーバーラップするライト同士はもっとひどく、結果は2つのライト操作の混じったものとなるかもしれません。元となるストレージがストライプされていて、書き込みがストライプごとに異なる順で完了した場合、データ破壊が起きます。同じデータをアクセスしたいクライアントが複数いる場合、pNFS サーバーは単一ライター XOR 複数リーダーの並列実行ポリシーを使えば、上記の競合を避けることができます。ストレージデバイスが、同時実行する同じデータへの読み書きあるいはライト同士のアトミシティーを保証しない場合、前記ポリシーは実装されなくてはいけません。

訳注。すぐ前に、アトミシティーは必要でないといっている。分散ファイルシステムでなくても、同時ライトの結果が混じるのは仕様。ファイルロックで排他するのはアプリの責任。なのだけど、以下に述べる、メタデータサーバーが、競合するレイアウトを同時に許可しない、競合するファイルロックとレイアウトも許可しない、というのがポリシーの実施にあたるのでしょうか。

クライアントが既存のレイアウト委譲と競合するレイアウト要求を出した場合、要求は NFS4ERR_LAYOUTTRYLATER でエラーになります。次にクライアントは、しばらくして、要求をリトライするでしょう。この間に、サーバーは、競合するレイアウト部分を持っているクライアントからそれを回収するべきです。この、拒否とリトライアプローチは、あるファイルのレイアウトに要求が多い時は、クライアントの飢餓状態、沈み込み、を起こすことがあります。pNFS サーバーはこれを防ぐしかけを持つべきです。1つの案は、サーバーが拒否したレイアウト要求のキューを持つことです。新しく届いた要求は、以前に拒否された要求と競合するときには、拒否されます。以前に拒否されたクライアントがリトライしてきたら、キューの自分のエントリーをクリアします。あるいは、古くなったら、エントリーは削除されます。

NFSv4 は、マンダトリーロックと共有予約をサポートします。クライアントは、これにより、他のクライアントが使うことのできる I/O 操作を制限することができます。すべての I/O 操作は、NFSv4 サーバーに届きますから、そこでこの制限をするのがよいでしょう。しかし、pNFS レイアウトでは、レイアウトを持つクライアントは直接データを持つストレージデバイスに I/O を出せます。デバイスは、ファイル、マンダトリーロック、あるいは共有予約については知りません。なので、制限ができません。このため、NFSv4 サーバーはマンダトリーロックや共有予約と競合するレイアウトを許可してはいけません。さらに、競合するマンダトリーロックあるいは競合するオープンが届いたならば、サーバーは要求を許可する前に、競合するレイアウト部分を回収しなくてはいけません。

ーーーーーーここからーーーーーー

ーーーーーーここまでーーーーーー

2.3.6 ファイル終端の処理

ファイル終端の位置は、2つの方法で更新されます。現在のファイル終端を超える WRITE or LAYOUTCOMMIT の結果によって暗黙的に。あるいは、 SETATTR によって明示的に。典型的には、 NFSv4 クライアントの SETATTR によってファイルが切り詰められたときは、サーバーは新しいファイル終端バイトを超える、ファイルに属しているすべてのディスクブロックを解放します。さらに、ファイル終端ブロックのうち、終端バイト以降の部分にゼロを書かなくてはいけません。これらの操作は、解放あるいは書き込まれたブロックを参照するすべての pNFS レイアウトを、意味的に無効にします。このため、サーバーは、トランケート要求を処理する前に、クライアントからこれらレイアウトを回収しなくてはいけません。この回収は、[NFSv4.1] で説明したように、時間がかかるかもしれません。もしサーバーが、クライアントの SETATTR 要求に妥当な時間内に応答できない場合は、 NFS4ERR_DELAY をクライアントに返すべきです。

PNFS_BLOCK_INVALID_DATA 状態にあるブロックで、新しいファイル終端の先にあるものは、特別なケースです。サーバーはこれらのブロックを、書き込み可能なレイアウトを持つ pNFS クライアントのために確保したのですが、クライアントはまだそのブロックをコミットして来ることはなく、ブロックはファイルのディスク上のマッピングの一部ではありません。サーバーは、 SETATTR の処理でこれらブロックを解放することもできます。もしそうしたら、前に述べたようにサーバーはそれを参照するレイアウトを回収する必要があります。サーバーが PNFS_BLOCK_INVALID_DATA を解放しないなら、PNFS_BLOCK_INVALID_DATA ブロックだけを参照するレイアウトは回収する必要はありません。

ファイルが、暗黙的に WRITE or LAYOUTCOMMIT によって現在のファイル終端より伸びた場合あるいは、明示的に SETATTR で伸びた場合は、サーバーはレイアウト回収をする必要は全くありません。

2.3.7 レイアウトヒント

2.3.8 クライアントフェンシング

pNFS ブロックプロトコルでは、システム障害、特に、ネットワーク接続の問題のために、サーバーが一方的に、あるクライアントの持つエクステントを失効させ、他のクライアントに与えるという状況に対処しなくてはいけません。pNFS サーバー実装は、ある資源を別のクライアントに与えたら、元のクライアントからはそれを使えないことを保証しなくてはいけません。これは、プロトコルのすべての参加者(サーバー、ストレージ、そしてクライアント)の間で起きる、ネットワーク分断、遅延のすべての組み合わせに対して保証されなくてはいけません。この隔離を実現するための2つのアプローチがあり、以下に説明します。

ブロッククライアントをブロックストレージからフェンスする1つの実装上の選択は、LUN マスキングあるいはマッピングを使うことです。ストレージシステムあるいはストレージエリアネットワークでそれを行い、クライアントのアクセスを無効にします。そのためには、サーバーが、ストレージシステムの管理インタフェースにアクセスして、LUN マスキングなどの管理操作をする権限がある必要があります。例えば、 Storage Management Initiative Specification (SMI-S) [SMIS] は、LUN を発見し、マスクする機能があります。また、あるワールドワイドネームや、イニシエーターネームを持つクライアントをマスクすることもできます。

LUN マスキングがサポートされないときは、サーバーは、クライアントが期限付きリースによる I/O フェンス機能を実装することに頼るしかありません。クライアントは、サーバーが LUN マスキングを使っているかわからないので、クライアントは常に期限付きリースによる I/O フェンスを実装しなくてはいけません。期限付きリースによる I/O フェンスのため、2つの期限を定義します。1つめ、「lease_time」は、サーバーの lease_time 属性(see [NFSv4.1])で定義されるリースの長さです。2つめ、「blh_maximum_io_time」は、クライアントのストレージシステムへの I/O が完了あるいは失敗するのに必要な最大時間です。これは、多くの場合、30秒あるいは60秒ですが、環境によってはもっと長いこともあります。クライアント I/O 時間の最大値が決められない場合、クライアントは、 blh_maximum_io_time として、すべて1をたてたものを使います。

新しいクライアント ID が確立されたら、クライアントはレイアウトヒントに LAYOUT4_BLOCK_VOLUME 型を指定した SETATTR を使って、サーバーに自分の I/O 時間の最大値を伝えます。これは、最初の LAYOUTGET 操作の前に行います。 I/O 時間の最大値ヒントは、ファイルごとの属性ですが、実際は、クライアントごとの特性です。このため、サーバーは、クライアントごとに、最新の I/O 時間の最大値ヒントを維持しなくてはいけません。それが変わったときは、サーバーは、そのクライアントがレイアウトを持つすべてのファイルに対して変更を行います。もしクライアントが、ブロックレイアウトを要求したファイルに、この属性を指定していなかったら、サーバーはそのクライアントが任意のファイルに指定した最新値を使うべきです。クライアントが全くこの属性を指定したことがないときは、サーバーはレイアウト要求を NFS4ERR_LAYOUTUNAVAILABLE で拒否するべきです。クライアントは、 LAYOUTGET のたびにレイアウトヒントの SETATTR を送るべきではありません。LUN マスキングでフェンシングをするサーバーは、クライアントからの任意の I/O 時間の最大値を受け付けるべきです。そうしないサーバーは、 SETATTR に、 NFS4ERR_INVAL を返すことがあります。そのようなサーバーは、クライアントが、無限の I/O 時間の最大値(すべて1)を送ってきた時や、 I/O 時間の最大値が pNFS でブロックレイアウトを使う他のクライアントと比べてとても大きい時には、 NFS4ERR_INVAL を返すべきです。

ーーーーーーここからーーーーーー

クライアントが、レイアウトヒントの SETATTR 操作に NFS4ERR_INVAL を受け取った場合、クライアントは LAYOUTGET 操作は使ってはいけません。サーバーも、そのクライアントが以降発行するすべての LAYOUTGET を、 NFS4ERR_LAYOUTUNAVAILABLE にしなければいけません。このように、大きいあるいは無限の I/O 時間の最大値を持つクライアントが pNFS を使うことができるかどうかは、サーバーが NFS4ERR_INVAL 、 NFS4_OK のどちらを返すかによって決まります。

リース時間と I/O 時間の最大値を使って、クライアントとサーバーは以下のようにふるまいます。

クライアントが LAYOUTGET でレイアウトを得たとき、それはサーバーがそれを許可したときから、最大、 "lease_time" 秒の間有効です。レイアウトは、SEQUENCE 操作が成功したとき、あるいは新しい stateid が作られたとき、更新されたとき("Lease Renewal" of [NFSv4.1] を参照ください。) に更新されます。レイアウトリースが、満了前に更新されないとき、クライアントは、それを使うのをやめなくてはいけません。それは、クライアントが元の LAYOUTGET を送ったとき、あるいは、最後のリース更新につながる操作を送ったときから、"lease_time" 秒に起きます。つまり、クライアントは、満了したレイアウトに書いてあるブロックには I/O を投げてはいけないということです。クライアントとサーバーに大きな通信遅延があるときは、サーバーの応答がクライアントに届く前にリースが満了することもあります。そのような場合、クライアントは満了したレイアウトを使ってはならず、通常の NFSv41 のREAD, WRITE に切り替えるべきです。さらにクライアントは、マルチパスドライバーが、複数パスを使って I/O をリトライすることがあっても、 I/O 操作が"blh_maximum_io_time" 内に完了するように設定されなければいけません。

「クライアントでリース満了に対処する」節 [NFSv4.1] で述べたように、 SEQUENCE 操作が成功しても、sr_status_flag が、SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED, SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED, or SEQ4_STATUS_ADMIN_STATE_REVOKED が立っている場合、クライアントはすべてのレイアウトと、そのサーバーに関連するデバイス ID からデバイスアドレスのマッピングを直ちに使わないようにしなければいけません。

フロントチャネルで、クライアントとサーバーの既知の双方向会話はありませんから、サーバーはレイアウトを元のクライアントから他に移すには、少なくとも "lease_time" plus "blh_maximum_io_time" の間、待たなくてはいけません。サーバーは、クライアントと同じく、保守的アプローチをとって、リース満了タイマーを、最後にリースを更新した操作を受け取ったその時刻から開始しなくてはいけません。

ーーーーーーここまでーーーーーー

2.4 障害回復の問題

一般論は、 NFSv4 仕様書に書いてありますから、ここでは、ブロック/ボリュームレイアウトに固有の話をしましょう。(大意)

サーバーがクラッシュして、クライアントは書き込み可能レイアウトを持っていて、以前にそのレイアウトの範囲にデータを書き、そのブロックは、まだ NFS_BLOCK_INVALID_DATA

状態だとすると、クライアントは2つの回復方法があります。もしクライアントが自分のキャッシュにデータをまだ持っていれば、サーバーが回復してからそれを NFSv4 経由で再度、書けばよろしい。データがキャッシュにない場合、クライアントはデータをデータサーバーから得ようとしてはいけません。そのかわり、クライアントは問題のブロックを、サーバーのグレースピリオドの間に、コミットしようと試みるべきです。それには、"loca_reclaim" フラグを真にした LAYOUTCOMMIT を送ります。詳しくは、Section 18.42.4 of [NFSv4.1] を参照下さい。

2.5 資源を回収する:CB_RECALL_ANY

2.6 一時的と永続的エラー

3 セキュリティ上の考察(大意)

2.1の後半と同じ。ストレージプロトコルは、ファイルのロックや ACL を理解できないから、クライアントと通信路が信頼できる、単一のデータセンター内以外では、おすすめできません。

訳注。仮想ブロックアドレスという案が示されているが、何のことかわかりません。

通信路のセキュリティは、パラレル SCSI ケーブルのように、物理的近傍にあることによって提供される場合も、iSCSI のように、プロトコルが持っている機能が活用される場合もあります。

にしても、ストレージプロトコルが行うのは、イニシエーター対ボリュームという荒い粒度なので、何度も言うようですが、おすすめできない環境というものがあります。

7. References

7.1. Normative References

[LEGAL] IETF Trust, "Legal Provisions Relating to IETF Documents",

http://trustee.ietf.org/docs/IETF-Trust-License-Policy.pdf,

November 2008.

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate

Requirement Levels", BCP 14, RFC 2119, March 1997.

[NFSv4.1] Shepler, S., Ed., Eisler, M., Ed., and D. Noveck, Ed.,

"Network File System (NFS) Version 4 Minor Version 1

Protocol", RFC 5661, January 2010.

[XDR] Eisler, M., Ed., "XDR: External Data Representation

Standard", STD 67, RFC 4506, May 2006.

7.2. Informative References

[MPFS] EMC Corporation, "EMC Celerra Multi-Path File System

(MPFS)", EMC Data Sheet,

http://www.emc.com/collateral/software/data-sheet/

h2006-celerra-mpfs-mpfsi.pdf.

[SMIS] SNIA, "Storage Management Initiative Specification (SMI-S)

v1.4", http://www.snia.org/tech_activities/standards/

curr_standards/smi/SMI-S_Technical_Position_v1.4.0r4.zip.

以上