Post

rfc1813中文翻译

rfc1813中文翻译

RFC 1813 NFS版本3协议规范 - 中文翻译

文档信息

  • RFC编号: RFC 1813
  • 标题: NFS Version 3 Protocol Specification (NFS版本3协议规范)
  • 作者: B. Callaghan, B. Pawlowski, P. Staubach (Sun Microsystems, Inc.)
  • 发布日期: 1995年6月
  • 类别: Informational (信息性)
  • 状态: 本备忘录为互联网社区提供信息。本备忘录不规定任何类型的互联网标准。本备忘录的分发不受限制。

摘要

本文档描述了NFS版本3协议。提供本文档的目的是使人们能够编写兼容的实现。

目录

  1. 引言 1.1 NFS版本3协议的范围 1.2 有用的术语 1.3 远程过程调用 1.4 外部数据表示 1.5 认证和权限检查 1.6 设计理念 1.7 与NFS版本2协议的变更
  2. RPC信息 2.1 认证 2.2 常量 2.3 传输地址 2.4 大小 2.5 基本数据类型 2.6 定义的错误号
  3. 服务器过程 3.1 关于属性的一般说明 3.2 关于文件名的一般说明 3.3.0 NULL: 不做任何操作 3.3.1 GETATTR: 获取文件属性 3.3.2 SETATTR: 设置文件属性 3.3.3 LOOKUP: 查找文件名 3.3.4 ACCESS: 检查访问权限 3.3.5 READLINK: 从符号链接读取 3.3.6 READ: 从文件读取 3.3.7 WRITE: 写入文件 3.3.8 CREATE: 创建文件 3.3.9 MKDIR: 创建目录 3.3.10 SYMLINK: 创建符号链接 3.3.11 MKNOD: 创建特殊设备 3.3.12 REMOVE: 删除文件 3.3.13 RMDIR: 删除目录 3.3.14 RENAME: 重命名文件或目录 3.3.15 LINK: 创建到对象的链接 3.3.16 READDIR: 从目录读取 3.3.17 READDIRPLUS: 扩展目录读取 3.3.18 FSSTAT: 获取动态文件系统信息 3.3.19 FSINFO: 获取静态文件系统信息 3.3.20 PATHCONF: 检索POSIX信息 3.3.21 COMMIT: 将服务器上的缓存数据提交到稳定存储
  4. 实现问题 4.1 多版本支持 4.2 服务器/客户端关系 4.3 路径名解释 4.4 权限问题 4.5 重复请求缓存 4.6 文件名组件处理 4.7 同步修改操作 4.8 稳定存储 4.9 查找和名称解析 4.10 自适应重传 4.11 缓存策略 4.12 稳定写入与非稳定写入 4.13 32位客户端/服务器和64位客户端/服务器
  5. 附录I: 挂载协议
  6. 附录II: 锁管理器协议
  7. 附录III: 参考文献
  8. 安全考虑
  9. 致谢
  10. 作者地址

1. 引言

Sun的NFS协议提供对跨网络共享文件系统的透明远程访问。NFS协议设计为机器、操作系统、网络架构和传输协议无关。这种独立性是通过建立在外部数据表示(XDR)之上的远程过程调用(RPC)原语实现的。NFS版本2协议的实现存在于各种机器上,从个人计算机到超级计算机。NFS协议的初始版本在网络文件系统协议规范[RFC1094]中指定。初始实现的描述可以在[Sandberg]中找到。

支持的MOUNT协议执行操作系统特定的功能,允许客户端将远程目录树附加到本地文件系统中的某个点。挂载过程还允许服务器通过导出控制向受限的客户端集授予远程访问权限。

锁管理器在NFS环境中使用时提供文件锁定支持。网络锁管理器(NLM)协议将文件锁定的固有状态方面隔离到单独的协议中。

上述协议及其实现的完整描述可以在[X/OpenNFS]中找到。

本文档的目的是:

  • 指定NFS版本3协议
  • 通过注释和预期实现的描述来描述协议的语义
  • 指定MOUNT版本3协议
  • 简要描述NLM版本3协议和NLM版本4协议之间的变更

规范性文本是RPC过程及其参数和结果的描述,它定义了线上协议以及这些过程的语义。描述实现实践的材料有助于理解协议规范,并描述了一些可能的实现问题和解决方案。不可能描述所有实现,UNIX操作系统的NFS版本3协议实现最常用于提供示例。鉴于此,实现讨论不具有线上协议本身描述的权威性。

1.1 NFS版本3协议的范围

NFS协议的这次修订解决了新的要求。支持更大文件和文件系统的需求促使扩展允许64位文件大小和偏移量。修订通过添加支持在服务器上进行访问检查来增强安全性。性能修改有三种类型:

  1. 通过在每个操作上返回文件属性,减少了给定文件操作集的线上数据包数量,从而减少了获取修改属性的调用次数。

  2. 通过添加支持使NFS服务器能够进行不安全写入,解决了NFS版本2协议中写入的同步定义导致的写入吞吐量瓶颈。不安全写入是在操作返回之前尚未提交到稳定存储的写入。本规范定义了一种将这些不安全写入可靠地提交到稳定存储的方法。

  3. 放宽了对传输大小的限制。

RPC中支持协议多个版本的能力将允许NFS版本3协议的实现者定义与现有NFS版本2协议实现安装基础提供向后兼容性的客户端和服务器。

这里描述的扩展代表现有NFS协议的演进,[Sandberg]中描述的NFS协议的大多数设计特征仍然存在。有关此次修订引入的变更的更详细摘要,请参见第11页的”与NFS版本2协议的变更”。

1.2 有用的术语

在本规范中,”服务器”是向网络提供资源的机器;”客户端”是通过网络访问资源的机器;”用户”是登录到客户端的人员;”应用程序”是在客户端上执行的程序。

1.3 远程过程调用

Sun远程过程调用规范提供面向过程的远程服务接口。每个服务器提供一个程序,它是一组过程。NFS服务就是这样一个程序。主机地址、程序号、版本号和过程号的组合指定一个远程服务过程。服务器可以通过使用不同的协议版本号来支持程序的多个版本。

NFS协议设计为不需要其底层提供任何特定的可靠性级别,因此它可能潜在地用于许多底层传输协议。NFS服务基于RPC,RPC提供了底层网络和传输协议之上的抽象。

本文档的其余部分假设NFS环境在Sun RPC之上实现,Sun RPC在[RFC1057]中指定。完整的讨论可以在[Corbin]中找到。

1.4 外部数据表示

外部数据表示(XDR)规范提供了在网络上表示一组数据类型的标准方法。这解决了不同通信机器上不同字节顺序、结构对齐和数据类型表示的问题。

在本文档中,使用RPC数据描述语言来指定NFS服务器提供的每个RPC服务过程的XDR格式参数和结果。RPC数据描述语言类似于C编程语言中的声明。添加了一些新的构造。表示法:

1
2
string  name[SIZE];
string  data<DSIZE>;

定义name,它是一个SIZE字节的固定大小块,和data,它是一个最大DSIZE字节的可变大小块。这种表示法指示固定长度数组和具有可变数量元素的数组,最大到固定最大值。没有指定大小的可变长度定义意味着该字段没有最大大小。

判别联合定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
union example switch (enum status) {
     case OK:
        struct {
           filename      file1;
           filename      file2;
           integer       count;
        }
     case ERROR:
        struct {
           errstat       error;
           integer       errno;
        }
     default:
        void;
}

定义了一个结构,其中网络上的第一个内容是一个称为status的枚举类型。如果status的值是OK,网络上的下一个内容将是包含file1、file2和count的结构。否则,如果status的值是ERROR,网络上的下一个内容将是包含error和errno的结构。如果status的值既不是OK也不是ERROR,那么结构中没有更多数据。

XDR类型hyper是一个8字节(64位)的数量。它的使用方式与整数类型相同。例如:

1
2
hyper          foo;
unsigned hyper bar;

foo是一个8字节有符号值,而bar是一个8字节无符号值。

尽管存在RPC/XDR编译器来从RPC数据描述语言输入生成客户端和服务器存根,但NFS实现不需要使用它们。任何提供等效编码和解码到XDR定义的标准网络顺序数据的软件都可以用于与其他N实现互操作。

XDR在[RFC1014]中描述。

1.5 认证和权限检查

RPC协议在每次调用中都包含一个认证参数槽。认证参数的内容由服务器和客户端使用的认证类型确定。服务器可以同时支持几种不同类型的认证。AUTH_NONE类型提供空认证,即不传递认证信息。AUTH_UNIX类型在每次调用时提供UNIX样式的用户ID、组ID和组。AUTH_DES类型提供基于网络范围名称的DES加密认证参数,会话密钥通过公钥方案交换。AUTH_KERB类型提供基于网络范围名称的DES加密认证参数,会话密钥通过Kerberos秘密密钥交换。

NFS服务器通过从每个远程请求中的RPC认证信息中获取凭据来检查权限。例如,使用AUTH_UNIX类型的认证,服务器在每次调用时获取用户的有效用户ID、有效组ID和组,并使用它们来检查访问。使用用户ID和组ID意味着客户端和服务器要么共享相同的ID列表,要么进行本地用户和组ID映射。对于没有实现一致用户ID和组ID空间的站点,服务器和客户端必须就用户到uid和组到gid的映射达成一致。在实践中,这种映射通常在服务器上执行,遵循静态映射方案或在挂载时由用户从客户端建立的映射。

AUTH_DES和AUTH_KERB风格的认证基于网络范围的名称。在AUTH_DES的情况下,它通过使用DES加密和公钥提供更大的安全性,在AUTH_KERB的情况下,使用DES加密和Kerberos秘密密钥(和票据)。同样,服务器和客户端必须就网络上特定名称的身份达成一致,但名称到身份的映射比AUTH_UNIX中的uid和gid映射更独立于操作系统。此外,因为认证参数是加密的,恶意用户必须知道另一个用户的网络密码或私钥才能冒充该用户。类似地,服务器返回的验证器也是加密的,因此冒充服务器需要知道网络密码。

NULL过程通常不需要认证。

1.6 设计理念

本规范定义NFS版本3协议,即客户端访问服务器的线上协议。协议提供对服务器文件资源的明确定义接口。客户端或服务器实现协议并提供本地文件系统语义和操作到NFS版本3协议中定义的那些的映射。实现可能在不同程度上有所不同,这取决于给定环境支持NFS版本3协议中定义的所有操作和语义的程度。尽管存在实现并用于说明NFS版本3协议的各个方面,但协议规范本身是客户端访问服务器资源的最终描述。

因为NFS版本3协议设计为独立于操作系统,它不一定匹配任何现有系统的语义。服务器实现应该尽力支持协议。如果服务器不能支持特定的协议过程,它可能返回错误NFS3ERR_NOTSUP,表示该操作不受支持。例如,许多操作系统不支持硬链接的概念。不能支持硬链接的服务器应该在响应LINK请求时返回NFS3ERR_NOTSUP。FSINFO在属性位图中描述了最常见的不支持的过程。或者,服务器可能本身不支持给定操作,但可以在NFS版本3协议实现中模拟它以提供更大的功能。

在某些情况下,服务器可以支持协议描述的大部分语义,但不能支持全部。例如,fattr结构中的ctime字段给出文件属性最后修改的时间。许多系统不保留此信息。在这种情况下,服务器可以通过返回最后修改时间来模拟GETATTR操作,而不是不支持GETATTR操作。服务器在模拟属性信息时必须小心,因为可能对客户端产生副作用。例如,许多客户端使用文件修改时间作为其缓存一致性方案的基础。

NFS服务器是哑的,NFS客户端是智能的。是客户端进行工作,将服务器提供的通用文件访问转换为对应用程序和用户有用的文件访问方法。在上面给出的LINK示例中,从服务器收到NFS3ERR_NOTSUP错误的UNIX客户端将进行必要的恢复,要么使应用程序看起来链接请求成功,要么返回合理的错误。通常,恢复是客户端的负担。

NFS版本3协议假设无状态服务器实现。无状态意味着服务器不需要维护关于其任何客户端的状态就能正确运行。无状态服务器在崩溃事件中比有状态服务器有明显优势。对于无状态服务器,客户端只需要重试请求直到服务器响应;客户端甚至不需要知道服务器已经崩溃。有关其他评论,请参见第99页的”重复请求缓存”。

为了使服务器有用,它持有非易失性状态:存储在文件系统中的数据。NFS版本3协议中关于将修改的数据刷新到稳定存储的设计假设减少了可能发生数据丢失的故障模式数量。通过这种方式,NFS版本3协议实现可以容忍瞬态故障,包括网络的瞬态故障。通常,NFS版本3协议的服务器实现不能容忍稳定存储本身的非瞬态故障。但是,存在容错实现尝试解决此类问题。

这并不是说NFS版本3协议服务器不能维护非关键状态。在许多情况下,服务器将维护关于先前操作的状态(缓存)以提高性能。例如,客户端READ请求可能触发对文件下一个块的预读到服务器的数据缓存中,预期客户端正在进行顺序读取,下一个客户端READ请求将从服务器的数据缓存而不是磁盘得到满足。服务器上的预读通过重叠服务器磁盘I/O与客户端请求来提高性能。这里的重要点是预读块对于正确的服务器行为不是必需的。如果服务器崩溃并丢失其读缓冲区的内存缓存,重启时恢复很简单 - 客户端将继续从服务器磁盘检索数据的读取操作。

NFS协议中的大多数数据修改操作是同步的。也就是说,当数据修改过程返回给客户端时,客户端可以假设操作已完成,与请求相关的任何修改数据现在都在稳定存储上。例如,同步客户端WRITE请求可能导致服务器更新数据块、文件系统信息块和文件属性信息 - 后者信息通常称为元数据。当WRITE操作完成时,客户端可以假设写入数据是安全的并可以丢弃它。这是服务器无状态特性的非常重要部分。如果服务器在返回给客户端之前没有将脏数据刷新到稳定存储,客户端将无法知道何时丢弃修改数据是安全的。以下数据修改过程是同步的:WRITE(稳定标志设置为FILE_SYNC)、CREATE、MKDIR、SYMLINK、MKNOD、REMOVE、RMDIR、RENAME、LINK和COMMIT。

NFS版本3协议引入服务器上的安全异步写入,当WRITE过程与COMMIT过程一起使用时。COMMIT过程提供了一种方法,让客户端将之前在服务器上使用稳定标志设置为UNSTABLE的异步WRITE请求的数据刷新到稳定存储,并检测是否需要重新传输数据。有关数据何时提交到稳定存储的更多信息,请参见第49页的WRITE过程描述和第92页的COMMIT过程描述。

LOOKUP过程被客户端用于遍历多组件文件名(路径名)。每次调用LOOKUP用于解析路径名的一个段。将LOOKUP限制为单个段有两个原因:很难为分层文件名标准化通用格式,并且客户端和服务器可能对路径名到文件系统的映射不同。这意味着要么客户端必须在文件系统挂载点处断开路径名,要么服务器必须知道客户端的文件系统挂载点。在NFS版本3协议实现中,是客户端使用挂载来构建层次结构,从而构建分层文件名空间。支持实用程序(如Automounter)提供了一种管理共享、一致的文件名空间映像的方法,同时仍然由客户端挂载过程驱动。

客户端可以以各种方式执行缓存。NFS版本2协议的一般实践是实现基于时间的客户端-服务器缓存一致性机制。预期NFS版本3协议实现将使用类似的机制。NFS版本3协议有一些显式支持,以附加属性信息的形式消除显式属性检查。但是,不需要缓存,协议也没有定义任何缓存策略。NFS版本2协议和NFS版本3协议都不提供维持严格客户端-服务器一致性(以及暗示跨客户端缓存一致性)的方法。

1.7 与NFS版本2协议的变更

已删除ROOT和WRITECACHE过程。已定义MKNOD过程以允许创建特殊文件,消除了CREATE的过载。客户端缓存不是由NFS版本3协议定义或规定的,但已向协议添加了附加信息和提示,以允许实现缓存的客户端更有效地管理其缓存。影响文件或目录属性的过程现在可以在操作完成后返回新属性,以优化验证属性缓存时使用的后续GETATTR。此外,修改目标对象所在目录的操作返回目录的旧属性和新属性,以允许客户端实现更智能的缓存失效过程。ACCESS过程提供服务器上的访问权限检查,FSSTAT过程返回文件系统的动态信息,FSINFO过程返回文件系统和服务器的静态信息,READDIRPLUS过程返回文件句柄和属性以及目录条目,PATHCONF过程返回文件的POSIX pathconf信息。

以下是NFS版本2协议和NFS版本3协议之间重要变更的列表。

文件句柄大小 文件句柄已从32字节的固定数组增加到最大64字节的可变长度数组。这解决了一些对稍大文件句柄大小的已知要求。文件句柄从固定长度转换为可变长度,以减少不利用完整64字节长度的系统的本地存储和网络带宽需求。

最大数据大小 READ和WRITE过程中使用的数据传输的最大大小现在由FSINFO返回结构中的值设置。此外,FSINFO返回首选传输大小。协议不对最大传输大小施加任何人为限制。

文件名和路径名现在指定为可变长度字符串。实际长度限制由客户端和服务器实现酌情确定。协议不对长度施加任何人为限制。提供了错误NFS3ERR_NAMETOOLONG,以允许服务器向客户端返回指示,表示它收到了对其来说太长而无法处理的路径名。

错误返回 某些情况下的错误返回现在返回数据(例如属性)。nfsstat3现在定义了服务器可以返回的完整错误集。不允许其他值。

文件类型 文件类型现在包括NF3CHR和NF3BLK用于特殊文件。这些类型的属性包括UNIX主设备和次设备号的子字段。现在为文件系统中的套接字和FIFO定义了NF3SOCK和NF3FIFO。

文件属性 已删除blocksize(文件中块的字节大小)字段。mode字段不再包含文件类型信息。size和fileid字段已从4字节整数扩展为8字节无符号整数。主设备和次设备信息现在以不同的结构呈现。blocks字段名已更改为used,现在包含文件使用的总字节数。它也是一个8字节无符号整数。

设置文件属性 在NFS版本2协议中,可设置属性由文件属性结构的子集表示;客户端通过将相应字段设置为-1来指示那些不修改的属性,重载了一些无符号字段。设置文件属性结构现在对每个字段使用判别联合来告诉是否或如何设置该字段。atime和mtime字段可以设置为服务器的当前时间或客户端提供的时间。

LOOKUP LOOKUP返回结构现在包括搜索目录的属性。

ACCESS 添加了ACCESS过程以允许显式线上权限检查。这解决了许多服务器实现中超级用户ID映射功能的已知问题(由于root用户映射,在读取或写入文件时可能发生意外的权限拒绝错误)。这也消除了NFS版本2协议中做出的假设,即对文件的访问仅基于UNIX样式的模式位。

READ 回复结构包括一个布尔值,如果在READ期间遇到文件结束,则为TRUE。这允许客户端正确检测文件结束。

WRITE 从WRITE参数中删除了beginoffset和totalcount字段。回复现在包括一个计数,因此如果需要,服务器可以写入比请求量少的数据。向参数添加了一个指示器,指示服务器客户端所需的缓存同步级别。

CREATE 添加了exclusive标志和create验证器用于常规文件的独占创建。

MKNOD 添加此过程以支持特殊文件的创建。这避免了在某些NFS版本2协议实现中对CREATE字段的重载。

READDIR READDIR参数现在包括一个验证器以允许服务器验证cookie。cookie现在是64位无符号整数,而不是NFS版本2协议中使用的4字节数组。这将有助于减少互操作性问题。

READDIRPLUS 添加此过程以在扩展目录列表中返回文件句柄和属性。

FSINFO 添加FSINFO以提供文件系统的非易失性信息。回复包括首选和最大读取传输大小、首选和最大写入传输大小,以及指示是否支持链接或符号链接的标志。还返回READDIR过程回复的首选传输大小、服务器时间粒度,以及是否可以在SETATTR请求中设置时间。

FSSTAT 添加FSSTAT以提供文件系统的易失性信息,供Unix系统df命令等实用程序使用。回复包括指定文件系统的总大小和可用空间(以字节为单位)、文件系统中的总文件槽和空闲文件槽数,以及文件系统修改之间时间的估计(用于缓存一致性检查算法)。

COMMIT COMMIT过程提供与异步WRITE操作一起使用的同步机制。


2. RPC信息

2.1 认证

NFS服务在NULL过程中使用AUTH_NONE。所有其他过程使用AUTH_UNIX、AUTH_DES或AUTH_KERB。将来可能支持其他认证类型。

2.2 常量

这些是调用NFS版本3服务所需的RPC常量。它们以十进制给出。

1
2
PROGRAM  100003
VERSION  3

2.3 传输地址

NFS协议通常在TCP和UDP协议上支持。它使用端口2049,与NFS版本2协议相同。

2.4 大小

这些是NFS版本3协议中使用的各种XDR结构的大小,以十进制字节为单位:

1
2
3
4
5
6
7
8
9
10
11
NFS3_FHSIZE 64
   不透明文件句柄的最大字节大小。

NFS3_COOKIEVERFSIZE 8
   READDIR和READDIRPLUS传递的不透明cookie验证器的字节大小。

NFS3_CREATEVERFSIZE 8
   用于独占CREATE的不透明验证器的字节大小。

NFS3_WRITEVERFSIZE 8
   用于异步WRITE的不透明验证器的字节大小。

2.5 基本数据类型

以下XDR定义是其他结构中使用的基本定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
uint64
   typedef unsigned hyper uint64;

int64
   typedef hyper int64;

uint32
   typedef unsigned long uint32;

int32
   typedef long int32;

filename3
   typedef string filename3<>;

nfspath3
   typedef string nfspath3<>;

fileid3
   typedef uint64 fileid3;

cookie3
   typedef uint64 cookie3;

cookieverf3
   typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];

createverf3
   typedef opaque createverf3[NFS3_CREATEVERFSIZE];

writeverf3
   typedef opaque writeverf3[NFS3_WRITEVERFSIZE];

uid3
   typedef uint32 uid3;

gid3
   typedef uint32 gid3;

size3
   typedef uint64 size3;

offset3
   typedef uint64 offset3;

mode3
   typedef uint32 mode3;

count3
   typedef uint32 count3;

nfsstat3
   enum nfsstat3 {
      NFS3_OK             = 0,
      NFS3ERR_PERM        = 1,
      NFS3ERR_NOENT       = 2,
      NFS3ERR_IO          = 5,
      NFS3ERR_NXIO        = 6,
      NFS3ERR_ACCES       = 13,
      NFS3ERR_EXIST       = 17,
      NFS3ERR_XDEV        = 18,
      NFS3ERR_NODEV       = 19,
      NFS3ERR_NOTDIR      = 20,
      NFS3ERR_ISDIR       = 21,
      NFS3ERR_INVAL       = 22,
      NFS3ERR_FBIG        = 27,
      NFS3ERR_NOSPC       = 28,
      NFS3ERR_ROFS        = 30,
      NFS3ERR_MLINK       = 31,
      NFS3ERR_NAMETOOLONG = 63,
      NFS3ERR_NOTEMPTY    = 66,
      NFS3ERR_DQUOT       = 69,
      NFS3ERR_STALE       = 70,
      NFS3ERR_REMOTE      = 71,
      NFS3ERR_BADHANDLE   = 10001,
      NFS3ERR_NOT_SYNC    = 10002,
      NFS3ERR_BAD_COOKIE  = 10003,
      NFS3ERR_NOTSUPP     = 10004,
      NFS3ERR_TOOSMALL    = 10005,
      NFS3ERR_SERVERFAULT = 10006,
      NFS3ERR_BADTYPE     = 10007,
      NFS3ERR_JUKEBOX     = 10008
   };

nfsstat3类型在每个过程的结果中返回,NULL过程除外。NFS3_OK值表示调用成功完成。任何其他值表示调用中发生了某些错误,如错误码所示。注意必须遵循精确的数字编码。服务器不能返回其他值。服务器应该尽力将错误条件映射到定义的错误码集。此外,本规范没有指定错误优先级。错误优先级确定在给定情况下多个错误适用时应返回的错误值。错误优先级将由各个服务器实现确定。如果客户端需要特定的错误优先级,它应该自己检查特定错误。

2.6 定义的错误号

每个定义错误的描述如下:

NFS3_OK 表示调用成功完成。

NFS3ERR_PERM 不是所有者。操作不被允许,因为调用者既不是特权用户(root),也不是操作目标的所有者。

NFS3ERR_NOENT 没有这样的文件或目录。指定的文件或目录名不存在。

NFS3ERR_IO I/O错误。在处理请求的操作时发生硬错误(例如磁盘错误)。

NFS3ERR_NXIO I/O错误。没有这样的设备或地址。

NFS3ERR_ACCES 权限被拒绝。调用者没有执行请求操作的正确权限。与此对比的是NFS3ERR_PERM,它仅限于所有者或特权用户权限失败。

NFS3ERR_EXIST 文件存在。指定的文件已经存在。

NFS3ERR_XDEV 尝试进行跨设备硬链接。

NFS3ERR_NODEV 没有这样的设备。

NFS3ERR_NOTDIR 不是目录。调用者在目录操作中指定了非目录。

NFS3ERR_ISDIR 是目录。调用者在非目录操作中指定了目录。

NFS3ERR_INVAL 无效参数或操作不支持参数。两个示例是尝试对非符号链接的对象进行READLINK,或尝试在不支持此操作的服务器上SETATTR时间字段。

NFS3ERR_FBIG 文件太大。操作会导致文件增长超过服务器的限制。

NFS3ERR_NOSPC 设备上没有剩余空间。操作会导致服务器的文件系统超过其限制。

NFS3ERR_ROFS 只读文件系统。在只读文件系统上尝试了修改操作。

NFS3ERR_MLINK 太多硬链接。

NFS3ERR_NAMETOOLONG 操作中的文件名太长。

NFS3ERR_NOTEMPTY 尝试删除非空目录。

NFS3ERR_DQUOT 资源(配额)硬限制超过。服务器上的用户资源限制已被超过。

NFS3ERR_STALE 无效文件句柄。参数中给出的文件句柄无效。该文件句柄引用的文件不再存在或对其访问已被撤销。

NFS3ERR_REMOTE 路径中远程级别太多。参数中给出的文件句柄引用服务器上非本地文件系统中的文件。

NFS3ERR_BADHANDLE 非法NFS文件句柄。文件句柄未通过内部一致性检查。

NFS3ERR_NOT_SYNC 在SETATTR操作期间检测到更新同步不匹配。

NFS3ERR_BAD_COOKIE READDIR或READDIRPLUS cookie过期。

NFS3ERR_NOTSUPP 操作不受支持。

NFS3ERR_TOOSMALL 缓冲区或请求太小。

NFS3ERR_SERVERFAULT 服务器上发生了不映射到任何合法NFS版本3协议错误值的错误。客户端应将其转换为适当的错误。UNIX客户端可以选择将其转换为EIO。

NFS3ERR_BADTYPE 尝试创建服务器不支持类型的对象。

NFS3ERR_JUKEBOX 服务器启动了请求,但无法及时完成它。客户端应该等待,然后使用新的RPC事务ID尝试请求。例如,支持分层存储并接收到处理已迁移文件的请求的服务器应该返回此错误。在这种情况下,服务器应该启动迁移过程并用此错误响应客户端。

1
2
3
4
5
6
7
8
9
10
11
ftype3

   enum ftype3 {
      NF3REG    = 1,
      NF3DIR    = 2,
      NF3BLK    = 3,
      NF3CHR    = 4,
      NF3LNK    = 5,
      NF3SOCK   = 6,
      NF3FIFO   = 7
   };

枚举ftype3给出文件的类型。类型NF3REG是常规文件,NF3DIR是目录,NF3BLK是块特殊设备文件,NF3CHR是字符特殊设备文件,NF3LNK是符号链接,NF3SOCK是套接字,NF3FIFO是命名管道。注意必须遵循精确的枚举编码。

1
2
3
4
5
6
specdata3

   struct specdata3 {
        uint32     specdata1;
        uint32     specdata2;
   };

两个字的解释取决于文件系统对象的类型。对于块特殊(NF3BLK)或字符特殊(NF3CHR)文件,specdata1和specdata2分别是主设备号和次设备号。(这显然是UNIX特定的解释。)对于所有其他文件类型,这两个元素应该设置为0,或者值应该由客户端和服务器商定。如果客户端和服务器对这些值没有达成一致,客户端应该将这些字段视为设置为0。此数据字段作为fattr3结构的一部分返回,因此可以从所有返回属性的回复中获得。因为这些字段对于非设备对象在其他方面未使用,所以可以将带外信息从服务器传递到客户端。但是,再次强调,服务器和客户端必须就传递的值达成一致。

1
2
3
4
5
nfs_fh3

   struct nfs_fh3 {
      opaque       data<NFS3_FHSIZE>;
   };

nfs_fh3是服务器在LOOKUP、CREATE、SYMLINK、MKNOD、LINK或READDIRPLUS操作上返回的可变长度不透明对象,客户端在后续操作中使用它来引用文件。文件句柄包含服务器区分单个文件所需的所有信息。对客户端而言,文件句柄是不透明的。客户端存储文件句柄以供后续请求使用,可以通过逐字节比较来比较来自同一服务器的两个文件句柄是否相等,但不能以其他方式解释文件句柄的内容。如果来自同一服务器的两个文件句柄相等,它们必须引用同一文件,但如果它们不相等,则不能得出任何结论。服务器应该尝试保持文件句柄和文件之间的一对一对应关系,但这不是必需的。客户端应该仅使用文件句柄比较来提高性能,而不是为了正确行为。

服务器可以随时撤销文件句柄提供的访问。如果调用中传递的文件句柄引用服务器上不再存在的文件系统对象,或者该文件句柄的访问已被撤销,应该返回错误NFS3ERR_STALE。

1
2
3
4
5
6
nfstime3

   struct nfstime3 {
      uint32   seconds;
      uint32   nseconds;
   };

nfstime3结构给出自1970年1月1日格林威治标准时间午夜以来的秒数和纳秒数。它用于传递时间和日期信息。与文件相关的时间都是服务器时间,除了在SETATTR操作中客户端可以显式设置文件时间的情况。服务器在处理时间值时与本地时间进行转换,尽可能保持准确性。如果为文件存储的时间戳精度低于NFS版本3协议定义的精度,可能会发生精度损失。建议使用辅助时间维护协议来减少客户端和服务器时间偏差。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fattr3

   struct fattr3 {
      ftype3     type;
      mode3      mode;
      uint32     nlink;
      uid3       uid;
      gid3       gid;
      size3      size;
      size3      used;
      specdata3  rdev;
      uint64     fsid;
      fileid3    fileid;
      nfstime3   atime;
      nfstime3   mtime;
      nfstime3   ctime;
   };

此结构定义文件系统对象的属性。它由对象上的大多数操作返回;在影响两个对象的操作的情况下(例如,修改目标目录属性并为新创建的目录定义新属性的MKDIR),可能返回两者的属性。在某些情况下,属性在下面定义的wcc_data结构中返回;在其他情况下,属性单独返回。与NFS版本2协议的主要变化是许多字段已被加宽,主/次设备信息现在以不同的结构呈现,而不是打包在一个字中。

fattr3结构包含文件的基本属性。所有服务器应该支持这组属性,即使它们必须模拟某些字段。Type是文件的类型。Mode是保护模式位。Nlink是文件的硬链接数 - 即同一文件的不同名称的数量。Uid是文件所有者的用户ID。Gid是文件组的组ID。Size是文件的字节大小。Used是文件实际使用的磁盘空间字节数(由于文件可能有洞或由于碎片而可能大于大小)。Rdev描述文件类型为NF3CHR或NF3BLK时的设备文件 - 参见第20页的specdata3。Fsid是文件系统的文件系统标识符。Fileid是一个在文件系统内唯一标识文件的数字(在UNIX上这将是inode号)。Atime是文件数据最后访问的时间。Mtime是文件数据最后修改的时间。Ctime是文件属性最后更改的时间。写入文件除了更改mtime外还更改ctime。

模式位定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
0x00800 执行时设置用户ID。
0x00400 执行时设置组ID。
0x00200 保存交换文本(POSIX中未定义)。
0x00100 所有者的读权限。
0x00080 所有者的写权限。
0x00040 文件所有者的执行权限。或目录中所有者的查找(搜索)权限。
0x00020 组的读权限。
0x00010 组的写权限。
0x00008 文件组的执行权限。或目录中组的查找(搜索)权限。
0x00004 其他人的读权限。
0x00002 其他人的写权限。
0x00001 文件其他人的执行权限。或目录中其他人的查找(搜索)权限。
1
2
3
4
5
6
7
8
post_op_attr

   union post_op_attr switch (bool attributes_follow) {
   case TRUE:
      fattr3   attributes;
   case FALSE:
      void;
   };

此结构用于在那些不直接涉及操作属性的操作中返回属性。此NFS协议修订的一个原则是从指示的操作返回实际值,而不是从附带操作返回错误。设计post_op_attr结构是为了允许服务器从获取属性时遇到的错误中恢复。

这似乎使返回属性成为可选的。但是,强烈鼓励服务器实现者尽可能返回属性,即使在返回错误时也是如此。

1
2
3
4
5
6
7
wcc_attr

   struct wcc_attr {
      size3       size;
      nfstime3    mtime;
      nfstime3    ctime;
   };

这是更好地支持弱缓存一致性语义所需的前操作属性子集。Size是操作前对象的文件字节大小。Mtime是操作前对象最后修改的时间。Ctime是操作前对象属性最后更改的时间。有关wcc_attr的讨论,请参见第24页的讨论。

客户端使用mtime来检测驻留在服务器上的文件系统对象的更改取决于服务器上时间基础的粒度。

1
2
3
4
5
6
7
8
pre_op_attr

   union pre_op_attr switch (bool attributes_follow) {
   case TRUE:
        wcc_attr  attributes;
   case FALSE:
        void;
   };
1
2
3
4
5
6
wcc_data

   struct wcc_data {
      pre_op_attr    before;
      post_op_attr   after;
   };

当客户端执行修改服务器上文件或目录状态的操作时,它不能立即从后操作属性确定刚刚执行的操作是否是自客户端上次接收到对象属性以来对该对象的唯一操作。这很重要,因为如果中间操作更改了对象,客户端将需要使对象的任何缓存数据失效(除了它刚刚写入的数据)。

为了处理这个问题,引入了弱缓存一致性数据或wcc_data的概念。wcc_data结构由操作前对象的某些关键字段以及操作后对象的属性组成。此信息允许客户端比NFS版本2协议实现更准确地管理其缓存。术语”弱缓存一致性”强调此机制不提供缓存一致性协议将提供的严格服务器-客户端一致性。

为了支持弱缓存一致性模型,服务器需要能够获取对象的前操作属性,执行预期的修改操作,然后原子地获取后操作属性。如果在操作和任一获取属性操作之间存在对象被修改的窗口,那么客户端将无法确定它是否是修改对象的唯一实体。一些信息将丢失,从而削弱了弱缓存一致性保证。

1
2
3
4
5
6
7
8
post_op_fh3

   union post_op_fh3 switch (bool handle_follows) {
   case TRUE:
        nfs_fh3  handle;
   case FALSE:
        void;
   };

此NFS协议修订的一个原则是从指示的操作返回实际值,而不是从附带操作返回错误。设计post_op_fh3结构是为了允许服务器从构造文件句柄时遇到的错误中恢复。

这是用于从CREATE、MKDIR、SYMLINK、MKNOD和READDIRPLUS请求返回文件句柄的结构。在每种情况下,客户端可以通过在列出的操作之一成功返回后发出LOOKUP请求来获取文件句柄。返回文件句柄是一种优化,这样客户端就不必立即发出LOOKUP请求来获取文件句柄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
sattr3

   enum time_how {
      DONT_CHANGE        = 0,
      SET_TO_SERVER_TIME = 1,
      SET_TO_CLIENT_TIME = 2
   };

   union set_mode3 switch (bool set_it) {
   case TRUE:
      mode3    mode;
   default:
      void;
   };

   union set_uid3 switch (bool set_it) {
   case TRUE:
      uid3     uid;
   default:
      void;
   };

   union set_gid3 switch (bool set_it) {
   case TRUE:
      gid3     gid;
   default:
      void;
   };

   union set_size3 switch (bool set_it) {
   case TRUE:
      size3    size;
   default:
      void;
   };

   union set_atime switch (time_how set_it) {
   case SET_TO_CLIENT_TIME:
      nfstime3  atime;
   default:
      void;
   };

   union set_mtime switch (time_how set_it) {
   case SET_TO_CLIENT_TIME:
      nfstime3  mtime;
   default:
      void;
   };

   struct sattr3 {
      set_mode3   mode;
      set_uid3    uid;
      set_gid3    gid;
      set_size3   size;
      set_atime   atime;
      set_mtime   mtime;
   };

sattr3结构包含可以从客户端设置的文件属性。字段与fattr3结构中类似命名的字段相同。在NFS版本3协议中,可设置属性由包含一组判别联合的结构描述。每个联合指示是否更新相应属性,如果更新,如何更新。

使用两种形式的判别联合。在设置mode、uid、gid或size时,判别联合切换为布尔值set_it;如果为TRUE,则编码适当类型的值。

在设置atime或mtime时,联合切换为枚举类型set_it。如果set_it的值为DONT_CHANGE,则相应属性保持不变。如果值为SET_TO_SERVER_TIME,则服务器将相应属性设置为其本地时间;客户端不提供数据。最后,如果set_it的值为SET_TO_CLIENT_TIME,则属性设置为客户端在nfstime3结构中传递的时间。(有关时间粒度问题的讨论,请参见第86页的FSINFO。)

1
2
3
4
5
6
diropargs3

   struct diropargs3 {
      nfs_fh3     dir;
      filename3   name;
   };

diropargs3结构用于目录操作。文件句柄dir标识要在其中操作或访问文件的目录name。有关其他评论,请参见第101页的”文件名组件处理”。


3. 服务器过程

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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 关于失败时属性和一致性数据的一般说明

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

3.2 关于文件名的一般说明

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

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

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

  3. 值为”..”的文件名被假定为当前目录的父目录的别名,即包含指定目录的目录。如果服务器支持目录,即使这些目录不包含UNIX样式的”.”或”..”条目,服务器也应该准备好处理这种语义。

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

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

有关其他评论,请参见第101页的”文件名组件处理”。

3.3.0 过程0: NULL - 不做任何操作

SYNOPSIS

1
void NFSPROC3_NULL(void) = 0;

DESCRIPTION

过程NULL不做任何工作。它可用于允许服务器响应测试和计时。

IMPLEMENTATION

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

ERRORS

由于NULL过程不需要NFS版本3协议参数也不返回NFS版本3协议响应,它不能返回NFS版本3协议错误。但是,某些服务器实现可能基于安全和认证要求返回RPC错误。

3.3.1 过程1: GETATTR - 获取文件属性

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

1
2
3
4
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

ACCESS。

3.3.2 过程2: SETATTR - 设置文件属性

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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

1
2
3
4
5
6
7
8
9
10
11
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和MKNOD。

3.3.3 过程3: LOOKUP - 查找文件名

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 要搜索的文件名。有关文件名的一般注释,请参见第30页。

成功返回时,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操作跨挂载点到不同文件系统的根目录,即使文件系统被导出。这并不阻止客户端访问服务器导出的文件系统层次结构,但客户端必须单独挂载每个文件系统,以便挂载点交叉发生在客户端上。给定的服务器实现可以根据该实现的特定能力或限制来细化这些规则。有关导出文件系统的讨论,请参阅[X/OpenNFS]。

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

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

ERRORS

1
2
3
4
5
6
7
8
NFS3ERR_IO
NFS3ERR_NOENT
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_NAMETOOLONG
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

CREATE、MKDIR、SYMLINK、MKNOD、READDIRPLUS和PATHCONF。

3.3.4 过程4: ACCESS - 检查访问权限

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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 要检查的访问权限的位掩码。

可以请求以下访问权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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请求中用于确定访问权限的认证信息。在后续读写操作中使用的是有效用户和组凭据。有关此主题的更多信息,请参见第98页”权限问题”中的注释。

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

ERRORS

1
2
3
4
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

GETATTR。

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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。(注意:NFS版本2协议的X/Open XNFS规范在此情况下将错误状态定义为NFSERR_NXIO。这与现有服务器实践不一致。)

ERRORS

1
2
3
4
5
6
7
NFS3ERR_IO
NFS3ERR_INVAL
NFS3ERR_ACCES
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_NOTSUPP
NFS3ERR_SERVERFAULT

SEE ALSO

READLINK、SYMLINK。

3.3.6 过程6: READ - 从文件读取

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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。成功读取空文件将始终返回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的正确方法。

一些NFS版本2协议服务器实现如果文件系统对象类型不是常规文件,错误地返回NFSERR_ISDIR。NFS版本3协议的正确返回值是NFS3ERR_INVAL。

ERRORS

1
2
3
4
5
6
7
NFS3ERR_IO
NFS3ERR_NXIO
NFS3ERR_ACCES
NFS3ERR_INVAL
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

READLINK。

3.3.7 过程7: WRITE - 写入文件

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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值的情况下销毁任何数据,并且它不会以低于客户端请求的级别提交数据和元数据。有关数据何时提交到稳定存储的更多信息,请参见第92页COMMIT的讨论。

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 文件的弱缓存一致性数据。对于只需要后写入文件属性的客户端,这些可以在file_wcc.after中找到。即使写入失败,也返回完整的wcc_data,以允许客户端确定失败的写入是否导致文件发生任何更改。

如果客户端以stable参数设置为UNSTABLE向服务器写入数据,并且回复产生DATA_SYNC或UNSTABLE的committed响应,那么客户端将在未来的某个时间跟随COMMIT操作,将未决的异步数据和元数据与服务器的稳定存储同步,除非客户端出错。由于客户端崩溃或其他错误,服务器可能不会收到后续的COMMIT。

IMPLEMENTATION

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

服务器可能写入少于count字节的数据。在这种情况下,除非根本没有写入数据,否则服务器不应该返回错误。如果服务器写入少于count字节,客户端应该发出另一个WRITE来写入剩余数据。

假设将数据写入文件的行为会导致文件的mtime更新。但是,除非文件内容被更改,否则文件的mtime不应该更改。因此,count设置为0的WRITE请求不应该导致文件的mtime更新。

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

稳定存储的定义历来是一个争议点。稳定存储的以下预期属性可能有助于解决实现中的设计问题。稳定存储是持久的存储,能够经受:

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

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

定义了一个cookie verf,以允许客户端检测可能丢失缓存、未提交数据的NFS版本3协议服务器的不同实例。在最可能的情况下,verf允许客户端检测服务器重启。需要此信息,以便客户端能够安全地确定服务器是否可能丢失了缓存数据。如果服务器意外失败,并且客户端有之前WRITE请求的未提交数据(使用stable参数设置为UNSTABLE执行,并且结果committed也返回为UNSTABLE),它可能没有将缓存数据刷新到稳定存储。恢复的负担在客户端,客户端需要将数据重新传输到服务器。

建议的verf cookie是使用服务器启动时间或服务器上次启动的时间(如果重启服务器而不重启导致缓冲区丢失)。

结果中的committed字段允许客户端进行更有效的缓存。如果服务器将所有WRITE请求提交到稳定存储,那么它应该在返回时将committed设置为FILE_SYNC,而不管参数中stable字段的值如何。使用NVRAM加速器的服务器可以选择实施此策略。客户端可以使用它来增加缓存的有效性,丢弃已经在服务器上提交的缓存数据。

一些实现可能在用户配额超过时返回NFS3ERR_NOSPC而不是NFS3ERR_DQUOT。

一些NFS版本2协议服务器实现如果文件系统对象类型不是常规文件,错误地返回NFSERR_ISDIR。NFS版本3协议的正确返回值是NFS3ERR_INVAL。

ERRORS

1
2
3
4
5
6
7
8
9
10
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 - 创建文件

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 一个判别联合,描述服务器如何处理文件创建以及适当的属性:

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的弱缓存一致性数据。对于只需要后CREATE目录属性的客户端,这些可以在dir_wcc.after中找到。

否则,CREATE3res.status包含失败时的错误,CREATE3res.resfail包含以下内容:

dir_wcc 目录where.dir的弱缓存一致性数据。对于只需要后CREATE目录属性的客户端,这些可以在dir_wcc.after中找到。即使CREATE失败,也返回完整的wcc_data,以允许客户端确定失败的CREATE是否导致目录发生任何更改。

IMPLEMENTATION

与NFS版本2协议不同,其中初始属性结构中的某些字段被重载以指示除常规文件外的设备和FIFO的创建,此过程仅支持常规文件的创建。在NFS版本3协议中引入MKNOD过程来处理设备和FIFO的创建。实现者没有理由在NFS版本3协议中重载CREATE语义。

NFS版本3协议CREATE过程的一个方面值得特别仔细考虑:引入的支持可靠独占创建常规文件的机制。当how.mode为EXCLUSIVE时,此机制发挥作用。在这种情况下,how.verf包含一个可以合理预期是唯一的验证器。客户端标识符(可能是客户端网络地址)和客户端生成的唯一数(可能是RPC事务标识符)的组合可能是合适的。

如果文件不存在,服务器创建文件并将验证器存储在稳定存储中。对于不提供任意文件属性存储机制的文件系统,服务器可以使用文件元数据的一个或多个元素来存储验证器。验证器必须存储在稳定存储中,以防止请求重传时的错误失败。假设执行独占创建是因为独占语义对应用程序至关重要。由于预期用途,独占CREATE不仅依赖通常易失的重复请求缓存来存储验证器。易失存储中的重复请求缓存在崩溃期间无法存活,实际上可能在长网络分区时刷新,打开故障窗口。在UNIX本地文件系统环境中,创建时验证器的预期存储位置是文件的元数据(时间戳)。因此,独占文件创建可能不包括初始属性,因为服务器将无处存储验证器。

如果服务器不能支持这些独占创建语义,可能是因为需要将验证器提交到稳定存储,它应该以错误NFS3ERR_NOTSUPP失败CREATE请求。

在独占CREATE请求期间,如果文件已经存在,服务器重建文件的验证器并将其与请求中的验证器进行比较。如果它们匹配,服务器将请求视为成功。请求被假定为更早成功请求的重复,回复丢失,并且服务器重复请求缓存机制未检测到。如果验证器不匹配,请求将被拒绝,状态为NFS3ERR_EXIST。

一旦客户端执行了成功的独占创建,它必须发出SETATTR来设置正确的文件属性。在此之前,它不应该依赖任何文件属性,因为服务器实现可能需要重载文件元数据来存储验证器。

使用GUARDED属性不提供恰好一次语义。特别是,如果回复丢失且服务器未检测到请求的重传,过程可能失败,返回NFS3ERR_EXIST,即使创建已经成功执行。

有关文件名的一般注释,请参见第30页。

ERRORS

1
2
3
4
5
6
7
8
9
10
11
12
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和PATHCONF。

3.3.9 过程9: MKDIR - 创建目录

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

1
2
3
4
5
6
7
8
9
10
11
12
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和PATHCONF。

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

1
2
3
4
5
6
7
8
9
10
11
12
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和PATHCONF。

3.3.11 过程11: MKNOD - 创建特殊设备

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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版本2协议中没有显式支持特殊文件类型创建的情况下,CREATE参数中的字段被重载以指示某些类型对象的创建。在NFS版本3协议中不需要这种重载。

如果服务器不支持任何定义的类型,应该返回错误NFS3ERR_NOTSUPP。否则,如果服务器不支持目标类型或目标类型非法,应该返回错误NFS3ERR_BADTYPE。注意NF3REG、NF3DIR和NF3LNK对MKNOD是非法类型。应该分别使用CREATE、MKDIR和SYMLINK过程来创建这些文件类型,而不是MKNOD。

ERRORS

1
2
3
4
5
6
7
8
9
10
11
12
13
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和PATHCONF。

3.3.12 过程12: REMOVE - 删除文件

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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版本2协议中一直是混淆的来源。

最后引用的概念是服务器特定的。但是,如果对象的前属性中nlink字段的值为1,客户端不应该依赖通过文件句柄引用对象。同样,客户端不应该依赖以前与对象关联的资源(磁盘空间、目录条目等)立即可用。因此,如果客户端需要在使用REMOVE删除文件后能够继续访问文件,客户端应该采取措施确保文件仍然可访问。通常使用的机制是使用RENAME将文件从旧名称重命名为新的隐藏名称。

有关文件名的一般注释,请参见第30页。

ERRORS

1
2
3
4
5
6
7
8
9
NFS3ERR_NOENT
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_NAMETOOLONG
NFS3ERR_ROFS
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

RMDIR和RENAME。

3.3.13 过程13: RMDIR - 删除目录

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
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 - 重命名文件或目录

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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和from.dir必须驻留在服务器上的同一文件系统上,[否则操作将失败]”意味着目录属性中的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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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和LINK。

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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从文件到目录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

对硬链接文件的任何属性的更改都会反映在所有链接的文件中。当对文件进行硬链接时,文件的属性应该有一个比LINK之前值大一的nlink值。RENAME下关于对象和目标驻留在同一文件系统的注释在这里也适用。关于目标名称的注释也适用。有关文件名的一般注释,请参见第30页。

ERRORS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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和FSINFO。

3.3.16 过程16: READDIR - 从目录读取

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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版本2协议中,返回的每个目录条目都包含一个标识目录中某个点的cookie。通过在后续READDIR中包含此cookie,客户端可以在目录中的任何点恢复目录读取。此方案的一个问题是服务器没有简单的方法来验证cookie是否有效。如果两个READDIR被一个或多个以某种方式更改目录的操作分隔(例如,重新排序或压缩),则第二个READDIR可能错过条目,或多次处理条目。如果cookie不再可用,例如指向目录条目的中间,服务器必须将cookie向下舍入到前一个条目的cookie,或向上舍入到目录中下一个条目的cookie。无论哪种方式都可能导致不正确的结果,而客户端不会意识到任何问题的存在。

在NFS版本3协议中,每个READDIR请求都包括一个cookie和一个cookie验证器。对于第一次调用,两者都设置为0。响应包括一个新的cookie验证器,每个条目一个cookie。对于后续READDIR,客户端必须同时呈现cookie和相应的cookie验证器。如果服务器检测到cookie不再有效,服务器将以状态NFS3ERR_BAD_COOKIE拒绝READDIR请求。客户端应该小心避免在修改目录内容的操作(如REMOVE和CREATE)之间保持目录条目cookie。

cookie-verifier机制的一个实现可能是服务器使用目录的修改时间。然而,这可能过于限制性。更好的方法是记录最后一次目录更改的时间,该更改以使cookie无法可靠解释的方式更改了目录组织。目录cookie总是有效的服务器可以自由地始终使用零作为验证器。

服务器可能返回少于count字节的XDR编码条目。客户端在请求中指定的count应该大于或等于FSINFO dtpref。

由于UNIX客户端给文件id值零特殊含义,UNIX客户端应该小心将零文件id值映射到某个其他值,服务器应该尝试避免发送零文件id。

ERRORS

1
2
3
4
5
6
7
8
NFS3ERR_IO
NFS3ERR_ACCES
NFS3ERR_NOTDIR
NFS3ERR_BAD_COOKIE
NFS3ERR_TOOSMALL
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

READDIRPLUS和FSINFO。

3.3.17 过程17: READDIRPLUS - 扩展目录读取

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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中,每个条目返回文件名和fileid。在READDIRPLUS中,每个条目返回名称、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

1
2
3
4
5
6
7
8
9
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 - 获取动态文件系统信息

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

1
2
3
4
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

FSINFO。

3.3.19 过程19: FSINFO - 获取静态文件系统信息

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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版本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限制,因为不能保证服务器可以处理更大的写入。任何计数大于wtmax的WRITE将导致最多wtmax字节的短写入。

wtpref WRITE请求的首选大小。除非在性能或效率上有明显好处,否则这应该与wtmax相同。

wtmult WRITE请求大小的建议倍数。

dtpref READDIR请求的首选大小。

maxfilesize 文件系统上文件的最大大小。

time_delta 服务器时间粒度。使用SETATTR设置文件时间时,服务器只保证保持此精度的时间。如果这是{0, 1},服务器可以支持纳秒时间,{0, 1000000}表示毫秒精度,{1, 0}表示时间只能精确到最近一秒。

properties 文件系统属性的位掩码。定义了以下值:

1
2
3
4
5
6
7
8
9
10
11
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版本3协议请求的传输大小不仅取决于文件系统的特性,还取决于网络接口的特性,特别是最大传输单元(MTU)。服务器实现可以根据接收FSINFO请求的接口通告不同的传输大小(对于rtmax、rtpref、wtmax、wtpref和dtpref字段)。这是一个实现问题。

ERRORS

1
2
3
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

READLINK、WRITE、READDIR、FSSTAT和PATHCONF。

3.3.20 过程20: PATHCONF - 检索POSIX信息

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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版本2协议实现中,pathconf信息是通过MOUNT协议在挂载时获得的。获取它的正确位置是在这里,在NFS版本3协议本身中。

ERRORS

1
2
3
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

LOOKUP、CREATE、MKDIR、SYMLINK、MKNOD、RENAME、LINK和FSINFO。

3.3.21 过程21: COMMIT - 将服务器上的缓存数据提交到稳定存储

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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强制或刷新之前使用stable字段设置为UNSTABLE的WRITE过程调用写入的数据到稳定存储。在入口处,COMMIT3args中的参数是:

file 要刷新(提交)数据的文件的文件句柄。这必须标识类型为NF3REG的文件系统对象。

offset 文件中开始刷新的位置。偏移量0意味着从文件开头开始刷新数据。

count 要刷新的数据字节数。如果count为0,则执行从offset到文件末尾的刷新。

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

file_wcc 文件的弱缓存一致性数据。对于只需要后操作文件属性的客户端,这些可以在file_wcc.after中找到。

verf 这是一个cookie,客户端可以使用它来确定服务器在对WRITE的调用和后续对WRITE或COMMIT的调用之间是否重启。此cookie在NFS版本3协议服务的单个启动会话期间必须一致,并且必须在可能丢失未提交数据的NFS版本3协议服务器实例之间唯一。

否则,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请求,即从偏移量0开始且count为0,它应该执行等效于fsync()文件的操作。否则,它应该安排将偏移量和count指定范围内的缓存数据刷新到稳定存储。在这两种情况下,任何与文件关联的元数据必须在返回之前刷新到稳定存储。服务器上没有任何内容要刷新并不是错误。这意味着需要刷新的数据和元数据已经刷新或在最后一次服务器故障期间丢失。

COMMIT的客户端实现稍微复杂一些。客户端希望将客户端缓冲区提交到稳定存储有两个原因。第一个是客户端想要重用缓冲区。在这种情况下,缓冲区的偏移量和计数在COMMIT请求中发送给服务器。服务器然后根据偏移量和计数刷新任何缓存数据,并刷新与文件关联的任何元数据。然后它返回刷新状态和verf验证器。客户端生成COMMIT的另一个原因是完整文件刷新,如关闭时可能执行的操作。在这种情况下,客户端将收集此文件的所有包含未提交数据的缓冲区,执行偏移量为0且count为0的COMMIT操作,然后释放所有这些缓冲区。任何其他脏缓冲区将按照正常方式发送到服务器。

此实现需要对客户端上的缓冲区缓存进行一些修改。在缓冲区以stable UNSTABLE写入后,在通过COMMIT操作刷新或通过stable设置为FILE_SYNC或DATA_SYNC的WRITE操作写入之前,它必须被视为客户端系统的脏缓冲区。这样做是为了防止缓冲区在数据能够刷新到服务器上的稳定存储之前被释放和重用。

当来自WRITE或COMMIT操作的响应包含意外verf时,客户端需要将所有包含未提交缓存数据的缓冲区重新传输到服务器。如何完成此操作取决于实现者。如果只有一个感兴趣的缓冲区,那么它可能应该在适当稳定标志的WRITE请求中发回。如果有多个,那么值得将所有缓冲区在stable设置为UNSTABLE的WRITE请求中重新传输,然后重新传输COMMIT操作以将服务器上的所有数据刷新到稳定存储。这些重传的时间留给实现者。

上述描述适用于基于页面缓存的系统以及基于缓冲区的系统。在这些系统中,虚拟内存系统需要修改而不是缓冲区缓存。

有关WRITE的其他注释,请参见第49页。

ERRORS

1
2
3
4
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT

SEE ALSO

WRITE。


4. 实现问题

NFS版本3协议设计为允许不同操作系统共享文件。但是,由于它是在UNIX环境中设计的,许多操作具有类似于UNIX文件系统操作的语义。本节讨论一些一般的实现特定细节和语义问题。过程描述包含针对该过程的实现注释。

已经写了许多描述构建NFS版本2协议实现时遇到问题的论文。最好的概述论文仍然是[Sandberg]。[Israel]、[Macklem]和[Pawlowski]描述了其他实现。[X/OpenNFS]提供了NFS版本2协议和支持协议的完整描述,以及实现问题和过程及错误语义的讨论。构建NFS版本2协议实现时遇到的许多问题在构建NFS版本3协议实现时也会遇到。

4.1 多版本支持

RPC协议明确支持服务的版本控制。NFS版本3协议的客户端和服务器实现应该支持两个版本,以实现完全的向后兼容性。RPC绑定协议的默认行为是客户端和服务器使用它们都支持的最高版本号进行绑定。不能轻松支持两个版本的客户端或服务器实现(例如,由于内存限制)将不得不选择支持哪个版本。NFS版本2协议将是一个安全的选择,因为完全功能的客户端和服务器应该支持两个版本。但是,此选择需要在考虑所有要求的情况下做出。

4.2 服务器/客户端关系

NFS版本3协议设计为允许服务器尽可能简单和通用。有时服务器的简单性可能成为一个问题,如果客户端实现了复杂的文件系统语义。

例如,一些操作系统允许删除打开的文件。进程可以打开文件,并且在它打开时从目录中删除它。只要进程保持打开,该文件就可以被读取和写入,即使该文件在文件系统中没有名称。无状态服务器不可能实现这些语义。客户端可以做一些技巧,比如在删除时重命名文件(到隐藏名称),只在关闭时物理删除它。NFS版本3协议提供足够的功能来实现客户端上的大多数文件系统语义。

每个NFS版本3协议客户端也可能成为服务器,远程和本地挂载的文件系统可以自由混合。当客户端遍历远程文件系统的目录树并到达服务器上另一个远程文件系统的挂载点时,这会产生一些问题。允许服务器跟随第二个远程挂载将需要循环检测、服务器查找和用户重新验证。相反,NFS版本2协议和NFS版本3协议实现通常不让客户端跨服务器的挂载点。当客户端对服务器挂载了文件系统的目录执行LOOKUP时,客户端看到的是底层目录而不是挂载的目录。

例如,如果服务器有一个名为/usr的文件系统,并在/usr/src上挂载另一个文件系统,如果客户端挂载/usr,它看不到挂载版本的/usr/src。客户端可以执行与服务器挂载点匹配的远程挂载来维护服务器的视图。在此示例中,客户端还必须挂载/usr/src以及/usr,即使它们来自同一服务器。

4.3 路径名解释

路径名总是在客户端解析的规则有一些复杂性。例如,符号链接在不同客户端上可能有不同的解释。本规范中没有对此问题的答案。

非UNIX实现的另一个常见问题是路径名”..”的特殊解释,表示给定目录的父目录。协议的未来修订可能会使用显式标志来指示父目录 - 但是这不是问题,因为许多工作的非UNIX实现存在。

4.4 权限问题

严格来说,NFS版本3协议不定义服务器使用的权限检查。但是,预期服务器将使用AUTH_UNIX样式的认证执行正常的操作系统权限检查,作为其保护机制的基础,或另一种更强的认证形式,如AUTH_DES或AUTH_KERB。使用AUTH_UNIX认证,服务器在每次调用时获取客户端的有效uid、有效gid和组,并使用它们来检查权限。这些是所谓的UNIX凭据。AUTH_DES和AUTH_KERB使用网络名称或netname作为标识的基础(UNIX服务器从中派生必要的标准UNIX凭据)。这种方法有问题,但已经解决了。

使用uid和gid意味着客户端和服务器共享相同的uid列表。每个服务器和客户端对必须具有相同的用户到uid和组到gid的映射。由于每个客户端也可以是服务器,这往往意味着整个网络共享相同的uid/gid空间。如果不是这种情况,那么通常由服务器执行一些自定义凭据映射,将凭据从一个认证域映射到另一个认证域。管理共享用户空间或提供用户ID映射机制的技术讨论超出了本规范的范围。

另一个问题源于通常有状态的打开操作。大多数操作系统在打开时检查权限,然后在每次读写请求时检查文件是否打开。对于无状态服务器,服务器无法检测文件是否打开,必须在每次读写调用时进行权限检查。使用此修订中的ACCESS过程调用可以提供UNIX客户端访问权限检查的语义,它允许客户端在不尝试操作的情况下显式检查访问权限。在本地文件系统上,用户可以打开文件,然后更改权限,使任何人都无法接触它,但由于文件是打开的,仍然可以写入该文件。相比之下,在远程文件系统上,写入将失败。为了解决这个问题,服务器的权限检查算法应该允许文件的所有者无论权限设置如何都能访问它。这在实际的NFS版本3协议服务器实现中是必需的,但它确实偏离了正确的本地文件系统语义。但是,这不应该影响ACCESS过程返回的访问权限结果。

类似的问题与通过网络分页执行程序有关。操作系统通常在为请求分页打开文件之前检查执行权限,然后从打开的文件读取块。在本地UNIX文件系统中,可执行文件不需要读取权限来执行(分页)。NFS版本3协议服务器无法区分正常文件读取(其中读取权限位有意义)和请求分页读取(如果对该用户或组或公共设置了执行位,服务器应该允许访问可执行文件)。为了使其工作,如果调用中给出的uid通过所有权、组成员身份或公共访问对文件具有执行或读取权限,服务器允许读取文件。同样,这偏离了正确的本地文件系统语义。

在大多数操作系统中,特定用户(在UNIX上为uid 0)可以访问所有文件,无论它们具有什么权限和所有权。在服务器上可能不允许这种超级用户权限,因为任何可以在其客户端上成为超级用户的人都可以访问所有远程文件。UNIX服务器默认将uid 0映射到特殊值(UID_NOBODY),同时也映射组列表,然后再进行其访问检查。服务器实现可以提供更改此映射的机制。这除了NFS版本3协议根文件系统(无磁盘NFS版本3协议客户端支持所需)外都有效,其中无法避免超级用户访问。在服务器上使用导出选项来限制允许超级用户访问的客户端集。

4.5 重复请求缓存

典型的NFS版本3协议故障恢复模型使用客户端超时和重传来处理服务器崩溃、网络分区和丢失的服务器回复。重试的请求称为原始请求的重复。

在文件服务器上下文中使用时,术语幂等可用于区分操作类型。幂等请求是服务器可以多次执行并产生等效结果的请求(尽管实际上,作为副作用,它可能会更改,例如,对于READ,文件的访问时间)。一些NFS操作显然是非幂等的。它们不能在没有特殊注意的情况下重新处理,因为如果第二次尝试可能会失败。CREATE请求,例如,可用于创建所有者没有写入权限的文件。如果原始请求成功,则此请求的重复不能成功。同样,文件只能被删除一次。

执行重复非幂等请求引起的副作用可能是破坏性的(例如,导致丢失写入的截断操作)。无状态设计与不可靠网络传输(UDP)的常见选择的结合意味着非幂等请求的破坏性重放的可能性。但更准确地说,是NFS版本3协议在不可靠RPC机制之上的固有状态设计产生了非幂等请求破坏性重放的可能性,因为即使在可靠连接导向传输上的NFS版本3协议实现中,具有自动重新建立的连接中断也需要重复请求处理(客户端将重新传输请求,服务器需要处理潜在的非幂等重复请求)。

大多数NFS版本3协议服务器实现使用最近请求的缓存(称为重复请求缓存)来处理重复的非幂等请求。重复请求缓存提供短期内存机制,其中记住请求的原始完成状态,操作只尝试一次。如果收到此请求的重复副本,则返回原始完成状态。

重复请求缓存机制在减少重复NFS版本3协议请求引起的破坏性副作用方面一直很有用。但是,此机制并不能在所有故障模式下保证避免这些破坏性副作用。大多数服务器将重复请求缓存存储在RAM中,因此如果服务器崩溃,内容将丢失。例外情况可能发生在冗余服务器高可用性方法中,其中文件系统本身可能用于共享重复请求缓存状态。即使缓存在服务器重启后仍然存在(或在髙可用性情况下的故障转移),其有效性也是其大小的函数。网络分区可能导致缓存条目在客户端收到相应请求的回复之前被重用。如果发生这种情况,重复请求将被作为新请求处理,可能具有破坏性副作用。

重复请求缓存的实现和使用的良好描述可以在[Juszczak]中找到。

4.6 文件名组件处理

NFS版本3协议的服务器实现经常对可以创建的名称施加限制。许多服务器还将禁止使用包含某些字符的名称,例如服务器操作系统使用的路径组件分隔符。例如,UFS文件系统将拒绝包含”/”的名称,而”.”和”..”在UFS中被区分,在创建文件系统对象时不能指定为名称。这些错误的正确错误状态值在每个过程参数的描述中指定。这些值(符合NFS版本2协议服务器实践)不一定明显,从一个过程到下一个过程也不一致。

4.7 同步修改操作

NFS版本3协议中的数据修改操作是同步的。当过程返回给客户端时,客户端可以假设操作已完成,与请求关联的任何数据现在都在稳定存储上。

4.8 稳定存储

NFS版本3协议服务器必须能够从多次电源故障(包括级联电源故障,即快速连续的几次电源故障)、操作系统故障和除存储介质本身(例如磁盘、非易失性RAM)之外的组件的硬件故障中恢复而不丢失数据。

NFS服务器允许的稳定存储的一些示例包括:

  1. 数据的介质提交,即修改的数据已成功写入磁盘介质,例如磁盘盘片。
  2. 具有电池支持驱动器上中间存储或不间断电源系统(UPS)的即时回复磁盘驱动器。
  3. 具有电池支持中间存储和恢复软件的服务器数据提交。
  4. 具有不间断电源系统(UPS)和恢复软件的缓存提交。

相反,以下不是稳定存储的示例:

  1. 没有电池支持驱动器上中间存储或不间断电源系统(UPS)的即时回复磁盘驱动器。
  2. 没有同时具有不间断电源系统(UPS)和恢复软件的缓存提交。

唯一的例外(在此次协议修订中引入)如WRITE过程所述关于stable位的处理,以及COMMIT过程的使用。使用同步COMMIT过程在NFS版本3协议中提供必要的语义支持。

4.9 查找和名称解析

对NFS版本3协议的一个常见反对意见是客户端通过组件逐一LOOKUP解析名称的理念。反对意见是这是低效的,因为组件逐一LOOKUP的延迟将难以忍受。

实现实践解决了这个问题。名称缓存,提供组件到文件句柄的映射,保持在客户端上,以短路实际的线上LOOKUP调用。缓存受限制属性的缓存超时参数约束。

4.10 自适应重传

大多数客户端实现使用指数退避策略到某个最大重传值,或尝试拥塞避免的更自适应策略。NFS请求重传中的拥塞避免方案基于[Jacobson]中提出的工作。[Nowicki]和[Macklem]描述了应用于UDP上NFS协议的拥塞避免方案。

4.11 缓存策略

NFS版本3协议不定义客户端或服务器上的缓存策略。特别是,没有对客户端和服务器之间的严格缓存一致性支持,也没有对不同客户端之间的支持。参见[Kazar]关于几个分布式文件系统中缓存同步问题和机制的讨论。

4.12 稳定写入与非稳定写入

WRITE参数中stable字段的设置,即是否进行异步WRITE请求,在UNIX客户端上是直接的。如果NFS版本3协议客户端接收到未标记为异步的写入请求,它应该生成stable设置为TRUE的RPC。如果请求被标记为异步,则应该生成stable设置为FALSE的RPC。如果回复返回的committed字段设置为TRUE,客户端应该只标记写入请求为完成,不需要进一步操作。如果committed设置为FALSE,表示缓冲区未与服务器的磁盘同步,客户端需要以某种方式标记缓冲区,指示缓冲区的副本存在于服务器上,不需要将新副本发送到服务器,但需要提交。

注意此算法为缓冲区引入了一个新状态,因此现在缓冲区有三个状态。三个状态是脏、已完成但需要提交、已完成。客户端上的这个额外状态可能需要修改NFS版本3协议客户端外部的系统。

一个被拒绝的提案是向WRITE操作添加一个布尔commit参数。它将用于指示服务器是否应该在写入后执行完整的文件提交。如果客户端知道它正在对文件进行最后一次写入,这似乎可能有用。但是,很难看到这在现有客户端架构中如何使用。

异步写入打开了与写入共享相关的问题窗口。例如:客户端A异步写入一些数据。客户端A仍然持有缓冲区缓存,等待稍后提交它们。客户端B读取修改的数据并将其写回服务器。然后服务器崩溃。当它重新启动时,客户端A发出COMMIT操作,返回不同的cookie以及更改的属性。在这种情况下,正确的操作可能不是也可能不是重新传输缓存缓冲区。不幸的是,客户端A无法确定,因此它需要重新传输缓冲区,从而覆盖客户端B的更改。幸运的是,写共享很少,解决方案匹配当前的写共享情况。如果不使用锁定进行同步,行为将是不确定的。

在髙可用性(冗余系统)服务器实现中,存在两种与verf更改相关的案例。如果髙可用性服务器实现不使用共享内存方案,那么verf应该在故障转移时更改,因为未同步的数据对第二个处理器不可用,并且不能保证拥有数据缓存的服务器能够在关闭之前将其刷新到稳定存储。客户端需要重新传输数据以确保安全。在共享内存髙可用性服务器实现中,verf不需要更改,因为服务器仍然可以访问缓存数据以进行刷新。但是,在共享内存髙可用性实现中关于verf的确切策略取决于服务器实现者。

4.13 32位客户端/服务器和64位客户端/服务器

NFS版本3协议的64位特性引入了几个兼容性问题。最显著的两个是不匹配的客户端和服务器,即32位客户端和64位服务器,或64位客户端和32位服务器。

64位客户端和32位服务器的问题很容易处理。客户端永远不会遇到它无法处理的文件。如果它向服务器发送服务器无法处理的请求,服务器应该以适当的错误拒绝请求。

32位客户端和64位服务器的问题要难处理得多。在这种情况下,服务器没有问题,因为它可以处理客户端可以生成的任何内容。但是,客户端可能遇到它无法处理的文件。客户端将无法处理其大小不能用32位表示的文件。因此,客户端无法正确地将文件的大小解码到其本地属性结构中。此外,文件可能在客户端访问文件时增长超过客户端的限制。

这些问题的解决方案留给各个实现者。但是,有两种常用的方法来解决这种情况。实现者可以在它们之间选择,甚至可以发明一个全新的解决方案。

最常见的解决方案是客户端拒绝访问任何大小不能用32位表示的文件。这可能是最安全的,但当文件在客户端访问时增长超过客户端的限制时确实会引入一些奇怪的语义。文件在被访问时变得不可访问。

第二种解决方案是客户端将任何大于它能处理的大小映射到它能处理的最大大小。实际上,它在对应用程序撒谎。这允许应用程序在给定32位偏移限制的情况下尽可能多地访问文件。这消除了文件在访问后有效消失的奇怪语义,但确实引入了其他问题。客户端将无法访问整个文件。

目前,第一种解决方案是推荐的解决方案。但是,鼓励客户端实现者尽其所能减少这种情况的影响。


5. 附录I: 挂载协议

从NFS版本2协议到NFS版本3协议的变更需要对MOUNT协议进行一些更改。为了满足NFS版本3协议的需求,定义了新版本的MOUNT协议。这个新协议满足NFS版本3协议的要求,并解决了几个其他当前市场需求。

5.1 RPC信息

5.1.1 认证

MOUNT服务在NULL过程中使用AUTH_NONE。所有其他过程使用AUTH_UNIX、AUTH_SHORT、AUTH_DES或AUTH_KERB。将来可能支持其他认证类型。

5.1.2 常量

这些是调用MOUNT服务所需的RPC常量。它们以十进制给出。

1
2
PROGRAM  100005
VERSION  3

5.1.3 传输地址

MOUNT服务通常在TCP和UDP协议上支持。应该查询rpcbind守护进程以获取正确的传输地址。

5.1.4 大小

1
2
3
const MNTPATHLEN = 1024;  /* 路径名中的最大字节数 */
const MNTNAMLEN  = 255;   /* 名称中的最大字节数 */
const FHSIZE3    = 64;    /* V3文件句柄中的最大字节数 */

5.1.5 基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef opaque fhandle3<FHSIZE3>;
typedef string dirpath<MNTPATHLEN>;
typedef string name<MNTNAMLEN>;

enum mountstat3 {
   MNT3_OK = 0,                 /* 无错误 */
   MNT3ERR_PERM = 1,            /* 不是所有者 */
   MNT3ERR_NOENT = 2,           /* 没有这样的文件或目录 */
   MNT3ERR_IO = 5,              /* I/O错误 */
   MNT3ERR_ACCES = 13,          /* 权限被拒绝 */
   MNT3ERR_NOTDIR = 20,         /* 不是目录 */
   MNT3ERR_INVAL = 22,          /* 无效参数 */
   MNT3ERR_NAMETOOLONG = 63,    /* 文件名太长 */
   MNT3ERR_NOTSUPP = 10004,     /* 操作不支持 */
   MNT3ERR_SERVERFAULT = 10006  /* 服务器上的故障 */
};

5.2 服务器过程

以下各节定义MOUNT版本3协议服务器提供的RPC过程。RPC过程号在页面顶部与名称和版本一起给出。SYNOPSIS提供过程名称、参数名称列表、结果名称列表,后跟XDR参数声明和结果声明。SYNOPSIS中的信息按照[RFC1014]中的定义在RPC数据描述语言中指定。DESCRIPTION部分告诉过程预期做什么以及如何使用其参数和结果。ERRORS部分列出针对特定类型失败返回的错误。IMPLEMENTATION字段描述过程预期如何工作以及客户端应如何使用它。

1
2
3
4
5
6
7
8
9
10
program MOUNT_PROGRAM {
   version MOUNT_V3 {
      void      MOUNTPROC3_NULL(void)    = 0;
      mountres3 MOUNTPROC3_MNT(dirpath)  = 1;
      mountlist MOUNTPROC3_DUMP(void)    = 2;
      void      MOUNTPROC3_UMNT(dirpath) = 3;
      void      MOUNTPROC3_UMNTALL(void) = 4;
      exports   MOUNTPROC3_EXPORT(void)  = 5;
   } = 3;
} = 100005;

5.2.0 过程0: Null - 不做任何操作

SYNOPSIS

1
void MOUNTPROC3_NULL(void) = 0;

DESCRIPTION

过程NULL不做任何工作。它可用于允许服务器响应测试和计时。

IMPLEMENTATION

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

ERRORS

由于NULL过程不需要MOUNT协议参数也不返回MOUNT协议响应,它不能返回MOUNT协议错误。但是,某些服务器实现可能基于安全和认证要求返回RPC错误。

5.2.1 过程1: MNT - 添加挂载条目

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
mountres3 MOUNTPROC3_MNT(dirpath) = 1;

struct mountres3_ok {
     fhandle3   fhandle;
     int        auth_flavors<>;
};

union mountres3 switch (mountstat3 fhs_status) {
case MNT_OK:
     mountres3_ok  mountinfo;
default:
     void;
};

DESCRIPTION

过程MNT将服务器上的路径名映射到文件句柄。路径名是描述服务器上目录的ASCII字符串。如果调用成功(MNT3_OK),服务器返回一个NFS版本3协议文件句柄和一个RPC认证风格的向量,这些认证风格支持客户端对该文件句柄(或从其派生的任何文件句柄)的使用。认证风格在[RFC1057]的第7.2节和第9节中定义。

IMPLEMENTATION

如果mountres3.fhs_status为MNT3_OK,那么mountres3.mountinfo包含目录的文件句柄和可接受认证风格的列表。此文件句柄只能在NFS版本3协议中使用。此过程还导致服务器在其挂载列表中添加一个新条目,记录此客户端已挂载了该目录。需要AUTH_UNIX认证或更好的认证。

ERRORS

1
2
3
4
5
MNT3ERR_NOENT
MNT3ERR_IO
MNT3ERR_ACCES
MNT3ERR_NOTDIR
MNT3ERR_NAMETOOLONG

5.2.2 过程2: DUMP - 返回挂载条目

SYNOPSIS

1
2
3
4
5
6
7
8
9
mountlist MOUNTPROC3_DUMP(void) = 2;

typedef struct mountbody *mountlist;

struct mountbody {
     name       ml_hostname;
     dirpath    ml_directory;
     mountlist  ml_next;
};

DESCRIPTION

过程DUMP返回远程挂载文件系统的列表。mountlist为每个客户端主机名和目录对包含一个条目。

IMPLEMENTATION

此列表派生自服务器维护的已使用MNT过程请求文件句柄的客户端列表。只有当客户端调用UMNT或UMNTALL过程时,才会从此列表中删除条目。如果客户端崩溃并且没有对其之前挂载的所有文件系统发出UMNT调用,或者客户端由于软件或硬件问题而崩溃,则条目可能过时。

ERRORS

从此过程不能返回任何MOUNT协议错误。但是,可能返回认证或其他RPC失败的RPC错误。

5.2.3 过程3: UMNT - 删除挂载条目

SYNOPSIS

1
void MOUNTPROC3_UMNT(dirpath) = 3;

DESCRIPTION

过程UMNT删除之前从此客户端进行MNT调用的目录的挂载列表条目。需要AUTH_UNIX认证或更好的认证。

IMPLEMENTATION

通常,服务器实现维护已挂载文件系统的客户端列表。过去,此列表用于通知客户端服务器将要关闭。

ERRORS

从此过程不能返回任何MOUNT协议错误。但是,可能返回认证或其他RPC失败的RPC错误。

5.2.4 过程4: UMNTALL - 删除所有挂载条目

SYNOPSIS

1
void MOUNTPROC3_UMNTALL(void) = 4;

DESCRIPTION

过程UMNTALL删除之前通过调用MNT为客户端记录的所有挂载条目。需要AUTH_UNIX认证或更好的认证。

IMPLEMENTATION

客户端在系统关闭后恢复时应该使用此过程。如果客户端在关闭前无法成功卸载所有其文件系统,或者客户端由于软件或硬件问题而崩溃,那么可能仍有服务器为此客户端保留挂载条目。这是客户端一次通知所有服务器它没有任何挂载文件系统的简单方法。但是,由于此过程通常使用广播RPC实现,因此只有有限的用处。

ERRORS

从此过程不能返回任何MOUNT协议错误。但是,可能返回认证或其他RPC失败的RPC错误。

5.2.5 过程5: EXPORT - 返回导出列表

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
exports MOUNTPROC3_EXPORT(void) = 5;

typedef struct groupnode *groups;

struct groupnode {
     name     gr_name;
     groups   gr_next;
};

typedef struct exportnode *exports;

struct exportnode {
     dirpath  ex_dir;
     groups   ex_groups;
     exports  ex_next;
};

DESCRIPTION

过程EXPORT返回所有导出文件系统的列表以及允许哪些客户端挂载每个文件系统。组列表中的名称是特定于实现的,不能由客户端直接解释。这些名称可以表示主机或主机组。

IMPLEMENTATION

此过程通常返回共享或导出文件系统列表的内容。这些是提供给NFS版本3协议客户端的文件系统。

ERRORS

从此过程不能返回任何MOUNT协议错误。但是,可能返回认证或其他RPC失败的RPC错误。


6. 附录II: 锁管理器协议

由于NFS版本2协议以及NFS版本3协议是无状态的,因此需要额外的网络锁管理器(NLM)协议来支持NFS挂载文件的锁定。与NFS版本2协议一起使用的NLM版本3协议在[X/OpenNFS]中有记录。

NFS版本3协议中的一些更改需要新版本的NLM协议。这个新协议是NLM版本4协议。下表总结了NFS协议版本和NLM协议版本之间的对应关系。

1
2
3
4
5
6
7
8
9
10
       NFS和NLM协议兼容性

               +---------+---------+
               |   NFS   |   NLM   |
               | Version | Version |
               +===================+
               |    2    |   1,3   |
               +---------+---------+
               |    3    |    4    |
               +---------+---------+

本附录仅讨论NLM版本3协议和NLM版本4协议之间的差异。与NFS版本3协议一样,NLM版本4协议中的几乎所有名称都已更改为包含版本号。本附录不讨论仅包含名称更改的更改。

6.1 RPC信息

6.1.1 认证

NLM服务在NULL过程中使用AUTH_NONE。所有其他过程使用AUTH_UNIX、AUTH_SHORT、AUTH_DES和AUTH_KERB。将来可能支持其他认证类型。

6.1.2 常量

这些是调用NLM服务所需的RPC常量。它们以十进制给出。

1
2
PROGRAM    100021
VERSION    4

6.1.3 传输地址

NLM服务通常在TCP和UDP协议上支持。应该查询rpcbind守护进程以获取正确的传输地址。

6.1.4 基本数据类型

1
2
3
4
5
6
7
8
9
10
11
uint64
   typedef unsigned hyper uint64;

int64
   typedef hyper int64;

uint32
   typedef unsigned long uint32;

int32
   typedef long int32;

这些类型对NLM版本4协议是新的。它们与NFS版本3协议中的相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nlm4_stats

   enum nlm4_stats {
      NLM4_GRANTED = 0,
      NLM4_DENIED = 1,
      NLM4_DENIED_NOLOCKS = 2,
      NLM4_BLOCKED = 3,
      NLM4_DENIED_GRACE_PERIOD = 4,
      NLM4_DEADLCK = 5,
      NLM4_ROFS = 6,
      NLM4_STALE_FH = 7,
      NLM4_FBIG = 8,
      NLM4_FAILED = 9
   };

Nlm4_stats指示调用的成功或失败。此版本包含几个新的错误码,以便客户端可以向应用程序提供更精确的失败信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
NLM4_GRANTED
   调用成功完成。

NLM4_DENIED
   调用失败。对于设置锁的尝试,此状态意味着如果客户端稍后重试调用,它可能成功。

NLM4_DENIED_NOLOCKS
   调用失败,因为服务器无法分配必要的资源。

NLM4_BLOCKED
   表示阻塞请求无法立即授予。服务器将在锁被授予时向客户端发出NLMPROC4_GRANTED回调。

NLM4_DENIED_GRACE_PERIOD
   调用失败,因为服务器在重启后重新建立旧锁,尚未准备好恢复正常服务。

NLM4_DEADLCK
   请求无法被授予,阻塞会导致死锁。

NLM4_ROFS
   调用失败,因为远程文件系统是只读的。例如,某些服务器实现可能不支持只读文件系统上的独占锁。

NLM4_STALE_FH
   调用失败,因为它使用了无效的文件句柄。如果文件已被删除或服务器上的文件访问已被撤销,可能发生这种情况。

NLM4_FBIG
   调用失败,因为它指定了超出服务器支持范围的长度或偏移量。

NLM4_FAILED
   调用因未列出的其他原因失败。客户端应将此状态视为不重试请求的强烈提示。
1
2
3
4
5
6
7
8
9
nlm4_holder

   struct nlm4_holder {
        bool     exclusive;
        int32    svid;
        netobj   oh;
        uint64   l_offset;
        uint64   l_len;
   };

此结构指示锁的持有者。exclusive字段指示持有者具有独占锁还是共享锁。svid字段标识持有锁的进程。oh字段是标识持有锁的主机或进程的不透明对象。l_len和l_offset字段标识锁定的区域。NLM版本3协议和NLM版本4协议之间的唯一区别是在NLM版本3协议中,l_len和l_offset字段是32位宽,而在NLM版本4协议中它们是64位宽。

1
2
3
4
5
6
7
8
9
10
nlm4_lock

   struct nlm4_lock {
        string   caller_name<LM_MAXSTRLEN>;
        netobj   fh;
        netobj   oh;
        int32    svid;
        uint64   l_offset;
        uint64   l_len;
   };

此结构描述锁请求。caller_name字段标识发出请求的主机。fh字段标识要锁定的文件。oh字段是标识发出请求的主机或进程的不透明对象,svid字段标识发出请求的进程。l_offset和l_len字段标识锁控制的文件区域。l_len为0表示”到文件末尾”。

此结构的NLM版本3协议和NLM版本4协议版本之间有两个区别。首先,在NLM版本3协议中,长度和偏移量是32位宽,而在NLM版本4协议中它们是64位宽。其次,在NLM版本3协议中,文件句柄是固定长度的NFS版本2协议文件句柄,编码为字节计数后跟字节数组。在NFS版本3协议中,文件句柄已经是可变长度的,所以它直接复制到fh字段中。也就是说,fh字段的前四个字节与NFS版本3协议nfs_fh3中的字节计数相同。fh字段的其余部分包含来自NFS版本3协议nfs_fh3的字节数组。

1
2
3
4
5
6
7
8
9
nlm4_share

   struct nlm4_share {
        string      caller_name<LM_MAXSTRLEN>;
        netobj      fh;
        netobj      oh;
        fsh4_mode   mode;
        fsh4_access access;
   };

此结构用于支持DOS文件共享。caller_name字段标识发出请求的主机。fh字段标识要操作的文件。oh字段是标识发出请求的主机或进程的不透明对象。mode和access字段指定文件共享和访问模式。fh的编码是字节计数,后跟文件句柄字节数组。有关更多详细信息,请参阅nlm4_lock的描述。

6.2 NLM过程

NLM版本4协议中的过程在语义上与NLM版本3协议中的过程相同。唯一的语义差异是添加了一个可以用来测试服务器响应性的NULL过程。带有_MSG和_RES后缀的过程名称表示异步消息;对于这些,void响应意味着不回复。句法更改是过程被重命名以避免与nlm4_stats的值发生名称冲突。因此过程定义如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
version NLM4_VERS {
   void
      NLMPROC4_NULL(void)                  = 0;

   nlm4_testres
      NLMPROC4_TEST(nlm4_testargs)         = 1;

   nlm4_res
      NLMPROC4_LOCK(nlm4_lockargs)         = 2;

   nlm4_res
      NLMPROC4_CANCEL(nlm4_cancargs)       = 3;

   nlm4_res
      NLMPROC4_UNLOCK(nlm4_unlockargs)     = 4;

   nlm4_res
      NLMPROC4_GRANTED(nlm4_testargs)      = 5;

   void
      NLMPROC4_TEST_MSG(nlm4_testargs)     = 6;

   void
      NLMPROC4_LOCK_MSG(nlm4_lockargs)     = 7;

   void
      NLMPROC4_CANCEL_MSG(nlm4_cancargs)   = 8;

   void
      NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9;

   void
      NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10;

   void
      NLMPROC4_TEST_RES(nlm4_testres)     = 11;

   void
      NLMPROC4_LOCK_RES(nlm4_res)         = 12;

   void
      NLMPROC4_CANCEL_RES(nlm4_res)       = 13;

   void
      NLMPROC4_UNLOCK_RES(nlm4_res)       = 14;

   void
      NLMPROC4_GRANTED_RES(nlm4_res)      = 15;

   nlm4_shareres
      NLMPROC4_SHARE(nlm4_shareargs)      = 20;

   nlm4_shareres
      NLMPROC4_UNSHARE(nlm4_shareargs)    = 21;

   nlm4_res
      NLMPROC4_NM_LOCK(nlm4_lockargs)     = 22;

   void
      NLMPROC4_FREE_ALL(nlm4_notify)      = 23;

} = 4;

6.2.0 过程0: NULL - 不做任何操作

SYNOPSIS

1
void NLMPROC4_NULL(void) = 0;

DESCRIPTION

NULL过程不做任何工作。它在所有RPC服务中都可用,以允许服务器响应测试和计时。

IMPLEMENTATION

重要的是此过程根本不做任何工作,以便它可以用于测量处理服务请求的开销。按照惯例,NULL过程永远不需要任何认证。

ERRORS

某些服务器实现可能基于安全和认证要求返回RPC错误。

6.3 实现问题

6.3.1 64位偏移量和长度

一些NFS版本3协议服务器只能支持文件偏移量或长度适合32位或更少位的请求。对于这些服务器,锁管理器将具有相同的限制。如果这样的锁管理器收到它无法处理的请求(因为偏移量或长度使用超过32位),它应该返回错误NLM4_FBIG。

6.3.2 文件句柄

从NFS版本2协议到NFS版本3协议的文件句柄格式更改使锁管理器复杂化。首先,锁管理器需要某种方法来判断NFS版本2协议文件句柄是否与NFS版本3协议文件句柄引用同一文件。(这是假设锁管理器支持NLM版本3协议客户端和NLM版本4协议客户端。)其次,如果锁管理器通过哈希函数运行文件句柄,哈希函数可能需要重新调整以适用于NFS版本3协议文件句柄以及NFS版本2协议文件句柄。


7. 附录III: 参考文献

[Corbin] Corbin, John, “The Art of Distributed Programming-Programming Techniques for Remote Procedure Calls.” Springer-Verlag, New York, New York. 1991. RPC和XDR的基本描述以及如何使用它们编程分布式应用程序。

[Glover] Glover, Fred, “TNFS Protocol Specification,” Trusted System Interest Group, Work in Progress.

[Israel] Israel, Robert K., Sandra Jett, James Pownell, George M. Ericson, “Eliminating Data Copies in UNIX-based NFS Servers,” Uniforum Conference Proceedings, San Francisco, CA, February 27 - March 2, 1989. 描述了减少NFS服务器代码中数据副本的两种方法。

[Jacobson] Jacobson, V., “Congestion Control and Avoidance,” Proc. ACM SIGCOMM `88, Stanford, CA, August 1988. 描述了TCP的改进以允许在广域网使用和通过连接不同容量网络的网关。这项工作是NFS动态重传工作的起点。

[Juszczak] Juszczak, Chet, “Improving the Performance and Correctness of an NFS Server,” USENIX Conference Proceedings, USENIX Association, Berkeley, CA, June 1990, pages 53-63. 描述了回复缓存实现,通过处理重复请求来避免服务器上的工作。更重要的是,虽然列为副作用,回复缓存有助于避免破坏性非幂等操作重新应用 - 提高正确性。

[Kazar] Kazar, Michael Leon, “Synchronization and Caching Issues in the Andrew File System,” USENIX Conference Proceedings, USENIX Association, Berkeley, CA, Dallas Winter 1988, pages 27-36. AFS中缓存一致性方案的描述。与其他分布式文件系统对比。

[Macklem] Macklem, Rick, “Lessons Learned Tuning the 4.3BSD Reno Implementation of the NFS Protocol,” Winter USENIX Conference Proceedings, USENIX Association, Berkeley, CA, January 1991. 描述了调整4.3BSD Reno NFS实现的性能工作。描述了通过消除数据副本实现的性能改进(减少CPU加载)。

[Mogul] Mogul, Jeffrey C., “A Recovery Protocol for Spritely NFS,” USENIX File System Workshop Proceedings, Ann Arbor, MI, USENIX Association, Berkeley, CA, May 1992. Spritely NFS的第二篇论文提出了恢复一致性协议状态的基于租约的方案。

[Nowicki] Nowicki, Bill, “Transport Issues in the Network File System,” ACM SIGCOMM newsletter Computer Communication Review, April 1989. 动态重传工作基础的简要描述。

[Pawlowski] Pawlowski, Brian, Ron Hixon, Mark Stein, Joseph Tumminaro, “Network Computing in the UNIX and IBM Mainframe Environment,” Uniforum `89 Conf. Proc., (1989) IBM的MVS操作系统的NFS服务器实现描述。

[RFC1014] Sun Microsystems, Inc., “XDR: External Data Representation Standard”, RFC 1014, Sun Microsystems, Inc., June 1987. 数据交换的标准格式规范,用于RPC。

[RFC1057] Sun Microsystems, Inc., “RPC: Remote Procedure Call Protocol Specification”, RFC 1057, Sun Microsystems, Inc., June 1988. 远程过程协议规范。

[RFC1094] Sun Microsystems, Inc., “Network Filesystem Specification”, RFC 1094, Sun Microsystems, Inc., March 1989. NFS版本2协议规范。

[Sandberg] Sandberg, R., D. Goldberg, S. Kleiman, D. Walsh, B. Lyon, “Design and Implementation of the Sun Network Filesystem,” USENIX Conference Proceedings, USENIX Association, Berkeley, CA, Summer 1985. 描述SunOS NFS版本2协议实现的基本论文,并讨论目标、协议规范和权衡。

[Srinivasan] Srinivasan, V., Jeffrey C. Mogul, “Spritely NFS: Implementation and Performance of Cache Consistency Protocols”, WRL Research Report 89/5, Digital Equipment Corporation Western Research Laboratory, 100 Hamilton Ave., Palo Alto, CA, 94301, May 1989. 分析了将Sprite类一致性协议应用于标准NFS的效果。有状态环境中的恢复问题在[Mogul]中涵盖。

[X/OpenNFS] X/Open Company, Ltd., X/Open CAE Specification: Protocols for X/Open Internetworking: XNFS, X/Open Company, Ltd., Apex Plaza, Forbury Road, Reading Berkshire, RG1 1AX, United Kingdom, 1991. NFS版本2协议和附带协议的不可或缺参考,包括锁管理器和端口映射器。

[X/OpenPCNFS] X/Open Company, Ltd., X/Open CAE Specification: Protocols for X/Open Internetworking: (PC)NFS, Developer’s Specification, X/Open Company, Ltd., Apex Plaza, Forbury Road, Reading Berkshire, RG1 1AX, United Kingdom, 1991. NFS版本2协议和附带协议的不可或缺参考,包括锁管理器和端口映射器。


8. 安全考虑

由于敏感文件数据可能通过NFS协议从服务器传输或接收,因此协议的实现应该解决认证、隐私和数据完整性问题。

与之前的协议修订(版本2)一样,NFS版本3遵循支持RPC协议[RFC1057]的认证规定,并假设数据隐私性和完整性由实现中可用的底层传输层提供。有关文件访问权限的讨论,请参见第4.4节。


9. 致谢

本协议描述源自Brian Pawlowski编写的原始文档,由Peter Staubach修订。此协议是合作努力的结果,包括Geoff Arnold、Brent Callaghan、John Corbin、Fred Glover、Chet Juszczak、Mike Eisler、John Gillono、Dave Hitz、Mike Kupfer、Rick Macklem、Ron Minnich、Brian Pawlowski、David Robinson、Rusty Sandberg、Craig Schamp、Spencer Shepler、Carl Smith、Mark Stein、Peter Staubach、Tom Talpey、Rob Thurlow和Mark Wittle的贡献。


10. 作者地址

将与此协议相关的评论发送到:

1
nfs3@eng.sun.com

Brent Callaghan Sun Microsystems, Inc. 2550 Garcia Avenue Mailstop UMTV05-44 Mountain View, CA 94043-1100

电话: 1-415-336-1051 传真: 1-415-336-6015 电子邮件: brent.callaghan@eng.sun.com

Brian Pawlowski Network Appliance Corp. 319 North Bernardo Ave. Mountain View, CA 94043

电话: 1-415-428-5136 传真: 1-415-428-5151 电子邮件: beepy@netapp.com

Peter Staubach Sun Microsystems, Inc. 2550 Garcia Avenue Mailstop UMTV05-44 Mountain View, CA 94043-1100

电话: 1-415-336-5615 传真: 1-415-336-6015 电子邮件: peter.staubach@eng.sun.com

This post is licensed under CC BY 4.0 by the author.