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.
-
文件名不得为 null, 也不得为空字符串. 如果服务器收到这样的文件名, 应返回错误 NFS3ERR_ACCES. 在某些客户端上, 文件名
''或空字符串被假定为当前目录的别名. 需要此功能的客户端应自行实现, 而不依赖服务器支持此类语义. -
值为 "." 的文件名被假定为当前目录的别名. 需要此功能的客户端应自行实现, 而不依赖服务器支持此类语义. 但是, 服务器应能够正确处理此类文件名.
-
值为 ".." 的文件名被假定为当前目录父目录的别名, 即包含当前目录的目录. 服务器应准备好处理此语义 (如果它支持目录), 即使这些目录不包含 UNIX 风格的 "." 或 ".." 条目.
-
如果文件名长于文件系统的最大值 (参见 PATHCONF, 特别是 name_max), 则结果取决于 PATHCONF 标志 no_trunc 的值. 如果 no_trunc 为 FALSE, 文件名将被静默截断为 name_max 字节. 如果 no_trunc 为 TRUE 且文件名超过服务器文件系统最大文件名长度, 操作将失败并返回错误 NFS3ERR_NAMETOOLONG.
-
通常, 服务器无法处理某些字符作为文件名的一部分. 这组字符因服务器和实现而异. 在大多数情况下, 是服务器控制客户端对文件系统的视图. 如果服务器收到包含其无法处理的字符的文件名, 应返回错误 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.
3.3.5 过程 5: READLINK - 从符号链接读取 (Read from symbolic link)
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协议中发现的性能瓶颈, 即需要同步将所有写入提交到稳定存储.
稳定存储的定义历来是争议点. 以下稳定存储的预期属性可能有助于解决实现中的设计问题. 稳定存储是能够在以下情况下存活的持久存储:
- 重复断电.
- 硬件故障 (任何板、电源等).
- 重复软件崩溃, 包括重启周期.
此定义不涉及稳定存储模块本身的故障.
定义了 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.
3.3.8 过程 8: CREATE - 创建文件 (Create a file)
SYNOPSIS
CREATE3res NFSPROC3_CREATE(CREATE3args) = 8;
enum createmode3 \\\{
UNCHECKED = 0,
GUARDED = 1,
EXCLUSIVE = 2
\\\};
union createhow3 switch (createmode3 mode) \\\{
case UNCHECKED:
case GUARDED:
sattr3 obj_attributes;
case EXCLUSIVE:
createverf3 verf;
\\\};
struct CREATE3args \\\{
diropargs3 where;
createhow3 how;
\\\};
struct CREATE3resok \\\{
post_op_fh3 obj;
post_op_attr obj_attributes;
wcc_data dir_wcc;
\\\};
struct CREATE3resfail \\\{
wcc_data dir_wcc;
\\\};
union CREATE3res switch (nfsstat3 status) \\\{
case NFS3_OK:
CREATE3resok resok;
default:
CREATE3resfail resfail;
\\\};
DESCRIPTION
过程 CREATE 创建一个普通文件. 进入时, CREATE3args 中的参数为:
where : 要创建的文件的位置:
dir : 文件将在其中创建的目录的文件句柄.
name : 要与所创建文件关联的名称. 参见第 30 页关于文件名的一般说明.
创建普通文件时, 有三种创建方式, 由以下字段定义:
how : 一个可区分联合 (discriminated union), 描述服务器应如何处理文件创建以及相应的属性:
mode : UNCHECKED, GUARDED 和 EXCLUSIVE 之一. UNCHECKED 表示创建文件时不检查同一目录中是否存在重复文件. 在这种情况下, how.obj_attributes 是一个 sattr3, 描述该文件的初始属性. GUARDED 指定服务器应在执行创建前检查是否存在重复文件, 如果存在重复文件, 则应以 NFS3ERR_EXIST 使请求失败. 如果文件不存在, 则按 UNCHECKED 所述执行请求. EXCLUSIVE 指定服务器应遵循独占创建语义, 使用校验器确保目标的独占创建. 在这种情况下不得提供属性, 因为服务器可能使用目标文件元数据来存储 createverf3 校验器.
成功返回时, CREATE3res.status 为 NFS3_OK, CREATE3res.resok 中的结果为:
obj : 新创建普通文件的文件句柄.
obj_attributes : 刚创建的普通文件的属性.
dir_wcc : 目录 where.dir 的弱缓存一致性 (weak cache consistency) 数据. 对于只需要 CREATE 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性.
否则, CREATE3res.status 包含失败时的错误, CREATE3res.resfail 包含以下内容:
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 CREATE 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性. 即使 CREATE 失败, 也会返回完整的 wcc_data, 以便客户端确定失败的 CREATE 是否导致目录发生任何更改.
IMPLEMENTATION
不同于 NFS version 2 protocol, 在该协议中初始属性结构中的某些字段被重载, 用于指示除普通文件外还创建设备和 FIFO, 此过程仅支持创建普通文件. NFS version 3 protocol 引入了 MKNOD 过程来处理设备和 FIFO 的创建. 在 NFS version 3 protocol 中, 实现没有理由重载 CREATE 语义.
NFS version 3 protocol 的 CREATE 过程有一个方面需要特别仔细考虑: 为支持可靠的普通文件独占创建而引入的机制. 当 how.mode 为 EXCLUSIVE 时, 该机制开始发挥作用. 在这种情况下, how.verf 包含一个可以合理预期为唯一的校验器. 客户端标识符 (可能是客户端网络地址) 与客户端生成的唯一数字 (可能是 RPC 事务标识符) 的组合可能是合适的.
如果文件不存在, 服务器创建该文件并将校验器存储在稳定存储 (stable storage) 中. 对于不提供任意文件属性存储机制的文件系统, 服务器可以使用文件元数据的一个或多个元素来存储校验器. 校验器必须存储在稳定存储中, 以防止请求重传时发生错误失败. 假定正在执行独占创建, 是因为独占语义对应用程序至关重要. 由于预期用途如此, 独占 CREATE 不会仅依赖通常易失的重复请求缓存来存储校验器. 易失存储中的重复请求缓存无法在崩溃后保留, 并且在长时间网络分区时实际上可能被刷新, 从而打开失败窗口. 在 UNIX 本地文件系统环境中, 创建时校验器的预期存储位置是文件的元数据 (时间戳). 因此, 独占文件创建不得包含初始属性, 因为服务器将没有位置存储校验器.
如果服务器无法支持这些独占创建语义, 可能是因为需要将校验器提交到稳定存储, 则它应以错误 NFS3ERR_NOTSUPP 使 CREATE 请求失败.
在独占 CREATE 请求期间, 如果文件已存在, 服务器会重构文件的校验器, 并将其与请求中的校验器进行比较. 如果二者匹配, 服务器将该请求视为成功. 该请求被推定为先前某个成功请求的重复请求, 该成功请求的应答已丢失, 且服务器重复请求缓存机制未检测到它. 如果校验器不匹配, 则以状态 NFS3ERR_EXIST 拒绝该请求.
一旦客户端完成了一次成功的独占创建, 它必须发出 SETATTR 来设置正确的文件属性. 在此之前, 它不应依赖任何文件属性, 因为服务器实现可能需要重载文件元数据以存储校验器.
使用 GUARDED 属性并不提供 exactly-once 语义. 特别是, 如果应答丢失且服务器未检测到请求的重传, 即使创建已成功执行, 该过程也可能以 NFS3ERR_EXIST 失败.
参见第 30 页关于文件名的一般说明.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_EXIST
NFS3ERR_NOTDIR
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_NAMETOOLONG
NFS3ERR_DQUOT
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
MKDIR, SYMLINK, MKNOD, and PATHCONF.
3.3.9 过程 9: MKDIR - 创建目录 (Create a directory)
SYNOPSIS
MKDIR3res NFSPROC3_MKDIR(MKDIR3args) = 9;
struct MKDIR3args \\\{
diropargs3 where;
sattr3 attributes;
\\\};
struct MKDIR3resok \\\{
post_op_fh3 obj;
post_op_attr obj_attributes;
wcc_data dir_wcc;
\\\};
struct MKDIR3resfail \\\{
wcc_data dir_wcc;
\\\};
union MKDIR3res switch (nfsstat3 status) \\\{
case NFS3_OK:
MKDIR3resok resok;
default:
MKDIR3resfail resfail;
\\\};
DESCRIPTION
过程 MKDIR 创建一个新的子目录. 进入时, MKDIR3args 中的参数为:
where : 要创建的子目录的位置:
dir : 子目录将在其中创建的目录的文件句柄.
name : 要与所创建子目录关联的名称. 参见第 30 页关于文件名的一般说明.
attributes : 子目录的初始属性.
成功返回时, MKDIR3res.status 为 NFS3_OK, MKDIR3res.resok 中的结果为:
obj : 新创建目录的文件句柄.
obj_attributes : 新创建子目录的属性.
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 MKDIR 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性.
否则, MKDIR3res.status 包含失败时的错误, MKDIR3res.resfail 包含以下内容:
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 MKDIR 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性. 即使 MKDIR 失败, 也会返回完整的 wcc_data, 以便客户端确定失败的 MKDIR 是否导致目录发生任何更改.
IMPLEMENTATION
许多服务器实现不允许将文件名 "." 或 ".." 用作 MKDIR 操作中的目标. 在这种情况下, 服务器应返回 NFS3ERR_EXIST. 参见第 30 页关于文件名的一般说明.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_EXIST
NFS3ERR_NOTDIR
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_NAMETOOLONG
NFS3ERR_DQUOT
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
CREATE, SYMLINK, MKNOD, and PATHCONF.
3.3.10 过程 10: SYMLINK - 创建符号链接 (Create a symbolic link)
SYNOPSIS
SYMLINK3res NFSPROC3_SYMLINK(SYMLINK3args) = 10;
struct symlinkdata3 \\\{
sattr3 symlink_attributes;
nfspath3 symlink_data;
\\\};
struct SYMLINK3args \\\{
diropargs3 where;
symlinkdata3 symlink;
\\\};
struct SYMLINK3resok \\\{
post_op_fh3 obj;
post_op_attr obj_attributes;
wcc_data dir_wcc;
\\\};
struct SYMLINK3resfail \\\{
wcc_data dir_wcc;
\\\};
union SYMLINK3res switch (nfsstat3 status) \\\{
case NFS3_OK:
SYMLINK3resok resok;
default:
SYMLINK3resfail resfail;
\\\};
DESCRIPTION
过程 SYMLINK 创建一个新的符号链接. 进入时, SYMLINK3args 中的参数为:
where : 要创建的符号链接的位置:
dir : 符号链接将在其中创建的目录的文件句柄.
name : 要与所创建符号链接关联的名称. 参见第 30 页关于文件名的一般说明.
symlink : 要创建的符号链接:
symlink_attributes : 符号链接的初始属性.
symlink_data : 包含符号链接数据的字符串.
成功返回时, SYMLINK3res.status 为 NFS3_OK, SYMLINK3res.resok 包含:
obj : 新创建符号链接的文件句柄.
obj_attributes : 新创建符号链接的属性.
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 SYMLINK 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性.
否则, SYMLINK3res.status 包含失败时的错误, SYMLINK3res.resfail 包含以下内容:
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 SYMLINK 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性. 即使 SYMLINK 失败, 也会返回完整的 wcc_data, 以便客户端确定失败的 SYMLINK 是否更改了目录.
IMPLEMENTATION
参见第 30 页关于文件名的一般说明.
对于符号链接, 预期实际的文件系统节点及其内容会在单个原子操作中创建. 也就是说, 一旦符号链接可见, 就不得存在 READLINK 会失败或返回错误数据的窗口.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_EXIST
NFS3ERR_NOTDIR
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_NAMETOOLONG
NFS3ERR_DQUOT
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
READLINK, CREATE, MKDIR, MKNOD, FSINFO, and PATHCONF.
3.3.11 过程 11: MKNOD - 创建特殊设备 (Create a special device)
SYNOPSIS
MKNOD3res NFSPROC3_MKNOD(MKNOD3args) = 11;
struct devicedata3 \\\{
sattr3 dev_attributes;
specdata3 spec;
\\\};
union mknoddata3 switch (ftype3 type) \\\{
case NF3CHR:
case NF3BLK:
devicedata3 device;
case NF3SOCK:
case NF3FIFO:
sattr3 pipe_attributes;
default:
void;
\\\};
struct MKNOD3args \\\{
diropargs3 where;
mknoddata3 what;
\\\};
struct MKNOD3resok \\\{
post_op_fh3 obj;
post_op_attr obj_attributes;
wcc_data dir_wcc;
\\\};
struct MKNOD3resfail \\\{
wcc_data dir_wcc;
\\\};
union MKNOD3res switch (nfsstat3 status) \\\{
case NFS3_OK:
MKNOD3resok resok;
default:
MKNOD3resfail resfail;
\\\};
DESCRIPTION
过程 MKNOD 创建一个类型为 what.type 的新特殊文件. 特殊文件可以是设备文件或命名管道. 进入时, MKNOD3args 中的参数为:
where : 要创建的特殊文件的位置:
dir : 特殊文件将在其中创建的目录的文件句柄.
name : 要与所创建特殊文件关联的名称. 参见第 30 页关于文件名的一般说明.
what : 一个可区分联合, 标识要创建的特殊文件类型, 以及适合该特殊文件类型的数据和属性:
type : 要创建的对象的类型.
创建字符特殊文件 (what.type 为 NF3CHR) 或块特殊文件 (what.type 为 NF3BLK) 时, what 包含:
device : 一个 devicedata3 结构, 包含以下组成部分:
dev_attributes : 特殊文件的初始属性.
spec : 主设备号存储在 device.spec.specdata1 中, 次设备号存储在 device.spec.specdata2 中.
创建套接字 (what.type 为 NF3SOCK) 或 FIFO (what.type 为 NF3FIFO) 时, what 包含:
pipe_attributes : 特殊文件的初始属性.
成功返回时, MKNOD3res.status 为 NFS3_OK, MKNOD3res.resok 包含:
obj : 新创建特殊文件的文件句柄.
obj_attributes : 新创建特殊文件的属性.
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 MKNOD 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性.
否则, MKNOD3res.status 包含失败时的错误, MKNOD3res.resfail 包含以下内容:
dir_wcc : 目录 where.dir 的弱缓存一致性数据. 对于只需要 MKNOD 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性. 即使 MKNOD 失败, 也会返回完整的 wcc_data, 以便客户端确定失败的 MKNOD 是否更改了目录.
IMPLEMENTATION
参见第 30 页关于文件名的一般说明.
由于 NFS version 2 protocol 不显式支持创建特殊文件类型, CREATE 参数中的字段曾被重载, 用于指示创建某些类型的对象. 在 NFS version 3 protocol 中, 这种重载并非必要.
如果服务器不支持任何已定义类型, 则应返回错误 NFS3ERR_NOTSUPP. 否则, 如果服务器不支持目标类型或目标类型非法, 则应返回错误 NFS3ERR_BADTYPE. 注意, NF3REG, NF3DIR 和 NF3LNK 对于 MKNOD 是非法类型. 应分别使用过程 CREATE, MKDIR 和 SYMLINK 来创建这些文件类型, 而不是使用 MKNOD.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_EXIST
NFS3ERR_NOTDIR
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_NAMETOOLONG
NFS3ERR_DQUOT
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
NFS3ERR_BADTYPE
SEE ALSO
CREATE, MKDIR, SYMLINK, and PATHCONF.
3.3.12 过程 12: REMOVE - 删除文件 (Remove a File)
SYNOPSIS
REMOVE3res NFSPROC3_REMOVE(REMOVE3args) = 12;
struct REMOVE3args \\\{
diropargs3 object;
\\\};
struct REMOVE3resok \\\{
wcc_data dir_wcc;
\\\};
struct REMOVE3resfail \\\{
wcc_data dir_wcc;
\\\};
union REMOVE3res switch (nfsstat3 status) \\\{
case NFS3_OK:
REMOVE3resok resok;
default:
REMOVE3resfail resfail;
\\\};
DESCRIPTION
过程 REMOVE 从目录中移除 (删除) 一个条目. 如果目录中的该条目是对应文件系统对象的最后一个引用, 则该对象可能被销毁. 进入时, REMOVE3args 中的参数为:
object : 一个 diropargs3 结构, 标识要移除的条目:
dir : 要从其中移除条目的目录的文件句柄.
name : 要移除的条目的名称. 参见第 30 页关于文件名的一般说明.
成功返回时, REMOVE3res.status 为 NFS3_OK, REMOVE3res.resok 包含:
dir_wcc : 目录 object.dir 的弱缓存一致性数据. 对于只需要 REMOVE 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性.
否则, REMOVE3res.status 包含失败时的错误, REMOVE3res.resfail 包含以下内容:
dir_wcc : 目录 object.dir 的弱缓存一致性数据. 对于只需要 REMOVE 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性. 即使 REMOVE 失败, 也会返回完整的 wcc_data, 以便客户端确定失败的 REMOVE 是否更改了目录.
IMPLEMENTATION
一般来说, REMOVE 旨在移除非目录文件对象, 而 RMDIR 用于移除目录. 然而, REMOVE 可以用于移除目录, 但受客户端或服务器接口施加的限制约束. 这曾是 NFS version 2 protocol 中的一个混淆来源.
最后引用 (last reference) 的概念由服务器特定定义. 但是, 如果对象先前属性中的 nlink 字段值为 1, 客户端不应依赖通过文件句柄引用该对象. 同样, 客户端不应依赖先前与该对象关联的资源 (磁盘空间, 目录条目等) 立即变为可用. 因此, 如果客户端在使用 REMOVE 移除文件后仍需要能够继续访问该文件, 客户端应采取措施确保该文件仍可访问. 通常使用的机制是用 RENAME 将文件从旧名称重命名为新的隐藏名称.
参见第 30 页关于文件名的一般说明.
ERRORS
NFS3ERR_NOENT
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_NAMETOOLONG
NFS3ERR_ROFS
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
SEE ALSO
RMDIR and RENAME.
3.3.13 过程 13: RMDIR - 删除目录 (Remove a Directory)
SYNOPSIS
RMDIR3res NFSPROC3_RMDIR(RMDIR3args) = 13;
struct RMDIR3args \\\{
diropargs3 object;
\\\};
struct RMDIR3resok \\\{
wcc_data dir_wcc;
\\\};
struct RMDIR3resfail \\\{
wcc_data dir_wcc;
\\\};
union RMDIR3res switch (nfsstat3 status) \\\{
case NFS3_OK:
RMDIR3resok resok;
default:
RMDIR3resfail resfail;
\\\};
DESCRIPTION
过程 RMDIR 从目录中移除 (删除) 一个子目录. 如果该子目录的目录条目是该子目录的最后一个引用, 则该子目录可能被销毁. 进入时, RMDIR3args 中的参数为:
object : 一个 diropargs3 结构, 标识要移除的目录条目:
dir : 要从其中移除子目录的目录的文件句柄.
name : 要移除的子目录的名称. 参见第 30 页关于文件名的一般说明.
成功返回时, RMDIR3res.status 为 NFS3_OK, RMDIR3res.resok 包含:
dir_wcc : 目录 object.dir 的弱缓存一致性数据. 对于只需要 RMDIR 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性.
否则, RMDIR3res.status 包含失败时的错误, RMDIR3res.resfail 包含以下内容:
dir_wcc : 目录 object.dir 的弱缓存一致性数据. 对于只需要 RMDIR 后目录属性的客户端, 可在 dir_wcc.after 中找到这些属性. 注意, 即使 RMDIR 失败, 也会返回完整的 wcc_data, 以便客户端确定失败的 RMDIR 是否更改了目录.
IMPLEMENTATION
注意, 在某些服务器上, 不允许移除非空目录.
在某些服务器上, 文件名 "." 是非法的. 这些服务器将返回错误 NFS3ERR_INVAL. 在某些服务器上, 文件名 ".." 是非法的. 这些服务器将返回错误 NFS3ERR_EXIST. 这看起来似乎不一致, 但允许这些服务器遵循它们自身特定的接口定义. 客户端应准备好处理这两种情况.
客户端不应依赖先前与该目录关联的资源 (磁盘空间, 目录条目等) 立即变为可用.
ERRORS
NFS3ERR_NOENT
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_INVAL
NFS3ERR_EXIST
NFS3ERR_NOTDIR
NFS3ERR_NAMETOOLONG
NFS3ERR_ROFS
NFS3ERR_NOTEMPTY
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
REMOVE.
3.3.14 过程 14: RENAME - 重命名文件或目录 (Rename a File or Directory)
SYNOPSIS
RENAME3res NFSPROC3_RENAME(RENAME3args) = 14;
struct RENAME3args \\\{
diropargs3 from;
diropargs3 to;
\\\};
struct RENAME3resok \\\{
wcc_data fromdir_wcc;
wcc_data todir_wcc;
\\\};
struct RENAME3resfail \\\{
wcc_data fromdir_wcc;
wcc_data todir_wcc;
\\\};
union RENAME3res switch (nfsstat3 status) \\\{
case NFS3_OK:
RENAME3resok resok;
default:
RENAME3resfail resfail;
\\\};
DESCRIPTION
过程 RENAME 将目录 from.dir 中由 from.name 标识的文件重命名为目录 to.dir 中的 to.name. 对客户端而言, 该操作要求是原子的. To.dir 和 from.dir 必须位于同一文件系统和同一服务器上. 进入时, RENAME3args 中的参数为:
from : 一个 diropargs3 结构, 标识源 (要重命名的文件系统对象):
from.dir : 要从其中重命名条目的目录的文件句柄.
from.name : 标识要重命名对象的条目名称. 参见第 30 页关于文件名的一般说明.
to : 一个 diropargs3 结构, 标识目标 (对象的新名称):
to.dir : 对象将被重命名到其中的目录的文件句柄.
to.name : 对象的新名称. 参见第 30 页关于文件名的一般说明.
如果目录 to.dir 已包含名为 to.name 的条目, 则源对象必须与目标兼容: 要么二者都不是目录, 要么二者都是目录且目标必须为空. 如果兼容, 则在重命名发生前移除现有目标. 如果不兼容, 或目标是目录但非空, 服务器应返回错误 NFS3ERR_EXIST.
成功返回时, RENAME3res.status 为 NFS3_OK, RENAME3res.resok 包含:
fromdir_wcc : 目录 from.dir 的弱缓存一致性数据.
todir_wcc : 目录 to.dir 的弱缓存一致性数据.
否则, RENAME3res.status 包含失败时的错误, RENAME3res.resfail 包含以下内容:
fromdir_wcc : 目录 from.dir 的弱缓存一致性数据.
todir_wcc : 目录 to.dir 的弱缓存一致性数据.
IMPLEMENTATION
RENAME 操作对客户端而言必须是原子的. 消息 "to.dir and from.dir must reside on the same file system on the server, [or the operation will fail]" 表示这些目录属性中的 fsid 字段相同. 如果它们位于不同文件系统, 则返回错误 NFS3ERR_XDEV. 即使该操作是原子的, 如果服务器内部使用了 "unlink/link/unlink" 序列, 也可能返回状态 NFS3ERR_MLINK.
文件句柄在重命名时可能变为陈旧, 也可能不会. 然而, 强烈建议服务器实现者尝试避免文件句柄以这种方式变为陈旧.
在某些服务器上, 文件名 "." 和 ".." 作为 from.name 或 to.name 都是非法的. 此外, from.name 和 to.name 都不能是 from.dir 的别名. 在这些情况下, 这些服务器将返回错误 NFS3ERR_INVAL.
如果 from 和 to 都引用同一个文件 (它们可能互为硬链接), 则 RENAME 应不执行任何操作并返回 NFS3_OK.
参见第 30 页关于文件名的一般说明.
ERRORS
NFS3ERR_NOENT
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_EXIST
NFS3ERR_XDEV
NFS3ERR_NOTDIR
NFS3ERR_ISDIR
NFS3ERR_INVAL
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_MLINK
NFS3ERR_NAMETOOLONG
NFS3ERR_NOTEMPTY
NFS3ERR_DQUOT
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
REMOVE and LINK.
3.3.15 过程 15: LINK - 创建到对象的链接 (Create Link to an object)
SYNOPSIS
LINK3res NFSPROC3_LINK(LINK3args) = 15;
struct LINK3args \\\{
nfs_fh3 file;
diropargs3 link;
\\\};
struct LINK3resok \\\{
post_op_attr file_attributes;
wcc_data linkdir_wcc;
\\\};
struct LINK3resfail \\\{
post_op_attr file_attributes;
wcc_data linkdir_wcc;
\\\};
union LINK3res switch (nfsstat3 status) \\\{
case NFS3_OK:
LINK3resok resok;
default:
LINK3resfail resfail;
\\\};
DESCRIPTION
过程 LINK 从 file 到目录 link.dir 中的 link.name 创建一个硬链接. file 和 link.dir 必须位于同一文件系统和同一服务器上. 进入时, LINK3args 中的参数为:
file : 现有文件系统对象的文件句柄.
link : 要创建的链接的位置:
link.dir : 链接将在其中创建的目录的文件句柄.
link.name : 要与所创建链接关联的名称. 参见第 17 页关于文件名的一般说明.
成功返回时, LINK3res.status 为 NFS3_OK, LINK3res.resok 包含:
file_attributes : 由 file 标识的文件系统对象的操作后属性.
linkdir_wcc : 目录 link.dir 的弱缓存一致性数据.
否则, LINK3res.status 包含失败时的错误, LINK3res.resfail 包含以下内容:
file_attributes : 由 file 标识的文件系统对象的操作后属性.
linkdir_wcc : 目录 link.dir 的弱缓存一致性数据.
IMPLEMENTATION
对硬链接文件的任何属性所做的更改都会反映到所有链接文件中. 当为一个文件创建硬链接时, 该文件属性中的 nlink 值应比 LINK 之前的值大 1.
RENAME 下关于对象和目标位于同一文件系统的说明同样适用于此处. 关于目标名称的说明也同样适用. 参见第 30 页关于文件名的一般说明.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_EXIST
NFS3ERR_XDEV
NFS3ERR_NOTDIR
NFS3ERR_INVAL
NFS3ERR_NOSPC
NFS3ERR_ROFS
NFS3ERR_MLINK
NFS3ERR_NAMETOOLONG
NFS3ERR_DQUOT
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
SYMLINK, RENAME and FSINFO.
3.3.16 过程 16: READDIR - 从目录读取 (Read From Directory)
SYNOPSIS
READDIR3res NFSPROC3_READDIR(READDIR3args) = 16;
struct READDIR3args \\\{
nfs_fh3 dir;
cookie3 cookie;
cookieverf3 cookieverf;
count3 count;
\\\};
struct entry3 \\\{
fileid3 fileid;
filename3 name;
cookie3 cookie;
entry3 *nextentry;
\\\};
struct dirlist3 \\\{
entry3 *entries;
bool eof;
\\\};
struct READDIR3resok \\\{
post_op_attr dir_attributes;
cookieverf3 cookieverf;
dirlist3 reply;
\\\};
struct READDIR3resfail \\\{
post_op_attr dir_attributes;
\\\};
union READDIR3res switch (nfsstat3 status) \\\{
case NFS3_OK:
READDIR3resok resok;
default:
READDIR3resfail resfail;
\\\};
DESCRIPTION
READDIR 过程从目录中按顺序检索数量可变的条目, 并返回每个条目的名称和文件标识符, 同时返回相关信息, 以便客户端在后续 READDIR 请求中请求更多目录条目. 进入时, READDIR3args 中的参数为:
dir
要读取的目录的文件句柄.
cookie
在读取目录的第一个请求中, 该值应设置为 0. 在后续请求中, 它应为服务器返回的 cookie.
cookieverf
在读取目录的第一个请求中, 该值应设置为 0. 在后续请求中, 它应为服务器返回的 cookieverf. cookieverf 必须与获取该 cookie 的 READDIR 所返回的值匹配.
count
READDIR3resok 结构的最大大小, 以字节为单位. 该大小必须包含所有 XDR 开销. 服务器可以自由返回少于 count 字节的数据.
成功返回时, READDIR3res.status 为 NFS3_OK, 且 READDIR3res.resok 包含:
dir_attributes
目录 dir 的属性.
cookieverf
Cookie 验证器.
reply
目录列表:
entries
零个或多个目录 (entry3) 条目.
eof
如果 reply.entries 的最后一个成员是目录中的最后一个条目, 或者列表 reply.entries 为空且 cookie 对应目录末尾, 则为 TRUE. 如果为 FALSE, 则可能还有更多条目可读取.
否则, READDIR3res.status 包含失败时的错误, READDIR3res.resfail 包含以下内容:
dir_attributes
目录 dir 的属性.
IMPLEMENTATION
在 NFS version 2 协议中, 返回的每个目录条目都包含一个 cookie, 用于标识目录中的某个位置. 通过在后续 READDIR 中包含此 cookie, 客户端可以从目录中的任意位置继续读取目录. 这种方案的一个问题是, 服务器没有简单的方法来验证 cookie 是否有效. 如果两个 READDIR 之间夹杂了一个或多个以某种方式更改目录的操作 (例如重新排序或压缩目录), 第二个 READDIR 就可能漏掉条目, 或多次处理某些条目. 如果 cookie 不再可用, 例如指向某个目录条目的中间位置, 服务器就必须将 cookie 向下舍入到前一个条目的 cookie, 或向上舍入到目录中下一个条目的 cookie. 无论哪种方式都可能导致错误结果, 而客户端不会意识到存在任何问题.
在 NFS version 3 协议中, 每个 READDIR 请求都同时包含 cookie 和 cookie 验证器. 第一次调用时, 两者都设置为 0. 响应包含一个新的 cookie 验证器, 并为每个条目提供一个 cookie. 对于后续 READDIR, 客户端必须同时提供 cookie 及对应的 cookie 验证器. 如果服务器检测到 cookie 不再有效, 服务器将以状态 NFS3ERR_BAD_COOKIE 拒绝 READDIR 请求. 客户端应注意避免跨越会修改目录内容的操作持有目录条目 cookie, 例如 REMOVE 和 CREATE.
cookie 验证器机制的一种实现方式是让服务器使用目录的修改时间. 但这可能过于严格. 更好的方法是记录上一次目录修改的时间, 该修改以某种方式改变了目录组织, 从而使可靠解释 cookie 变得不可能. 对于目录 cookie 始终有效的服务器, 可以始终使用零作为验证器.
服务器可以返回少于 count 字节的 XDR 编码条目. 客户端在请求中指定的 count 应大于或等于 FSINFO dtpref.
由于 UNIX 客户端对 fileid 值零赋予特殊含义, UNIX 客户端应注意将零 fileid 值映射为其他值, 服务器也应尽量避免发送零 fileid.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_BAD_COOKIE
NFS3ERR_TOOSMALL
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
SEE ALSO
READDIRPLUS and FSINFO.
3.3.17 过程 17: READDIRPLUS - 从目录扩展读取 (Extended read from directory)
SYNOPSIS
READDIRPLUS3res NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17;
struct READDIRPLUS3args \\\{
nfs_fh3 dir;
cookie3 cookie;
cookieverf3 cookieverf;
count3 dircount;
count3 maxcount;
\\\};
struct entryplus3 \\\{
fileid3 fileid;
filename3 name;
cookie3 cookie;
post_op_attr name_attributes;
post_op_fh3 name_handle;
entryplus3 *nextentry;
\\\};
struct dirlistplus3 \\\{
entryplus3 *entries;
bool eof;
\\\};
struct READDIRPLUS3resok \\\{
post_op_attr dir_attributes;
cookieverf3 cookieverf;
dirlistplus3 reply;
\\\};
struct READDIRPLUS3resfail \\\{
post_op_attr dir_attributes;
\\\};
union READDIRPLUS3res switch (nfsstat3 status) \\\{
case NFS3_OK:
READDIRPLUS3resok resok;
default:
READDIRPLUS3resfail resfail;
\\\};
DESCRIPTION
READDIRPLUS 过程从文件系统目录中检索数量可变的条目, 并返回每个条目的完整信息, 同时返回相关信息, 以便客户端在后续 READDIRPLUS 中请求更多目录条目. READDIRPLUS 与 READDIR 的区别仅在于为每个条目返回的信息量. 在 READDIR 中, 每个条目返回 filename 和 fileid. 在 READDIRPLUS 中, 每个条目返回 name, fileid, 属性 (包括 fileid), 以及文件句柄. 进入时, READDIRPLUS3args 中的参数为:
dir
要读取的目录的文件句柄.
cookie
在读取目录的第一个请求中, 该值应设置为 0. 在后续请求中, 它应为服务器返回的 cookie.
cookieverf
在读取目录的第一个请求中, 该值应设置为 0. 在后续请求中, 它应为服务器返回的 cookieverf. cookieverf 必须与获取该 cookie 的 READDIRPLUS 调用所返回的值匹配.
dircount
返回的目录信息的最大字节数. 该数值不应包括结果中属性和文件句柄部分的大小.
maxcount
READDIRPLUS3resok 结构的最大大小, 以字节为单位. 该大小必须包含所有 XDR 开销. 服务器可以自由返回少于 maxcount 字节的数据.
成功返回时, READDIRPLUS3res.status 为 NFS3_OK, 且 READDIRPLUS3res.resok 包含:
dir_attributes
目录 dir 的属性.
cookieverf
Cookie 验证器.
reply
目录列表:
entries
零个或多个目录 (entryplus3) 条目.
eof
如果 reply.entries 的最后一个成员是目录中的最后一个条目, 或者列表 reply.entries 为空且 cookie 对应目录末尾, 则为 TRUE. 如果为 FALSE, 则可能还有更多条目可读取.
否则, READDIRPLUS3res.status 包含失败时的错误, READDIRPLUS3res.resfail 包含以下内容:
dir_attributes
目录 dir 的属性.
IMPLEMENTATION
此过程需要理解的问题包括客户端上增加的缓存刷新活动 (因为新的文件句柄与名称一起返回并进入缓存), 以及线上传输开销与预期消除后续 LOOKUP 之间的权衡. 通常认为, 对于目录浏览, 当属性总是必需时, 例如 Apple Macintosh 操作系统和 MS-DOS 上, 此过程可能提升性能.
dircount 和 maxcount 字段作为一种优化被包含进来. 设想 UNIX 操作系统实现上一次 1048 字节的 READDIRPLUS 调用; 由于属性和文件句柄带来的开销, 回复中不会包含很多条目. 另一种方法是发出 8192 字节的 READDIRPLUS 调用, 然后只使用前 1048 字节的目录信息. 但是, 服务器并不知道实际所需的只是 1048 字节的目录信息 (如 READDIR 返回的那样). 它看到的是 8192 字节请求, 并发出 8192 字节的 VOP_READDIR. 然后它遍历所有这些目录条目, 为每个条目获取属性和文件句柄. 当它编码结果时, 服务器只编码到取得 8192 字节结果为止, 这些结果包括属性和文件句柄. 因此, 它执行了更大的 VOP_READDIR, 并进行了远多于必要数量的属性获取. 目录条目大小与属性大小加文件句柄大小之和的比例通常至少为 8 比 1. 服务器完成了远超必要的工作.
此问题的解决方案是客户端向服务器提供两个计数. 第一个是客户端真正想要的目录信息字节数, 即 dircount. 第二个是结果中的最大字节数, 包括属性和文件句柄, 即 maxcount. 因此, 服务器只会针对客户端真正想获取的字节数发出 VOP_READDIR, 而不是一个膨胀后的数值. 这应有助于减少服务器上的 VOP_READDIR 请求大小, 从而减少服务器端完成的工作量, 并减少服务器为构造属性和文件句柄而执行的 VOP_LOOKUP, VOP_GETATTR 及其他调用的数量.
ERRORS
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_BAD_COOKIE
NFS3ERR_TOOSMALL
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT
SEE ALSO
READDIR.
3.3.18 过程 18: FSSTAT - 获取动态文件系统信息 (Get dynamic file system information)
SYNOPSIS
FSSTAT3res NFSPROC3_FSSTAT(FSSTAT3args) = 18;
struct FSSTAT3args \\\{
nfs_fh3 fsroot;
\\\};
struct FSSTAT3resok \\\{
post_op_attr obj_attributes;
size3 tbytes;
size3 fbytes;
size3 abytes;
size3 tfiles;
size3 ffiles;
size3 afiles;
uint32 invarsec;
\\\};
struct FSSTAT3resfail \\\{
post_op_attr obj_attributes;
\\\};
union FSSTAT3res switch (nfsstat3 status) \\\{
case NFS3_OK:
FSSTAT3resok resok;
default:
FSSTAT3resfail resfail;
\\\};
DESCRIPTION
FSSTAT 过程检索易变的文件系统状态信息. 进入时, FSSTAT3args 中的参数为:
fsroot
标识文件系统中某个对象的文件句柄. 这通常是文件系统挂载点的文件句柄, 最初从服务器上的 MOUNT 服务获取.
成功返回时, FSSTAT3res.status 为 NFS3_OK, 且 FSSTAT3res.resok 包含:
obj_attributes
fsroot 中指定的文件系统对象的属性.
tbytes
文件系统的总大小, 以字节为单位.
fbytes
文件系统中的空闲空间量, 以字节为单位.
abytes
RPC 中认证信息所标识的用户可用的空闲空间量, 以字节为单位. (这反映文件系统保留的空间; 不反映服务器实现的任何配额系统.)
tfiles
文件系统中文件槽位的总数. (在 UNIX 服务器上, 这通常对应已配置的 inode 数量.)
ffiles
文件系统中的空闲文件槽位数量.
afiles
RPC 中认证信息对应用户可用的空闲文件槽位数量. (这反映文件系统保留的槽位; 不反映服务器实现的任何配额系统.)
invarsec
文件系统易变性的度量: 这是预计文件系统不会发生变化的秒数. 对于易变且频繁更新的文件系统, 该值为 0. 对于不可变文件系统, 例如 CD-ROM, 该值将是最大的无符号整数. 对于很少修改的文件系统, 例如包含本地可执行程序和在线文档的文件系统, 可以使用对应数小时或数天的值. 客户端可以将其作为调优缓存管理的提示. 但是请注意, 此度量被假定为动态值, 可能随时改变.
否则, FSSTAT3res.status 包含失败时的错误, FSSTAT3res.resfail 包含以下内容:
obj_attributes
fsroot 中指定的文件系统对象的属性.
IMPLEMENTATION
并非所有实现都能支持完整的属性列表. 服务器预期会尽最大努力支持所有属性.
ERRORS
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
SEE ALSO
FSINFO.
3.3.19 过程 19: FSINFO - 获取静态文件系统信息 (Get static file system Information)
SYNOPSIS
FSINFO3res NFSPROC3_FSINFO(FSINFO3args) = 19;
const FSF3_LINK = 0x0001;
const FSF3_SYMLINK = 0x0002;
const FSF3_HOMOGENEOUS = 0x0008;
const FSF3_CANSETTIME = 0x0010;
struct FSINFOargs \\\{
nfs_fh3 fsroot;
\\\};
struct FSINFO3resok \\\{
post_op_attr obj_attributes;
uint32 rtmax;
uint32 rtpref;
uint32 rtmult;
uint32 wtmax;
uint32 wtpref;
uint32 wtmult;
uint32 dtpref;
size3 maxfilesize;
nfstime3 time_delta;
uint32 properties;
\\\};
struct FSINFO3resfail \\\{
post_op_attr obj_attributes;
\\\};
union FSINFO3res switch (nfsstat3 status) \\\{
case NFS3_OK:
FSINFO3resok resok;
default:
FSINFO3resfail resfail;
\\\};
DESCRIPTION
FSINFO 过程检索非易变的文件系统状态信息, 以及有关 NFS version 3 协议服务器实现的一般信息. 进入时, FSINFO3args 中的参数为:
fsroot
标识某个文件对象的文件句柄. 常规用法是提供文件系统挂载点的文件句柄, 最初从服务器上的 MOUNT 服务获取.
成功返回时, FSINFO3res.status 为 NFS3_OK, 且 FSINFO3res.resok 包含:
obj_attributes
fsroot 中指定的文件系统对象的属性.
rtmax
服务器支持的 READ 请求最大大小, 以字节为单位. 任何数值大于 rtmax 的 READ 都将导致短读, 读取 rtmax 字节或更少.
rtpref
READ 请求的首选大小. 除非在性能或效率方面有明确收益, 否则该值应与 rtmax 相同.
rtmult
READ 请求大小的建议倍数.
wtmax
服务器支持的 WRITE 请求最大大小. 一般而言, 客户端受 wtmax 限制, 因为不能保证服务器能够处理更大的写入. 任何 count 大于 wtmax 的 WRITE 都将导致短写, 最多写入 wtmax 字节.
wtpref
WRITE 请求的首选大小. 除非在性能或效率方面有明确收益, 否则该值应与 wtmax 相同.
wtmult
WRITE 请求大小的建议倍数.
dtpref
READDIR 请求的首选大小.
maxfilesize
文件系统上文件的最大大小.
time_delta
服务器时间粒度. 使用 SETATTR 设置文件时间时, 服务器只保证将时间保留到此精度. 如果该值为 \\\{0, 1\\\}, 则服务器可支持纳秒级时间; \\\{0, 1000000\\\} 表示毫秒精度; \\\{1, 0\\\} 表示时间仅精确到最接近的秒.
properties
文件系统属性的位掩码. 定义了以下值:
FSF_LINK
如果此位为 1 (TRUE), 则文件系统支持硬链接.
FSF_SYMLINK
如果此位为 1 (TRUE), 则文件系统支持符号链接.
FSF_HOMOGENEOUS
如果此位为 1 (TRUE), 则 PATHCONF 返回的信息对文件系统中的每个文件和目录都是相同的. 如果为 0 (FALSE), 客户端应按需为每个文件和目录检索 PATHCONF 信息.
FSF_CANSETTIME
如果此位为 1 (TRUE), 则在请求时, 服务器将通过 SETATTR 设置文件时间 (精度由 time_delta 指示). 如果为 0 (FALSE), 服务器无法按请求设置时间.
否则, FSINFO3res.status 包含失败时的错误, FSINFO3res.resfail 包含以下内容:
attributes
fsroot 中指定的文件系统对象的属性.
IMPLEMENTATION
并非所有实现都能支持完整的属性列表. 服务器预期会尽最大努力支持所有属性.
所提供的文件句柄预期是文件系统根的文件句柄, 即 MOUNT 操作返回的文件句柄. 由于挂载可能发生在导出树中的任意位置, 服务器应预期收到指定导出文件系统内文件句柄的 FSINFO 请求. 服务器可以导出不同类型的文件系统, 并为 FSINFO 调用返回不同属性. 客户端应为每个已完成的挂载检索 FSINFO 信息. 虽然服务器可以为文件系统内不同文件返回不同 FSINFO 信息, 但并不要求客户端对挂载时返回的文件句柄以外的对象获取 FSINFO 信息.
maxfilesize 字段决定服务器的特定文件系统使用 32 位大小和偏移量, 还是使用 64 位文件大小和偏移量. 这可能会影响客户端的处理.
请求的首选大小名义上与客户端挂载的导出文件系统相关联. 一个可以解决的问题是, NFS version 3 协议请求的传输大小不仅取决于文件系统特征, 还取决于网络接口特征, 尤其是最大传输单元 (MTU). 服务器实现可以根据接收 FSINFO 请求的接口通告不同传输大小 (针对 rtmax, rtpref, wtmax, wtpref 和 dtpref 字段). 这是一个实现问题.
ERRORS
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
SEE ALSO
READLINK, WRITE, READDIR, FSSTAT and PATHCONF.
3.3.20 过程 20: PATHCONF - 检索 POSIX 信息 (Retrieve POSIX information)
SYNOPSIS
PATHCONF3res NFSPROC3_PATHCONF(PATHCONF3args) = 20;
struct PATHCONF3args \\\{
nfs_fh3 object;
\\\};
struct PATHCONF3resok \\\{
post_op_attr obj_attributes;
uint32 linkmax;
uint32 name_max;
bool no_trunc;
bool chown_restricted;
bool case_insensitive;
bool case_preserving;
\\\};
struct PATHCONF3resfail \\\{
post_op_attr obj_attributes;
\\\};
union PATHCONF3res switch (nfsstat3 status) \\\{
case NFS3_OK:
PATHCONF3resok resok;
default:
PATHCONF3resfail resfail;
\\\};
DESCRIPTION
PATHCONF 过程检索文件或目录的 pathconf 信息. 如果 FSFINFO3resok.properties 中设置了 FSF_HOMOGENEOUS 位, 则 pathconf 信息对于此文件或目录所在的导出文件系统中的所有文件和目录都相同. 进入时, PATHCONF3args 中的参数为:
object
文件系统对象的文件句柄.
成功返回时, PATHCONF3res.status 为 NFS3_OK, 且 PATHCONF3res.resok 包含:
obj_attributes
object 指定对象的属性.
linkmax
指向某个对象的硬链接最大数量.
name_max
文件名组件的最大长度.
no_trunc
如果为 TRUE, 服务器将拒绝任何包含长度超过 name_max 的名称的请求, 并返回错误 NFS3ERR_NAMETOOLONG. 如果为 FALSE, 任何超过 name_max 字节的名称都会被静默截断为 name_max 字节.
chown_restricted
如果为 TRUE, 当调用者不是特权用户 (Uid 0) 时, 服务器将拒绝任何更改文件关联所有者或组的请求.
case_insensitive
如果为 TRUE, 服务器文件系统在解释文件名时不区分大小写.
case_preserving
如果为 TRUE, 服务器文件系统将在 CREATE, MKDIR, MKNOD, SYMLINK, RENAME 或 LINK 操作期间保留名称的大小写.
否则, PATHCONF3res.status 包含失败时的错误, PATHCONF3res.resfail 包含以下内容:
obj_attributes
object 指定对象的属性.
IMPLEMENTATION
在 NFS version 2 协议的一些实现中, pathconf 信息是在挂载时通过 MOUNT 协议获取的. 获取它的正确位置如这里所示, 是在 NFS version 3 协议本身中.
ERRORS
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
SEE ALSO
LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD, RENAME, LINK and FSINFO.
3.3.21 过程 21: COMMIT - 将服务器上的缓存数据提交到稳定存储 (Commit cached data on a server to stable storage)
SYNOPSIS
COMMIT3res NFSPROC3_COMMIT(COMMIT3args) = 21;
struct COMMIT3args \\\{
nfs_fh3 file;
offset3 offset;
count3 count;
\\\};
struct COMMIT3resok \\\{
wcc_data file_wcc;
writeverf3 verf;
\\\};
struct COMMIT3resfail \\\{
wcc_data file_wcc;
\\\};
union COMMIT3res switch (nfsstat3 status) \\\{
case NFS3_OK:
COMMIT3resok resok;
default:
COMMIT3resfail resfail;
\\\};
DESCRIPTION
COMMIT 过程强制或刷新先前通过 WRITE 过程调用写入的数据到稳定存储, 该 WRITE 调用的 stable 字段设置为 UNSTABLE. 进入时, COMMIT3args 中的参数为:
file
要刷新 (提交) 数据的文件的文件句柄. 该文件句柄必须标识类型为 NF3REG 的文件系统对象.
offset
文件内开始刷新的位置. offset 为 0 表示从文件开头开始刷新数据.
count
要刷新的数据字节数. 如果 count 为 0, 则执行从 offset 到文件末尾的刷新.
成功返回时, COMMIT3res.status 为 NFS3_OK, 且 COMMIT3res.resok 包含:
file_wcc
文件的弱缓存一致性数据. 对于只需要操作后文件属性的客户端, 这些属性可在 file_wcc.after 中找到.
verf
这是一个 cookie, 客户端可用它确定服务器是否在一次 WRITE 调用和后续 COMMIT 调用之间重启过. 在单次启动会话期间, 此 cookie 必须保持一致; 在未提交数据可能丢失的 NFS version 3 协议服务器实例之间, 此 cookie 必须唯一.
否则, COMMIT3res.status 包含失败时的错误, COMMIT3res.resfail 包含以下内容:
file_wcc
文件的弱缓存一致性数据. 对于只需要写入后文件属性的客户端, 这些属性可在 file_wcc.after 中找到. 即使 COMMIT 失败, 也会返回完整的 wcc_data, 以允许客户端确定服务器上的文件是否在 WRITE 和 COMMIT 调用之间发生变化.
IMPLEMENTATION
COMMIT 过程在操作和语义上类似于 POSIX fsync(2) 系统调用, 后者将文件状态与磁盘同步, 即把文件的数据和元数据刷新到磁盘. COMMIT 为客户端执行相同操作, 将服务器上指定文件的任何未同步数据和元数据刷新到服务器磁盘. 与 fsync(2) 类似, 可能存在一些已修改数据需要同步, 也可能没有已修改数据需要同步. 数据可能已经由服务器正常的周期性缓冲区同步活动完成同步. 除非发生意外错误, COMMIT 将始终返回 NFS3_OK.
COMMIT 与 fsync(2) 的不同之处在于, 客户端可以刷新文件的某个范围 (最可能由客户端上的缓冲区回收方案触发, 且发生在文件尚未完全写入之前).
服务器端 COMMIT 实现相当简单. 如果服务器收到完整文件 COMMIT 请求, 即从 offset 0 开始且 count 为 0, 它应执行等价于对文件调用 fsync() 的操作. 否则, 它应安排将 offset 和 count 指定范围内的缓存数据刷新到稳定存储. 在两种情况下, 返回前都必须将与文件关联的任何元数据刷新到稳定存储. 服务器上没有需要刷新的内容并不是错误. 这意味着需要刷新的数据和元数据已经在上一次服务器故障期间被刷新或丢失.
客户端端 COMMIT 实现稍复杂一些. 想要将客户端缓冲区提交到稳定存储有两个原因. 第一个原因是客户端想要复用某个缓冲区. 在这种情况下, 缓冲区的 offset 和 count 会在 COMMIT 请求中发送给服务器. 然后服务器根据 offset 和 count 刷新任何缓存数据, 并刷新与文件关联的任何元数据. 随后它返回刷新状态和 verf 验证器. 客户端生成 COMMIT 的另一个原因是进行完整文件刷新, 例如在 close 时可能执行的刷新. 在这种情况下, 客户端会收集此文件中所有包含未提交数据的缓冲区, 以 offset 为 0 且 count 为 0 执行 COMMIT 操作, 然后释放所有这些缓冲区. 任何其他脏缓冲区将按正常方式发送给服务器.
此实现需要对客户端上的缓冲区缓存做一些修改. 当缓冲区以 stable 为 UNSTABLE 写入后, 客户端系统必须将其视为脏缓冲区, 直到它通过 COMMIT 操作被刷新, 或通过 stable 设置为 FILE_SYNC 或 DATA_SYNC 的 WRITE 操作被写入. 这样做是为了防止缓冲区在数据能够刷新到服务器稳定存储之前被释放和复用.
当包含意外 verf 的响应从 WRITE 或 COMMIT 操作返回时, 客户端需要将所有包含未提交缓存数据的缓冲区重传给服务器. 如何执行由实现者决定. 如果只有一个相关缓冲区, 则可能应在带有适当 stable 标志的 WRITE 请求中将其重新发送. 如果不止一个, 则可能值得在 stable 设置为 UNSTABLE 的 WRITE 请求中重传所有缓冲区, 然后重传 COMMIT 操作, 以将服务器上的所有数据刷新到稳定存储. 这些重传的时机留给实现者决定.
上述说明既适用于基于 page cache 的系统, 也适用于基于 buffer cache 的系统. 在这些系统中, 需要修改的是虚拟内存系统, 而不是缓冲区缓存.
参见第 49 页关于 WRITE 的附加说明.
ERRORS
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
SEE ALSO
WRITE.