跳到主要内容

3. 服务器过程 (Server Procedures)

以下各节定义了 NFS 版本3协议服务器提供的 RPC 过程. RPC 过程编号在页面顶部与名称一起给出. SYNOPSIS 提供过程的名称、参数名称列表、结果名称列表, 以及 XDR 参数声明和结果声明. SYNOPSIS 中的信息以 [RFC1014] 中定义的 RPC 数据描述语言指定. DESCRIPTION 部分说明过程预期执行的操作以及如何使用其参数和结果. ERRORS 部分列出针对特定类型失败返回的错误. 这些列表并非旨在作为任何特定过程可以返回的所有错误的权威声明, 而是作为可能返回的更常见错误的指南. 客户端实现应准备好处理来自服务器的意外错误. IMPLEMENTATION 字段提供有关过程预期如何工作以及客户端应如何使用它的信息.

program NFS_PROGRAM {
version NFS_V3 {

void
NFSPROC3_NULL(void) = 0;

GETATTR3res
NFSPROC3_GETATTR(GETATTR3args) = 1;

SETATTR3res
NFSPROC3_SETATTR(SETATTR3args) = 2;

LOOKUP3res
NFSPROC3_LOOKUP(LOOKUP3args) = 3;

ACCESS3res
NFSPROC3_ACCESS(ACCESS3args) = 4;

READLINK3res
NFSPROC3_READLINK(READLINK3args) = 5;

READ3res
NFSPROC3_READ(READ3args) = 6;

WRITE3res
NFSPROC3_WRITE(WRITE3args) = 7;

CREATE3res
NFSPROC3_CREATE(CREATE3args) = 8;

MKDIR3res
NFSPROC3_MKDIR(MKDIR3args) = 9;

SYMLINK3res
NFSPROC3_SYMLINK(SYMLINK3args) = 10;

MKNOD3res
NFSPROC3_MKNOD(MKNOD3args) = 11;

REMOVE3res
NFSPROC3_REMOVE(REMOVE3args) = 12;

RMDIR3res
NFSPROC3_RMDIR(RMDIR3args) = 13;

RENAME3res
NFSPROC3_RENAME(RENAME3args) = 14;

LINK3res
NFSPROC3_LINK(LINK3args) = 15;

READDIR3res
NFSPROC3_READDIR(READDIR3args) = 16;

READDIRPLUS3res
NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17;

FSSTAT3res
NFSPROC3_FSSTAT(FSSTAT3args) = 18;

FSINFO3res
NFSPROC3_FSINFO(FSINFO3args) = 19;

PATHCONF3res
NFSPROC3_PATHCONF(PATHCONF3args) = 20;

COMMIT3res
NFSPROC3_COMMIT(COMMIT3args) = 21;

} = 3;
} = 100003;

超出范围 (未定义) 的过程编号会导致 RPC 错误. 详情请参阅 [RFC1057].

3.1 关于属性和失败时一致性数据的一般说明 (General comments on attributes and consistency data on failure)

对于那些在失败时返回 post_op_attr 或 wcc_data 结构的过程, 判别联合可能包含对象或对象父目录的操作前属性. 这取决于遇到的错误, 也可能取决于特定的服务器实现. 强烈建议实现者在失败时尽可能多地返回属性数据, 但客户端实现者需要意识到, 其实现必须正确处理不返回任何属性或一致性数据的变体返回实例.

3.2 关于文件名的一般说明 (General comments on filenames)

以下注释适用于所有 NFS 版本3协议过程, 其中客户端在参数中提供一个或多个文件名: LOOKUP、CREATE、MKDIR、SYMLINK、MKNOD、REMOVE、RMDIR、RENAME 和 LINK.

  1. 文件名不得为 null, 也不得为空字符串. 如果服务器收到这样的文件名, 应返回错误 NFS3ERR_ACCES. 在某些客户端上, 文件名 '' 或空字符串被假定为当前目录的别名. 需要此功能的客户端应自行实现, 而不依赖服务器支持此类语义.

  2. 值为 "." 的文件名被假定为当前目录的别名. 需要此功能的客户端应自行实现, 而不依赖服务器支持此类语义. 但是, 服务器应能够正确处理此类文件名.

  3. 值为 ".." 的文件名被假定为当前目录父目录的别名, 即包含当前目录的目录. 服务器应准备好处理此语义 (如果它支持目录), 即使这些目录不包含 UNIX 风格的 "." 或 ".." 条目.

  4. 如果文件名长于文件系统的最大值 (参见 PATHCONF, 特别是 name_max), 则结果取决于 PATHCONF 标志 no_trunc 的值. 如果 no_trunc 为 FALSE, 文件名将被静默截断为 name_max 字节. 如果 no_trunc 为 TRUE 且文件名超过服务器文件系统最大文件名长度, 操作将失败并返回错误 NFS3ERR_NAMETOOLONG.

  5. 通常, 服务器无法处理某些字符作为文件名的一部分. 这组字符因服务器和实现而异. 在大多数情况下, 是服务器控制客户端对文件系统的视图. 如果服务器收到包含其无法处理的字符的文件名, 应返回错误 NFS3ERR_EACCES. 客户端实现应准备好处理异构性的这种副作用.

3.3.0 过程 0: NULL - 不做任何事 (Do nothing)

SYNOPSIS

void NFSPROC3_NULL(void) = 0;

DESCRIPTION

NULL 过程不做任何工作. 它被提供以允许服务器响应测试和计时.

IMPLEMENTATION

重要的是此过程完全不做任何工作, 以便可以用于测量处理服务请求的开销. 按照惯例, NULL 过程永远不应要求任何身份验证. 在更安全的实现中, 服务器可以选择忽略此惯例, 其中响应 NULL 过程调用向未经身份验证的客户端确认资源的存在.

ERRORS

由于 NULL 过程不接受任何 NFS 版本3协议参数且不返回任何 NFS 版本3协议响应, 因此它不能返回 NFS 版本3协议错误. 但是, 某些服务器实现可能会根据安全和身份验证要求返回 RPC 错误.

3.3.1 过程 1: GETATTR - 获取文件属性 (Get file attributes)

SYNOPSIS

GETATTR3res NFSPROC3_GETATTR(GETATTR3args) = 1;

struct GETATTR3args {
nfs_fh3 object;
};

struct GETATTR3resok {
fattr3 obj_attributes;
};

union GETATTR3res switch (nfsstat3 status) {
case NFS3_OK:
GETATTR3resok resok;
default:
void;
};

DESCRIPTION

GETATTR 过程检索指定文件系统对象的属性. 对象由服务器作为 LOOKUP、CREATE、MKDIR、SYMLINK、MKNOD 或 READDIRPLUS 过程响应的一部分返回的文件句柄标识 (或来自 MOUNT 服务). 进入时, GETATTR3args 中的参数为:

  • object: 要检索其属性的对象的文件句柄.

成功返回时, GETATTR3res.status 为 NFS3_OK, GETATTR3res.resok 包含:

  • obj_attributes: 对象的属性.

否则, GETATTR3res.status 包含失败时的错误, 不返回其他结果.

IMPLEMENTATION

文件系统对象的属性是不同操作系统之间主要分歧点. 服务器应尽最大努力支持 fattr3 结构中的所有属性, 以便客户端可以将其作为公共基础. 可能需要一些映射来将本地属性映射到 fattr3 结构中的属性.

目前, 大多数客户端 NFS 版本3协议实现实现了基于时间限制的属性缓存方案, 以减少线上属性检查.

ERRORS

NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

ACCESS.

3.3.2 过程 2: SETATTR - 设置文件属性 (Set file attributes)

SYNOPSIS

SETATTR3res NFSPROC3_SETATTR(SETATTR3args) = 2;

union sattrguard3 switch (bool check) {
case TRUE:
nfstime3 obj_ctime;
case FALSE:
void;
};

struct SETATTR3args {
nfs_fh3 object;
sattr3 new_attributes;
sattrguard3 guard;
};

struct SETATTR3resok {
wcc_data obj_wcc;
};

struct SETATTR3resfail {
wcc_data obj_wcc;
};

union SETATTR3res switch (nfsstat3 status) {
case NFS3_OK:
SETATTR3resok resok;
default:
SETATTR3resfail resfail;
};

DESCRIPTION

SETATTR 过程更改服务器上文件系统对象的一个或多个属性. 新属性由 sattr3 结构指定. 进入时, SETATTR3args 中的参数为:

  • object: 对象的文件句柄.
  • new_attributes: 包含描述要设置的属性及其新值的布尔值和枚举的 sattr3 结构.
  • guard: sattrguard3 联合:
    • check: 如果服务器要验证 guard.obj_ctime 与对象的 ctime 匹配, 则为 TRUE; 否则为 FALSE.

客户端可以请求服务器在执行 SETATTR 操作之前检查对象是否处于预期状态. 为此, 它将参数 guard.check 设置为 TRUE, 并在 guard.obj_ctime 中传递时间值. 如果 guard.check 为 TRUE, 服务器必须将 guard.obj_ctime 的值与对象的当前 ctime 进行比较. 如果值不同, 服务器必须保留对象属性并返回状态 NFS3ERR_NOT_SYNC. 如果 guard.check 为 FALSE, 服务器将不执行此检查.

成功返回时, SETATTR3res.status 为 NFS3_OK, SETATTR3res.resok 包含:

  • obj_wcc: 包含对象旧属性和新属性的 wcc_data 结构.

否则, SETATTR3res.status 包含失败时的错误, SETATTR3res.resfail 包含:

  • obj_wcc: 包含对象旧属性和新属性的 wcc_data 结构.

IMPLEMENTATION

guard.check 机制允许客户端避免基于过时属性更改对象的属性. 它不保证精确一次语义. 特别是, 如果回复丢失且服务器未检测到请求的重传, 即使属性设置之前已成功执行, 过程也可能以错误 NFS3ERR_NOT_SYNC 失败. 客户端可以尝试通过从服务器获取新属性并使用新 ctime 发送新的 SETATTR 请求来从此错误中恢复. 如果新属性显示属性已按需设置, 客户端可以选择检查属性以避免第二个 SETATTR 请求 (尽管可能不是发出请求的客户端设置了属性).

new_attributes.size 字段用于请求更改文件大小. 值为0会导致文件被截断, 小于文件当前大小的值会导致从新大小到文件末尾的数据被丢弃, 大于文件当前大小的值会导致逻辑上为零的数据字节被添加到文件末尾. 服务器可以使用空洞或实际零数据字节来自由实现此功能. 客户端不应对服务器此功能的实现做任何假设, 除了返回的字节将为零. 服务器必须支持通过 SETATTR 扩展文件大小.

SETATTR 不保证原子性. 失败的 SETATTR 可能会部分更改文件的属性.

使用 SETATTR 更改文件大小会间接更改 mtime. 客户端必须考虑到这一点, 因为大小更改可能导致数据删除.

如果服务器和客户端时间不同, 将客户端时间与文件时间进行比较的程序可能会出错. 应使用时间维护协议来限制客户端/服务器时间偏差.

在异构环境中, 服务器很可能无法支持 SETATTR 请求的全部范围. 如果服务器无法在其自己的 uid 或 gid 表示中存储 uid 或 gid, 则可能返回错误 NFS3ERR_INVAL. 如果服务器只能支持32位偏移量和大小, 则将文件大小设置为大于32位可以表示的大小的 SETATTR 请求将被拒绝并返回相同的错误.

ERRORS

NFS3ERR_PERM
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_INVAL
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_DQUOT
NFS3ERR_NOT_SYNC
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

CREATE, MKDIR, SYMLINK, and MKNOD.

3.3.3 过程 3: LOOKUP - 查找文件名 (Lookup filename)

SYNOPSIS

LOOKUP3res NFSPROC3_LOOKUP(LOOKUP3args) = 3;

struct LOOKUP3args {
diropargs3 what;
};

struct LOOKUP3resok {
nfs_fh3 object;
post_op_attr obj_attributes;
post_op_attr dir_attributes;
};

struct LOOKUP3resfail {
post_op_attr dir_attributes;
};

union LOOKUP3res switch (nfsstat3 status) {
case NFS3_OK:
LOOKUP3resok resok;
default:
LOOKUP3resfail resfail;
};

DESCRIPTION

LOOKUP 过程在目录中搜索特定名称, 并返回对应文件系统对象的文件句柄. 进入时, LOOKUP3args 中的参数为:

  • what: 要查找的对象:
    • dir: 要搜索的目录的文件句柄.
    • name: 要搜索的文件名. 参见关于文件名的一般说明.

成功返回时, LOOKUP3res.status 为 NFS3_OK, LOOKUP3res.resok 包含:

  • object: 对应 what.name 的对象的文件句柄.
  • obj_attributes: 对应 what.name 的对象的属性.
  • dir_attributes: 目录 what.dir 的操作后属性.

否则, LOOKUP3res.status 包含失败时的错误, LOOKUP3res.resfail 包含:

  • dir_attributes: 目录 what.dir 的操作后属性.

IMPLEMENTATION

乍一看, 在 what.name 指向服务器上的挂载点的情况下, 似乎有两种不同的回复. 服务器可以返回被挂载目录的文件句柄或挂载目录根的文件句柄. 这种歧义很容易解决. 服务器不允许 LOOKUP 操作跨越挂载点到不同文件系统的根, 即使该文件系统已导出. 这不会阻止客户端访问服务器导出的文件系统层次结构, 但客户端必须单独挂载每个文件系统, 以便挂载点跨越发生在客户端. 给定的服务器实现可以根据该实现特有的能力或限制来细化这些规则.

两个文件名被区分, 如 NFS 版本2协议中一样. 名称 "." 是当前目录的别名, 名称 ".." 是父目录的别名; 即包含指定目录作为成员的目录. 没有处理多父目录的设施, NFS 协议假设层次组织, 组织为单根树.

注意此过程不跟随符号链接. 客户端负责所有文件名的解析, 包括在查找过程中遇到符号链接修改的文件名.

ERRORS

NFS3ERR_IO
NFS3ERR_NOENT
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_NAMETOOLONG
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

CREATE, MKDIR, SYMLINK, MKNOD, READDIRPLUS, and PATHCONF.

3.3.4 过程 4: ACCESS - 检查访问权限 (Check Access Permission)

SYNOPSIS

ACCESS3res NFSPROC3_ACCESS(ACCESS3args) = 4;

const ACCESS3_READ = 0x0001;
const ACCESS3_LOOKUP = 0x0002;
const ACCESS3_MODIFY = 0x0004;
const ACCESS3_EXTEND = 0x0008;
const ACCESS3_DELETE = 0x0010;
const ACCESS3_EXECUTE = 0x0020;

struct ACCESS3args {
nfs_fh3 object;
uint32 access;
};

struct ACCESS3resok {
post_op_attr obj_attributes;
uint32 access;
};

struct ACCESS3resfail {
post_op_attr obj_attributes;
};

union ACCESS3res switch (nfsstat3 status) {
case NFS3_OK:
ACCESS3resok resok;
default:
ACCESS3resfail resfail;
};

DESCRIPTION

ACCESS 过程确定用户 (由请求中的凭据标识) 对文件系统对象拥有的访问权限. 客户端在位掩码中编码要检查的权限集. 服务器检查位掩码中编码的权限. 返回状态 NFS3_OK 以及编码了允许客户端拥有的权限的位掩码.

此过程的结果本质上是建议性的. 也就是说, 返回状态 NFS3_OK 且位掩码中设置了适当位并不意味着将来允许对文件系统对象进行此类访问, 因为服务器可以随时撤销访问权限.

进入时, ACCESS3args 中的参数为:

  • object: 要检查访问权限的文件系统对象的文件句柄.
  • access: 要检查的访问权限的位掩码.

可以请求以下访问权限:

  • ACCESS3_READ: 从文件读取数据或读取目录.
  • ACCESS3_LOOKUP: 在目录中查找名称 (对非目录对象无意义).
  • ACCESS3_MODIFY: 重写现有文件数据或修改现有目录条目.
  • ACCESS3_EXTEND: 写入新数据或添加目录条目.
  • ACCESS3_DELETE: 删除现有目录条目.
  • ACCESS3_EXECUTE: 执行文件 (对目录无意义).

成功返回时, ACCESS3res.status 为 NFS3_OK. 如果没有发生阻止服务器进行所需访问检查的错误, 服务器应返回状态 NFS3_OK. ACCESS3res.resok 中的结果为:

  • obj_attributes: 对象的操作后属性.
  • access: 指示请求中提供的身份验证凭据的访问权限的位掩码.

否则, ACCESS3res.status 包含失败时的错误, ACCESS3res.resfail 包含:

  • obj_attributes: 对象的属性 - 如果允许访问属性.

IMPLEMENTATION

通常, 客户端通过检查文件属性中的 uid、gid 和 mode 字段来推断访问权限是不够的, 因为服务器可能执行 uid 或 gid 映射或强制执行额外的访问控制限制. NFS 版本3协议服务器也可能与 NFS 版本3协议客户端不在同一 ID 空间中. 在这些情况下 (以及可能的其他情况), NFS 版本3协议客户端无法仅凭当前文件属性可靠地执行访问检查.

在 NFS 版本2协议中, 确定操作是否被允许的唯一可靠方法是尝试它并查看是否成功或失败. 使用 NFS 版本3协议中的 ACCESS 过程, 客户端可以询问服务器是否允许一个或多个类别的操作. ACCESS 操作的提供是为了允许客户端在执行一系列操作之前进行检查. 这在操作系统 (如 UNIX) 中很有用, 其中权限检查仅在打开文件或目录时完成. 此过程也由 NFS 客户端访问过程调用 (可能通过 access(2) 调用). 其目的是使打开远程文件的行为与打开本地文件的行为更加一致.

服务器响应 ACCESS 调用返回的信息不是永久性的. 它在服务器执行检查的确切时间是正确的, 但之后不一定. 服务器可以随时撤销访问权限.

NFS 版本3协议客户端应使用用户的有效凭据来构建 ACCESS 请求中的身份验证信息, 以确定访问权限. 在后续读写操作中使用的是有效用户和组凭据.

许多实现不直接支持 ACCESS3_DELETE 权限. 像 UNIX 这样的操作系统将忽略对非目录对象的访问请求中设置的 ACCESS3_DELETE 位. 在这些系统中, 文件的删除权限由文件所在目录的访问权限决定, 而不是由文件本身的权限决定. 因此, 此类请求返回的位掩码将 ACCESS3_DELETE 位设置为0, 表示客户端没有此权限.

ERRORS

NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

GETATTR.

SYNOPSIS

READLINK3res NFSPROC3_READLINK(READLINK3args) = 5;

struct READLINK3args {
nfs_fh3 symlink;
};

struct READLINK3resok {
post_op_attr symlink_attributes;
nfspath3 data;
};

struct READLINK3resfail {
post_op_attr symlink_attributes;
};

union READLINK3res switch (nfsstat3 status) {
case NFS3_OK:
READLINK3resok resok;
default:
READLINK3resfail resfail;
};

DESCRIPTION

READLINK 过程读取与符号链接关联的数据. 数据是对服务器不透明的 ASCII 字符串. 也就是说, 无论是由客户端的 NFS 版本3协议软件创建还是在服务器上本地创建, 符号链接中的数据在创建时不被解释, 而只是被存储. 进入时, READLINK3args 中的参数为:

  • symlink: 符号链接的文件句柄 (NF3LNK 类型的文件系统对象).

成功返回时, READLINK3res.status 为 NFS3_OK, READLINK3res.resok 包含:

  • data: 与符号链接关联的数据.
  • symlink_attributes: 符号链接的操作后属性.

否则, READLINK3res.status 包含失败时的错误, READLINK3res.resfail 包含:

  • symlink_attributes: 符号链接的操作后属性.

IMPLEMENTATION

符号链接名义上是指向另一个文件的指针. 数据不一定由服务器解释, 只是存储在文件中. 客户端实现可能在符号链接中存储对服务器操作系统没有意义的路径名. READLINK 操作将数据返回给客户端进行解释. 如果不同的实现想要共享对符号链接的访问, 则它们必须就符号链接中数据的解释达成一致.

READLINK 操作仅允许在 NF3LNK 类型的对象上. 如果对象不是 NF3LNK 类型, 服务器应返回错误 NFS3ERR_INVAL.

ERRORS

NFS3ERR_IO
NFS3ERR_INVAL
NFS3ERR_ACCES
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT

SEE ALSO

READLINK, SYMLINK.

3.3.6 过程 6: READ - 从文件读取 (Read From file)

SYNOPSIS

READ3res NFSPROC3_READ(READ3args) = 6;

struct READ3args {
nfs_fh3 file;
offset3 offset;
count3 count;
};

struct READ3resok {
post_op_attr file_attributes;
count3 count;
bool eof;
opaque data<>;
};

struct READ3resfail {
post_op_attr file_attributes;
};

union READ3res switch (nfsstat3 status) {
case NFS3_OK:
READ3resok resok;
default:
READ3resfail resfail;
};

DESCRIPTION

READ 过程从文件读取数据. 进入时, READ3args 中的参数为:

  • file: 要从中读取数据的文件的文件句柄. 这必须标识 NF3REG 类型的文件系统对象.
  • offset: 文件中开始读取的位置. 偏移量为0表示从文件开头开始读取数据. 如果偏移量大于或等于文件大小, 则返回状态 NFS3_OK, count 设置为0, eof 设置为 TRUE, 但需进行访问权限检查.
  • count: 要读取的数据字节数. 如果 count 为0, READ 将成功并返回0字节数据, 但需进行访问权限检查. count 必须小于或等于文件所在文件系统的 FSINFO 回复结构中 rtmax 字段的值. 如果更大, 服务器可能只返回 rtmax 字节, 导致短读.

成功返回时, READ3res.status 为 NFS3_OK, READ3res.resok 包含:

  • file_attributes: 读取完成时文件的属性.
  • count: 读取返回的数据字节数.
  • eof: 如果读取在文件末尾结束 (正式地, 在正确形成的 READ 请求中, 如果 READ3args.offset 加上 READ3resok.count 等于文件大小), eof 返回为 TRUE; 否则为 FALSE. 对空文件的成功 READ 将始终返回 eof 为 TRUE.
  • data: 从文件读取的计数数据.

否则, READ3res.status 包含失败时的错误, READ3res.resfail 包含:

  • file_attributes: 文件的操作后属性.

IMPLEMENTATION

NFS 版本2协议中用于 READ 和 WRITE 操作的 nfsdata 类型定义请求或回复的数据部分, 已更改为可变长度不透明字节数组. 协议允许的最大大小现在受 XDR 和底层传输允许的限制. NFS 版本3协议没有施加任何人为限制. 有关详细信息, 请参阅 FSINFO 过程描述.

服务器可能返回少于 count 字节的数据. 如果服务器返回少于请求的计数且 eof 设置为 FALSE, 客户端应发出另一个 READ 以获取剩余数据. 服务器在几种情况下可能返回少于请求的数据. 文件可能已被另一个客户端或服务器本身截断, 改变了请求客户端认为的文件大小. 这将减少客户端实际可用的数据量. 服务器可能会退回传输大小并减少读取请求返回. 服务器资源耗尽也可能发生, 需要较小的读取返回.

某些 NFS 版本2协议客户端实现选择将短读响应解释为指示 EOF. NFS 版本3协议中添加的 eof 标志提供了正确处理 EOF 的方法.

ERRORS

NFS3ERR_IO
NFS3ERR_NXIO
NFS3ERR_ACCES
NFS3ERR_INVAL
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

READLINK.

3.3.7 过程 7: WRITE - 写入文件 (Write to file)

SYNOPSIS

WRITE3res NFSPROC3_WRITE(WRITE3args) = 7;

enum stable_how {
UNSTABLE = 0,
DATA_SYNC = 1,
FILE_SYNC = 2
};

struct WRITE3args {
nfs_fh3 file;
offset3 offset;
count3 count;
stable_how stable;
opaque data<>;
};

struct WRITE3resok {
wcc_data file_wcc;
count3 count;
stable_how committed;
writeverf3 verf;
};

struct WRITE3resfail {
wcc_data file_wcc;
};

union WRITE3res switch (nfsstat3 status) {
case NFS3_OK:
WRITE3resok resok;
default:
WRITE3resfail resfail;
};

DESCRIPTION

WRITE 过程将数据写入文件. 进入时, WRITE3args 中的参数为:

  • file: 要写入数据的文件的文件句柄. 这必须标识 NF3REG 类型的文件系统对象.
  • offset: 文件中开始写入的位置. 偏移量为0表示从文件开头开始写入数据.
  • count: 要写入的数据字节数. 如果 count 为0, WRITE 将成功并返回计数0, 除非由于权限检查导致的错误. 数据大小必须小于或等于文件所在文件系统的 FSINFO 回复结构中 wtmax 字段的值. 如果更大, 服务器可能只写入 wtmax 字节, 导致短写.
  • stable: 如果 stable 为 FILE_SYNC, 服务器必须在返回结果之前将写入的数据加上所有文件系统元数据提交到稳定存储. 这对应于 NFS 版本2协议语义. 任何其他行为都构成协议违规. 如果 stable 为 DATA_SYNC, 则服务器必须在返回之前将所有数据提交到稳定存储以及足够的元数据以检索数据. 服务器实现者可以以与 FILE_SYNC 相同的方式自由实现 DATA_SYNC, 但可能会有性能下降. 如果 stable 为 UNSTABLE, 服务器可以在返回客户端回复之前自由地将数据和元数据的任何部分提交到稳定存储, 包括全部或全不. 不保证任何未提交的数据何时或是否随后会被提交到稳定存储. 服务器做出的唯一保证是它不会在不更改 verf 值的情况下销毁任何数据, 并且不会以低于客户端请求的级别提交数据和元数据.
  • data: 要写入文件的数据.

成功返回时, WRITE3res.status 为 NFS3_OK, WRITE3res.resok 包含:

  • file_wcc: 文件的弱缓存一致性数据. 对于只需要写后文件属性的客户端, 可以在 file_wcc.after 中找到.
  • count: 写入文件的数据字节数. 服务器可能写入少于请求的字节数. 如果是这样, 则返回从位置 offset 开始写入的实际字节数.
  • committed: 服务器应通过 committed 返回数据和元数据的提交级别指示. 如果服务器将所有数据和元数据提交到稳定存储, committed 应设置为 FILE_SYNC. 如果提交级别至少与 DATA_SYNC 一样强, 则 committed 应设置为 DATA_SYNC. 否则, committed 必须返回为 UNSTABLE. 如果 stable 为 FILE_SYNC, 则 committed 也必须为 FILE_SYNC: 任何其他情况都构成协议违规. 如果 stable 为 DATA_SYNC, 则 committed 可以为 FILE_SYNC 或 DATA_SYNC: 任何其他情况都构成协议违规. 如果 stable 为 UNSTABLE, 则 committed 可以为 FILE_SYNC、DATA_SYNC 或 UNSTABLE.
  • verf: 这是一个 cookie, 客户端可以使用它来确定服务器是否在 WRITE 调用和后续 WRITE 或 COMMIT 调用之间更改了状态. 此 cookie 在 NFS 版本3协议服务的单个实例期间必须一致, 并且在 NFS 版本3协议服务器的实例之间必须唯一, 其中未提交的数据可能会丢失.

否则, WRITE3res.status 包含失败时的错误, WRITE3res.resfail 包含:

  • file_wcc: 文件的弱缓存一致性数据. 即使写入失败, 也会返回完整的 wcc_data, 以允许客户端确定失败的写入是否导致文件发生任何更改.

IMPLEMENTATION

NFS 版本3协议引入了安全异步写入. WRITE 与 stable 设置为 UNSTABLE 结合 COMMIT 解决了 NFS 版本2协议中发现的性能瓶颈, 即需要同步将所有写入提交到稳定存储.

稳定存储的定义历来是争议点. 以下稳定存储的预期属性可能有助于解决实现中的设计问题. 稳定存储是能够在以下情况下存活的持久存储:

  1. 重复断电.
  2. 硬件故障 (任何板、电源等).
  3. 重复软件崩溃, 包括重启周期.

此定义不涉及稳定存储模块本身的故障.

定义了 cookie verf, 以允许客户端检测 NFS 版本3协议服务器的不同实例, 在这些实例中缓存的未提交数据可能会丢失. 在最可能的情况下, verf 允许客户端检测服务器重启. 此信息是必需的, 以便客户端可以安全地确定服务器是否可能丢失了缓存数据.

ERRORS

NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_FBIG
NFS3ERR_DQUOT
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_INVAL
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

COMMIT. test