第十一章 网络文件系统
NFS,网络文件系统(network filesystem),或许是使用RPC最突出的网络服务了。它允许
你以访问任何本地文件一样的方法来访问远程主机上的文件。这是通过将客户端的内核功能
(它使用远程文件系统)与服务器端的NFS服务器功能(它提供文件数据)相混合而成为可能
的。这种文件访问对客户来说是完全透明的,并且可在各种服务器和各种主机结构上工作。
NFS提供的许多优点:
? 被所有用户访问的数据可以存放在一台中央主机上,由客户在引导启动时加载这个目录。
例如,你可以将所有用户的帐目存放在一台主机上,让你的网络上的所有用户从那台主机上
加载/home目录。如果也安装了NIS的话,用户就可以登录进任何系统上,而始终在一组文件
上工作。
? 需要耗费大量磁盘空间的数据可以被保存在一台主机上。例如,所有有关LaTeX和METAFON
T的文件和程序可以在一个地方保存和维护。
? 管理用的数据可以存放在单个主机上。不再需要使用rcp将相同的文件安装到20个不同的机
器上。
NFS在很大程度上是由Rick Sladkey做出的,[1] 他编制了NFS的内核代码和NFS服务器的大部
分。后者源自于由Mark Shand编制的unfsd user-space NFS服务器和Donald Becker编制的h
nfs Harris NFS服务器。
现在让我们观看一下NFS是如何工作的:一个客户可以请求将一台远程主机的目录加载到一个
本地目录上,正如用加载一个物理设备同样的方法。然而,用于指定远程目录的句法是不同
的。例如,为了主机vlager的/home加载到vale的/users上,管理员在vale上要发出以下的命
令:[2]
# mount ?t nfs vlager:/home /users
此时,mount将试图通过RPC联系vlager上的mountd mount后台程序。服务器将检查vale是否
允许加载所考虑的目录,如果行的话,就返回一个文件句柄(file handle)。这个文件句柄
将被用于所有随后对/users下的文件的请求。
当某人通过NFS访问一个文件时,内核就将一个RPC调用送至服务器机器上的nfsd(NFS后台程
序)。该调用将文件句柄、要访问的文件名以及用户的user和group id作为参数。这些用于
确定对指定文件的访问权限。为了避免非授权用户读取或修改文件,user和group id在两台
主机上必须相同。
在许多UN*X实现中,NFS的客户和服务器功能是作为内核层的后台程序实现的,是在系统引导
时从用户空间启动的。NFS后台程序(nfsd)在服务器主机上,Block I/O后台程序(biod)
在客户主机上。为了提高吞吐率,biod使用预读(read-ahead)和后写(迟写)(write-be
hind)来执行同步I/O;同样,几个nfsd后台程序通常是并发运行的。
NFS的Linux实现稍微有些不同,客户代码被紧密地集成到内核的虚拟文件系统中(VFS)并且
不需要通过biod进行另外的控制。另一方面,服务器代码完全在用户空间运行,所以同时运
行该服务器的几个拷贝几乎是不可能的―因为这将涉及到同步问题。目前Linux的NFS还缺乏
预读和后写机制,但Rick Sladkey计划今后将添加进去。[3]
Linux的NFS代码的最大问题是Linux的1.0版内核不能分配大于4K的内存块;其结果是,网络
代码不能处理除去头大小等数据后大于3500左右字节的数据报。这意味着对于使用默认的大
的UDP数据报的系统(例如,在SunOS上是8K),从其上运行的NFS后台程序上传回的数据,需
要人工地切成小块。在某些环境下这会严重地损害系统性能。[4] 这个限制在最近的Linux-
1.1内核中已不复存在,并且客户代码也已进行了修改以克服这个问题。
11.1 准备NFS
在你能够使用NFS之前,不管是作为服务器还是客户,你必须确信你的内核已将NFS支持编译
进去了。对此,较新的内核在proc文件系统上有一个简单的接口,即/proc/filesystems文件
,你可以使用cat来显示它:
$ cat /proc/filesystems
minix
ext2
msdos
nodev proc
nodev nfs
如果这个列表中没有nfs,那么你必须编译你自己的启用了NFS的内核。配置内核网络选项在
第三章的“内核配置”一节中作过解释。
对于Linux 1.1以前的内核,要找出你的内核是否启用了NFS支持的最容易的方法是实际地试
着加载一个NFS文件系统。对于此,你可以在/tmp下建立一个目录,并试着往上加载一个本地
目录:
# mkdir /tmp/test
# mount localhost:/etc/ tmp/test
如果这个加载尝试失败了,并有一段出错信息指出“fs type nfs no supported by kernel
”,那么你就必须制作一个启用了NFS的新内核。任何其它的出错信息都完全无关紧要,因为
你还没有在你的主机上配置NFS后台程序。
11.2 加载一个NFS卷
NFS卷[5]的加载方法与普通文件系统的加载方式是一样的。你使用下面的句法调用mount:
# mount ?t nfs nfs_volume local_dir options
nfs_volume是以remote_host:remote_dir形式给出。由于这个表示法对NFS文件系统来说是唯
一的,你可以省略-t nfs选项。
在加载一个NFS卷时,你可以指定许多别的选项。这些选项可以在命令行上在-o开关后面给出
,或者在/etc/fstab该卷条目的选项字段内给出。在这两种情况下,多个选项是用逗号彼此
分开的。在命令行上的选项总是覆盖fstab文件中给出的选项。
在/etc/fstab中的一个样本条目可以是
# volume mount point type options
news:/usr/spool/news /usr/spool/news nfs timeo=14,intr
然后,这个卷可以使用下面命令被加载
# mount news:/usr/spool/news
如果fstab中没有相应的条目,那么NFS的mount调用看上去就有点乱。例如,假如你从一台称
为moonshot的机器上加载你的用户主目录,moonshot机器使用一个默认的4K大小的块来进行
读/写操作。你可以发出如下命令将块的大小减至2K以适应Linux的数据报大小的限制
# mount moonshot:/home /home -o rsize=2048,wsize=2048
在随Rick Sladkey的基于NFS的mount工具(可以在Rik Faith的util-linux软件包中找到)而
来的nfs(5)手册页中对所有有效选项的列表进行了完整的描述。下面是你可能要用到的这些
选项的一个不完整的列表:
rsize=n and wsize=n
这分别指出了用于NFS客户读写请求的数据报的大小。由于上述的UDP数据报大小的限制,它
们目前的缺省值是1024字节。
timeo=n 这用于设置NFS客户将等待一个请求完成的等待时间(以十分之一秒计)。缺省值是
0.7秒。
hard 明确地标记出这个卷是硬加载的(hard-mounted)。缺省值是on。
soft 软加载(Soft-mount)驱动程序(与硬加载相反)。
intr 允许通知中断一个NFS调用。对于服务器没有响应时的异常中止很有用。
除了rsize和wsize以外,所有这些选项应用于当服务器临时变得不可访问时客户的相应动作
。它们一起以如下的方式行事:每当一个客户想NFS服务器发送了一个请求,它就期望操作在
一给定的时间间隔内(由timeout选项指定)完成。如果在该时间内没有收到确认,就会发生
一个所谓的次超时(minor timeout),操作被重试并且超时间隔时间翻倍。在到达60秒钟的
最大超时时间时,就发生一个主超时(major timeout)。
缺省地,一个主超时将导致客户程序在控制台上打印出一条消息并且再次重新开始,这一次
,时间值再次翻倍。潜在地,这将会一直继续下去。顽固地重复一个操作直到服务器再次可
用时的卷称为硬加载(hard-mounted)。相反地,每当一个主超时发生时,软加载(soft-m
ounted)的卷就为调用进程生成一个I/O出错信息。由于缓冲引入了后写,所以在进程下一次
调用write(2)函数之前,这个出错情形并没有传播到进程本身,因此一个程序就完全不能确
知对一个软加载卷的写操作是否已经完成了。
硬加载还是软加载一个卷不仅只是一个感觉(习惯)问题,而且也是与从该卷上你要访问什
么信息有关。例如,如果你通过NFS加载你的X程序,你当然不希望你的X会话仅仅因为有人同
时开启7个xv致使网络几乎中断而抓狂,或者由于片刻插拔下以太网插头而使得X会话瞬时停
止。通过硬加载这个卷,你可以确信你的计算机将会等待,直到能够重新与你的NFS服务器建
立连接。另一方面,非关键数据比如NFS加载的news分区或FTP文档程序也可以软加载,那么
在远程机器暂时连接不上或关闭时就不会挂起你的会话过程。如果到服务器的网络连接很脆
弱或者要经过一个重负荷的路由器的话,那么你或者使用timeo选项增大初始的超时值,或者
硬加载这个卷,但是要允许信号中断NFS调用,这样你仍然可以终止任何挂起的文件访问。
通常,mountd后台程序以某种方法保持哪个目录已被什么主机加载的轨迹。这个信息能够使
用showmount程序显示出来,该程序也包括在NFS服务器软件包中。然而现在Linux mountd还
不能做到这件事。
11.3 NFS后台程序(Daemons)
如果你想为其它主机提供NFS服务,那么必须在你的机器上运行nfsd和mountd后台程序。作为
基于RPC的程序,它们不是由inetd管理的,而是在引导期间启动的,并且用portmapper注册
自身的。因此你必须确信只在rpc.portmap运行之后才开始运行它们。通常,在你的rc.inet
2脚本中要包括下面两行:
if [ -x /usr/sbin/rpc.mountd ]; the