第29章 网络文件系统
29.5 NFS协议
使用N F S,客户可以透明地访问服务器上的文件和文件系统。这不同于提供文件传输的F T P(第2 7章)。F T P会产生文件一个完整的副本。 N F S只访问一个进程引用文件的那一部分,并且N F S的一个目的就是使得这种访问透明。这就意味着任何能够访问一个本地文件的客户程序不需要做任何修改,就应该能够访问一个 N F S文件。
N F S是一个使用Sun RPC构造的客户服务器应用程序。 N F S客户通过向一个N F S服务器发送R P C请求来访问其上的文件。尽管这一工作可以使用一般的用户进程来实现—即N F S客户可以是一个用户进程,对服务器进行显式调用。而服务器也可以是一个用户进程—因为两个理由,N F S一般不这样实现。首先,访问一个 N F S文件必须对客户透明。因此, N F S的客户调用是由客户操作系统代表用户进程来完成的。第二,出于效率的考虑, N F S服务器在服务器操作系统中实现。如果 N F S服务器是一个用户进程,每个客户请求和服务器应答(包括读和写的数据)将不得不在内核和用户进程之间进行切换,这个代价太大。
本节中,我们考察在R F C 1 0 9 4中说明的第2版的NFS [Sun Microsystems 1988b]。[ X / O p e n 1991] 中给出了Sun RPC、X D R和N F S的一个更好的描述。 [Stern 1991] 给出了使用和管理N F S的细节。第3版的N F S协议在1 9 9 3年发布,我们在2 9 . 7节中对它做一个简单的描述。
图2 9 - 3显示了一个N F S客户和一个N F S服务器的典型配置,图中有很多地方需要注意。
- 访问的是一个本地文件还是一个 N F S文件对于客户来说是透明的。当文件被打开时,由内核决定这一点。文件被打开之后,内核将本地文件的所有引用传递给名为“本地文件访问”的框中,而将一个N F S文件的所有引用传递给名为“ N F S客户”的框中。
- NFS客户通过它的T C P / I P模块向N F S服务器发送R P C请求。N F S主要使用U D P,最新的实现也可以使用T C P。
- NFS服务器在端口2 0 4 9接收作为U D P数据报的客户请求。尽管 N F S可以被实现成使用端口映射器,允许服务器使用一个临时端口,但是大多数的实现都是直接指定 U D P端口2 0 4 9。
- 当N F S服务器收到一个客户请求时,它将这个请求传递给本地文件访问例程,后者访问服务器主机上的一个本地的磁盘文件。
- NFS服务器需要花一定的时间来处理一个客户的请求。访问本地文件系统一般也需要一部分时间。在这段时间间隔内,服务器不应该阻止其他的客户请求得到服务。为了实现这一功能,大多数的N F S服务器都是多线程的—即服务器的内核中实际上有多个 N F S服务器在运行。具体怎么实现依赖于不同的操作系统。既然大多数的 U n i x内核不是多线程的,一个共同的技术就是启动一个用户进程(常被称为 n f s d)的多个实例。这个实例执行一个系统调用,使自己作为一个内核进程保留在操作系统的内核中。.
- 同样,在客户主机上, N F S客户需要花一定的时间来处理一个用户进程的请求。 N F S客户向服务器主机发出一个 R P C调用,然后等待服务器的应答。为了给使用 N F S的客户主机上的用户进程提供更多的并发性,在客户内核中一般运行着多个 N F S客户。同样,具体实现也依赖于操作系统。U n i x系统经常使用类似于N F S服务器的技术:一个叫作b i o d的用户进程执行一个系统调用,作为一个内核进程保留在操作系统的内核中。
大多数的U n i x主机可以作为一个N F S客户,一个N F S服务器,或者两者都是。大多数P C机的实现(M S - D O S)只提供了N F S客户实现。大多数的I B M大型机只提供了N F S服务器功能。N F S实际上不仅仅由N F S协议组成。图2 9 - 4显示了N F S使用的不同R P C程序。
在这个图中,程序的版本是在SunOS 4.1.3中使用的。更新的实现提供了其中一些程序更新的版本。例如,Solaris 2.2还支持端口映射器的第3版和第4版,以及安装守护程序的第2版。SVR4支持第3版的端口映射器。
在客户能够访问服务器上的文件系统之前, N F S客户主机必须调用安装守护程序。我们在下面讨论安装守护程序。
加锁管理程序和状态监视器允许客户锁定一个 N F S服务器上文件的部分区域。这两个程序独立于N F S协议,因为加锁需要知道客户和服务器的状态,而 N F S本身在服务器上是无状态的(下面我们对N F S的无状态会介绍得更多)。[X/Open 1991] 的第9, 10和11章说明了使用加锁管理程序和状态监视器进行 N F S文件锁定的过程。
29.5.1 文件句柄
N F S中一个基本概念是文件句柄 (file handle)。它是一个不透明( o p a q u e )的对象,用来引用服务器上的一个文件或目录。不透明指的是服务器创建文件句柄,把它传递给客户,然后客户访问文件时,使用对应的文件句柄。客户不会查看文件句柄的内容—它的内容只对服务器有意义。
每次一个客户进程打开一个实际上位于一个 N F S服务器上的文件时,N F S客户就会从N F S服务器那里获得该文件的一个文件句柄。每次 N F S客户为用户进程读或写文件时,文件句柄就会传给服务器以指定被访问的文件。
一般情况下,用户进程不会和文件句柄打交道—只有N F S客户和N F S服务器将文件句柄传来传去。在第2版的N F S中,一个文件句柄占据3 2个字节,第3版中增加为6 4个字节。U n i x服务器一般在文件句柄中存储下面的信息:文件系统标识符(文件系统最大和最小的设备号),i - n o d e号(在一个文件系统中唯一的数值)和一个 i - n o d e的生成码(每当一个i-node被一个不同的文件重用时就改变的数值)。
29.5.2 安装协议
客户必须在访问服务器上一个文件系统中的文件之前,使用安装协议安装那个文件系统。一般情况下,这是在客户主机引导时完成的。最后的结果就是客户获得服务器文件系统的一个文件句柄。 图2 9 - 5显示了一个U n i x客户发出m o u n t( 8 )命令所发生的情况,它说明一个N F S的安装过程。
依次发生了下面的动作。
- 服务器上的端口映射器一般在服务器主机引导时被启动。
- 安装守护程序( m o u n t d)在端口映射器之后被启动。它创建了一个 T C P端点和一个U D P端点,并分别赋予一个临时的端口号。然后它在端口映射器中注册这些端口号。
- 在客户机上执行 m o u n t命令,它向服务器上的端口映射器发出一个 R P C调用来获得服务器上安装守护程序的端口号。客户和端口映射器交互既可以使用 T C P也可以使用U D P,但一般使用U D P。
- 端口映射器应答以安装守护程序的端口号。
- m o u n t命令向安装守护程序发出一个R P C调用来安装服务器上的一个文件系统。同样,既可以使用 T C P也可以使用 U D P,但一般使用U D P。服务器现在可以验证客户,使用客户的 I P地址和端口号来判别是否允许客户安装指定的文件系统。
- 安装守护程序应答以指定文件系统的文件句柄。
- 客户机上的m o u n t命令发出m o u n t系统调用将第5步返回的文件句柄与客户机上的一个本地安装点联系起来。文件句柄被存储在 N F S客户代码中,从现在开始,用户进程对于那个服务器文件系统的任何引用都将从使用这个文件句柄开始。
上述实现技术将所有的安装处理,除了客户机上的 m o u n t系统调用,都放在用户进程中,而不是放在内核中。我们显示的三个程序—m o u n t命令、端口映射器和安装守护程序—都是用户进程。 作为一个例子,在我们的主机 s u n(一个N F S客户机)上执行:
代码语言:javascript复制sun # mount -t nfs bsdi:/usr /nfs/bsdi/usr
这个命令将主机 b s d i(一个N F S服务器)上的 / u s r目录安装成为本地文件系统 / n f s / b s d i /u s r。图2 9 - 6显示了结果。
当我们引用客户机s u n上的/nfs/bsdi/usr/rstevens/hello.c 文件时,实际上引用的是服务器b s d i上的文件/ u s r / r s t e v e n s / h e l l o . c。
29.5.3 NFS过程
现在我们描述N F S服务器提供的1 5个过程(使用的个数与N F S过程的实际个数不一样,因为我们把它们按照功能分了组)。尽管N F S被设计成可以在不同的操作系统上工作,而不仅仅是U n i x系统,但是一些提供 U n i x功能的过程可能不被其他操作系统支持(例如硬链接、符号链接、组的属主和执行权等)。[Stevens 1992]的第4章包含了U n i x文件系统其他的一些信息,其中有些被N F S采用。
- GETAT T R。返回一个文件的属性:文件类型(一般文件,目录等)、访问权限、文件大小、文件的属主者及上次访问时间等信息。
- SETAT T R。设置一个文件的属性。只允许设置文件属性的一个子集:访问权限、文件的属主、组的属主、文件大小、上次访问时间和上次修改时间。
- STAT F S。返回一个文件系统的状态:可用空间的大小、最佳传送大小等。例如 U n i x的d f命令使用此过程。
- LOOKUP。查找一个文件。每当一个用户进程打开一个 N F S服务器上的一个文件时,N F S客户调用此过程。
- READ。从一个文件中读数据。客户说明文件的句柄、读操作的开始位置和读数据的最大字节数(最多8 1 9 2个字节)。
- WRITE。对一个文件进行写操作。客户说明文件的句柄、开始位置、写数据的字节数和要写的数据。
- CREAT E。创建一个文件。
- REMOVE。删除一个文件。
- RENAME。重命名一个文件。
- LINK。为一个文件构造一个硬链接。硬链接是一个 U n i x的概念,指的是磁盘中的一个文件可以有任意多个目录项(即名字,也叫作硬链接)指向它。
- SYMLINK。为一个文件创建一个符号链接。符号链接是一个包含另一个文件名字的文件。大多数引用符号链接的操作(例如,打开)实际上引用的是符号链接所指的文件。
- READLINK。读一个符号链接。即返回符号链接所指的文件的名字。
- MKDIR。创建一个目录。
- RMDIR。删除一个目录。
- READDIR。读一个目录。例如,U n i x的l s命令使用此过程。这些过程实际上有一个前缀 N F S P R O C _,我们把它省略了。
29.5.4 UDP还是TCP
N F S最初是用 U D P写的,所有的厂商都提供了这种实现。最新的一些实现也支持 T C P。T C P支持主要用于广域网,它可以使文件操作更快。 N F S已经不再局限于局域网的使用。当从L A N转换到WA N时,网络的动态特征变化得非常大。往返时间( round-trip time)变动范围大,拥塞经常发生。 WA N的这些特征使得我们考虑使用具有 T C P属性的算法—慢启动,但是可以避免拥塞。既然 U D P没有提供任何类似的东西,那么在 N F S客户和服务器上加进同样的算法或者使用T C P。
29.5.5 TCP上的NFS
伯克利实现的Net/2 NFS支持U D P或者T C P。[Macklem 1991]描述了这个实现。让我们看一下使用T C P有什么不同。
- 当服务器主机进行引导时,它启动一个 N F S服务器,后者被动打开 T C P端口2 0 4 9,等待着客户的连接请求。这通常是另一个 N F S服务器,正常的NFS UDP服务器在U D P端口2 0 4 9等待着进入的U D P数据报。
- 当客户使用T C P安装服务器上的文件系统时,它对服务器上的 T C P端口2 0 4 9做一个主动打开。这样就为这个文件系统在客户和服务器之间形成了一个 T C P连接。如果同样的客户安装同样服务器上的另一个文件系统,就会创建另一个 T C P连接。
- 客户和服务器在它们连接的两端都要设置 T C P的k e e p a l i v e选项,这样双方都能检测到对方主机崩溃,或者崩溃然后重启动。
- 客户方所有使用这个服务器文件系统的应用程序共享这个 T C P连接。例如,在图 2 9 - 6中,如果在 b s d i的/ u s r目录下还有另一个目录 s m i t h,那么对两个目录
/ n f s / b s d i / u s r / r s t e v e n s
和/ n f s / b s d i / u s r / s m i t h
下所有文件的引用将共享同样的 T C P连接。 - 如果客户检测到服务器已经崩溃,或者崩溃然后重启动(通过收到一个 T C P差错“连接超时”或者“对方复位连接”),它尝试与服务器重新建立连接。客户做另一个主动打开,为同一个文件系统请求重新建立 T C P连接。在以前连接上超时的所有客户请求在新的连接上都会重新发出。
- 如果客户机崩溃,那么当它崩溃时正在运行的应用程序也要崩溃。当客户机重新启动时,它很可能使用 T C P重新安装服务器的文件系统,这将导致和服务器的另一个连接。客户和服务器之间针对同一个文件系统的前一个连接现在打开了一半(服务器方认为它还开着),但是既然服务器设置了 k e e p a l i v e选项,当服务器发出下一个 k e e p a l i v e探查报文时,这个半开 着的T C P连接就会被中止。
随着时间的流逝,另外一些厂商也计划支持 T C P上的N F S。