1、NFS配置Linux网络文件系统(NFS)分析浙江大学计算机系 98硕宋鹏 王靖滨 余可曼1. 网络文件系统概述 411 远程文件存取 412 网络文件系统概述 413 网络文件系统上层实现 5131 Mount安装协议和NFS远程过程 5132 访问文件的具体流程 514 网络文件系统下层实现远程过程调用(RPC) 6141 RPC的概念模型 7142 SUN RPC的定义 7143 SUN RPC的传输层实现机制 81431 通信语义 81432 动态端口映射 9144 一次RPC远程调用的具体流程 92. Linux的NFS系统框架 1121 源码分析环境 1122 Linux下NFS的
2、体系结构 1223 NFS的Client端 12231 Client端的VFS层 13232 Client端的RPC层 20233 Client端的NFS层 272331 NFS过程层 2724 NFS的Server端 33241 Server端的RPC层 33242 Server端的NFS层 37243 NFS Server端启动 39244 nfsservctl系统调用实现 40245 RPC鉴别机制 463 Mount安装协议的具体实现 4831 NFS Client端Mount协议数据结构 4832 NFS Client端Mount协议实现 50321Linux根文件系统的NFS Mo
3、unt协议安装 513211 nfs_root_setup函数的实现 523212 nfs_root_mount函数的功能 54322命令行下的动态NFS Mount协议安装 603221 nfs_read_super函数的实现 604NFS文件操作具体流程 6441 NFS文件协议的数据结构 6442 打开一个NFS文件的具体流程 65421 VFS层操作分析 65422 NFS层操作分析 67423 RPC层操作分析 69424 Server端操作分析 6943 读写一个NFS文件的具体流程 70431 sys_read函数 71432nfs_file_read函数 72433nfs_re
4、adpagenfs_readpage_sync函数 725 NFS文件系统FAQ 76参考文献: 791. 网络文件系统概述11 远程文件存取许多早期的网络系统提供了文件传输(File transfer)服务,它允许用户把某文件的一个副本从一台机器移到另一台机器上。而更多近期的网络则提供了文件存取(File access)服务,即允许某个应用程序从一台远程机器上对某个文件进行存取。使用远程文件机制对文件进行存取的应用程序,可以同它所要存取的文件驻留在同一台机器上,也可以运行在某台远程机器上。当一个应用程序要存取一个驻留在某台远程机器上的文件时,该程序的操作系统将调用客户机软件,这个客户机软件与
5、远程机器中的服务器联系,执行对该文件执行所请求的操作。与文件传输服务不同,该服务的系统并不立即对整个文件进行传输和存储,而是每次要求传送一小块数据。为了提供对驻留在某台计算机上的某些或所有文件的远程存取能力,系统管理员必须让该计算机运行一个可以对存取请求进行响应的服务器。这个服务器对每个请求进行检查,以验证该客户是否具有对指定文件进行存取的权利,然后执行所指明的操作,最后向客户机返回一个结果。12 网络文件系统概述Sun Microsystems公司于1984年推出了一个在整个计算机工业中被广泛接受的远程文件存取机制,它被称为Sun的网络文件系统(Network File System),或者
6、简称为NFS。该机制允许在一台计算机上运行一个服务器,使对其上的某些或所有文件都可以进行远程存取,还允许其他计算机上的应用程序对这些文件进行存取。它使我们能够达到文件的共享。当使用者想用远端档案时只要用mount就可把remote档案系统挂接在自己的档案系统之下,使得远端的文件操作上和本地机器的文件没两样。一个应用程序可以打开(Open)一个远程文件以进行存取,可以从这个文件中读取(Read)数据,向该文件中写入(Write)数据,定位(Seek)到文件中的某个指定位置(开始、结尾或者其他地方),最后当使用完毕后关闭(Close)该文件。并且这些操作都是对编程者透明的,操作方法和对本地文件的操
7、作方法完全一样。下面的两节我们将继续介绍Sun的网络文件系统的具体实现,这对于了解下一章Linux中NFS的实现提供了很好的理论背景。13 网络文件系统上层实现131 Mount安装协议和NFS远程过程NFS的实现被分离成两个独立的程序来实现,分别是Mount安装协议和NFS远程过程调用。Mount安装协议是实现文件访问的开端。它的主要功能是获取远程机器上的不同文件系统结构并返回所要访问的文件系统根句柄,作为以后对该文件系统进行操作的根本。在下一节中我们将介绍PRC(远程过程调用)的基础知识,而关于PRC如何实现NFS的上述两部分功能,我们将在下一章中,结合具体的Linux函数进行分析。相信这
8、样,更能加深这部分知识的理解。132 访问文件的具体流程上面我们看到了NFS文件系统的主要数据结构,以及实现文件系统的两部分重要构成。下面总结一下NFS中怎样实现对一个目标文件的访问。在NFS中,每次对远程文件系统上的通过一个称之为”文件句柄”(file-handle)的数据结构来实现对远程机器上目标文件的操纵。首先对文件名在本地进行解析。这一过程与传统UNIX中的文件名解析过程类似。即一次解析一个全路径名的一部分。它从分层结构的根及路径的开始出发,重复地从路径中取出下一部分,并找出一个具有该名字的文件或子目录。在NFS系统中,得到一个目的文件句柄不是一步完成的,而是分多个步骤实现的。首先是由
9、Mount安装协议取得该NFS服务器上的分层文件结构信息,并取得相应文件系统的根句柄。在得到一个远程文件系统的根句柄后,结合本地对文件名字解析的结果,可以调用NFS的远程过程,在当前远程文件系统根句柄下取出各个子目录的文件句柄返回,检查返回的文件句柄,得到最后的所要访问的文件句柄。得到文件句柄的流程图如下所示,它展示了当客户机要在服务器的分层结构中查找一个路径为/a/b/c的文件时,客户机和服务器之间所进行的信息交换。句柄Hr在Hb中查找c句柄Hc句柄Hb句柄Ha在Ha中查找b在Hr中查找a请求根句柄发送的报文服务器端客户机端以后对该文件的各种操作,就通过该文件句柄来实现了。各种操作可以参见前
10、一小节上面所列出的NFS远程过程。14 网络文件系统下层实现远程过程调用(RPC)由于NFS的底层实现是采用远程过程调用(RPC)来实现的。因此在这里,我们将先概述一下RPC的基本模型、机制以及SUN RPC的定义。在下一章中,我们将详细介绍NFS的Mount协议以及对文件操作的远程过程是如何用RPC来具体实现的。141 RPC的概念模型远程过程调用模型主要来自于传统编程语言中的过程调用机制。过程调用提供了一个强有力的抽象,它允许程序员将一个程序划分为一些小的、可管理的、易于理解的片段。它可以给出程序执行的概念性模型的简单明了的实现。图一 远程过程调用模型计算机二计算机一Proc7Proc4P
11、roc6Proc5Proc3Proc2Proc1mainRPC使用了和传统程序一样的过程抽象,只是它允许一个过程的边界跨越两台计算机。图一展示了远程过程调用模型如何将一个程序划分为两片,每片在一个单独的计算机上执行。根据过程执行模型,单个控制线索流经所有过程。计算机从一个主程序开始执行,它将一直继续下去,直到遇到一个过程调用。这个调用使执行转入到某个指定的过程代码并继续执行,直到遇到一个return语句。因此在RPC中,一个远程过程调用把控制权传递给被调用的过程,把调用过程的执行挂起。而远程的服务器则实现这个过程,当执行完毕,它给客户机一个响应,这对应于过程模型的return。使控制权返回给调
12、用者,被调用过程停止执行。这个过程是可嵌套的。142 SUN RPC的定义Sun Microsystems公司定义了一个特定形式的远程过程调用。它称为Sun RPC。它定义了调用者(客户机)发出的调用服务器中的某个远程过程的报文的格式、参数的格式,以及被调用过程返回给调用者的结果的格式。Sun RPC通过定义一个远程执行环境而扩展了远程过程调用模型。它定义了一个远程程序,把它作为在远程机器上执行的软件的基本单元。每个远程程序对应于我们所设想的一个服务器,它包括一组远程过程以及全局数据。在一个远程程序中的所有过程都能共享它的全局数据。SUN Microsystems公司设计了一种外部数据表示,它
13、规定了在网络传输数据时如何表示成公共形式的数据。Sun的外部数据表示XDR已成为大多数客户机-服务器应用的一个事实上的标准。RPC远程过程调用的数据传输的数据必须遵循XDR标准。Sun RPC标准说明,在某个计算机上执行的每个远程程序都必须分配一个唯一的32比特整数,调用者使用该整数来标识这个程序。并且,针对每个远程程序的整数型还有一个版本号,使程序可以不必获得一个新的程序号就能改变某个远程过程的细节。此外,SUN RPC为每一个给定的远程程序中的远程过程分配了一个整数标识符。因此,每个RPC报文通过一个三元组来标识某台给定计算机上的所期望的接受者,这个三元组是:(prog, vers, pr
14、oc)在此,prog标识远程程序,vers表示抱文所要发往的程序的版本号,proc表示该远程程序中的某一个远程过程。143 SUN RPC的传输层实现机制1431 通信语义为保证RPC语义的实现,我们必须在良种可能中进行选择。一方面,为尽量使远程过程调用的行为像一个本地过程调用,RPC应该使用一种像TCP这样可靠的运输,而且应该对程序员保证可靠性。另一方面,为允许程序员使用高效率的、无连接的运输协议,远程过程调用机制应当支持用UDP这样的数据报协议进行通信。因为UDP传输的不可靠性,在传输过程中可能因为报文的丢失,使得调用者无法做出应答,而导致远程过程被多次调用。因此,选择UDP作为PRC应用
15、传输协议的程序员,他们所构建的程序必须要能容忍零或多次执行语义。在我们下一章的Linux源代码分析中,我们将看到,Linux对于RPC远程过程调用的实现是采用UDP作为它的传输层应用协议来进行的。目前的Linux系统中,并没有采用TCP协议来实现网络文件系统的传输层应用。Linux设计者在这方面的考虑应该是基于实现NFS系统传输的高效性,对于TCP协议的支持相信Linux将会在以后实现。1432 动态端口映射在使用TCP或UDP协议进行远程数据传输的时候,需要指定一个服务器的通信端口号。但是,SUN RPC引出了一个有趣的问题:因为它使用32位比特数来标识远程程序,而UDP和TCP运输协议使用
16、16比特数的协议端口号来标识通讯端点,这就有可能超出协议端口的范围。因此,不可能将RPC程序号直接映射到协议端口号,因此RPC不能象其他通讯协议一样使用分配知名端口的协议。但是尽管RPC程序的潜在数量超过了分配知名端口的能力,但RPC和其他服务没有什么不同。在任意给定时间内,单个计算机仅仅执行少量的远程程序。因此,只要端口分配是临时的,每个RPC程序可以获得一个协议端口号,并且使用这个端口号进行通信。PRC对于协议端口的获得是通过一个称之为端口映射器的机制来实现的。因为服务器端口映射是临时的,每个 RPC程序在数据传输前可以获得一个协议端口号,并且使用这个传输端口进行通信。然而,作为发起远程过
17、程调用的客户机程序,除了知道它所希望与之联系的机器地址以及RPC程序号以外,它还必须在开始执行之后获得一个协议端口,否则不能直接联系远程程序。这种端口映射必须是动态的,因为如果机器重启动或者RPC程序再次开始执行,端口可能会改变。ONC RPC机制包含了一个动态映射服务。提供RPC程序的每台机器维护着一个端口映射数据库,而且提供了一种允许调用者将RPC端口号映射为协议端口的机制。它在每台机器中用一个服务器维护这一个小数据库,这个服务器被称为RPC端口映射器。一个RPC程序一旦注册了自己,其他机器上的调用者就可以通过向端口映射器发送一个请求来找到它的协议端口。144 一次RPC远程调用的具体流程
18、通过以上两小节的讨论,我们对RPC体系的实现从上到下有了一个概念上的认识。这一小节中,将具体说明一次远程过程调用的具体实现,从而加深对这部分实现机制的认识。一个RPC远程过程调用的流程如下:1. 需要运行一个远程程序时,本地机器向端口映射器发出注册请求,将一个三元组加到数据库: (RPC程序号,协议端口号,版本号) 并分配给该远程程序一个通信协议端口。2. 调用方发送RPC查找请求,调用TCP或UDP协议,将请求报文发送到服务器端口映射器的知名端口,在给定一RPC程序号和版本号时查找其协议端口。3. 端口映射器返回这个指定程序当前正在使用的协议端口号。4. 调用者在得到了该目标程序正在使用的端
19、口号后,可以直接联系远程程序了。此后,调用方将调用的远程过程的名称、类型、版本号、一些传输的XDR数据结构,进行参数的序列化,构成RPC报文。在调用方和服务器之间实现通信传输。2. Linux的NFS系统框架 NFS是由客户和服务器共同合作实现的:在客户一边,通过一些核心函数调用来使用远程文件系统;在服务器一边,由NFS服务器监听进程来提供文件数据。主要有两个监听进程moutd和nfsd,其中moutd用来监听客户的安装请求,并发送相应的应答信息,如客户端地址和服务器地址等;而nfsd进程用来监听客户端的读写文件请求并返回相应的文件数据。文件的访问对客户来说是完全透明的,并且NFS可以跨越各种
20、服务器和主机平台进行。同其他文件系统在底层是通过访问磁盘不同,NFS在底层是通过RPC(远程过程调用)协议来实现文件访问的。NFS的主要优点是可以将占用大量磁盘空间的或用户共享的数据只保存在一个NFS服务器上,其它主机要访问这些数据,只需通过NFS将其安装到本地目录进行透明的访问。所谓透明的访问,是指访问这些文件与访问本地的一般文件的用户界面是一致的,并不需要额外的命令。如下图: (NFS服务器)21 源码分析环境我们分析的Linux内核代码版本为2.2.5(套装系统为RedHat 6.0)。Linux从2.2.X版本开始,对内核中NFS部分的内容有了重大的改进。增加了很多内容,重写了很多函数
21、,功能有了很大的改进。其中比2.0.34版本的内核的主要改进有:在内核中增加了NFS的Server端内容。而在2.0.34版本中Server端并不在内核中支持,需要外部Server程序。将NFS与RPC的实现分开,使RPC可以不仅为NFS提供服务,还可以为其他网络协议提供服务。显著增强了RPC的功能,增加了如RPC调用的调度、权限验证、端口映射器以及支持同步和异步调用两种方式等功能。在这一章中,我们将主要介绍Linux下网络文件系统所用到的主要数据结构及他们之间的关系。在下一章开始,我们将详细阐述系统运作的流程。22 Linux下NFS的体系结构Linux下网络文件系统主要分为两个部分:NFS
22、 Client端、NFS Server端,即采用Client-Server体系结构。其中Client 方面主要负责处理用户对远程文件的操作请求,并把请求的内容按一定的包格式从网络发给文件所在的Server方面。而Server方面则接受Client方面的请求,调用本机的VFS的函数进行文件的实际操作,并把结果按一定格式返回给Client方面。而Client方面得到Server的返回结果,把它返回给用户。 这是Linux下网络文件系统的基本体系结构:NFS体系结构服务器端客户端VFSSocketXDRRPCNFS安装协议SocketXDRRPCNFS安装协议VFS23 NFS的Client端由上图
23、所示,Client端从高层到底层由四部分组成:VFS、NFS、RPC、Socket。下面将介绍各个部分的实现以及他们之间的接口。231 Client端的VFS层Linux最大的特点之一是它支持多种文件系统,如:EXT、EXT2、XIA、MINIX、UMSDOS、MSDOS、VFAT、PROC、SMB、NCP、ISO9660、SYSV、HPFS、SFFS和UFS等等,甚至还支持NFS。它之所以能支持这么多的文件系统,是由于它在具体的文件系统上增加了一层抽象层:VFS文件系统。VFS文件系统将独立于具体文件系统的数据和操作集中在自身之中,并通过数据结构中的UNION类型和函数指针将具体的文件系统包
24、容进来。这种分层的概念,使得Linux不仅可以有良好的兼容性,而且也使它有较大的可扩充性。VFS文件系统是建立在具体文件系统上的一个抽象层次。它必须管理在Linux系统中的每一个具体的文件系统。为此,它维护着众多的数据结构,这些数据结构描述了整个文件系统和实际的安装上的文件系统。其中最主要的数据结构有super_block、inode、file、file_system_type、dentry等。在这些数据结构中,包含了一些与具体文件系统的接口,下面将结合NFS层逐个进行介绍这些数据结构及其和NFS的接口。NFS的常数和文件模式定义了六种基本常数来指明协议所用数组的大小。另外,象UNIX一样,N
25、FS假定每个文件或目录一个指明其类型和存取保护的模式(mode)。图23.7列出了NFS模式整数的单个比特及其含义。定义直接对应于UNIX的stat函数的返回值。 #define NFS_PORT 2049 #define NFS_MAXDATA 8192 #define NFS_MAXPATHLEN 1024 #define NFS_MAXNAMLEN 255 #define NFS_MAXGROUPS 16 #define NFS_FHSIZE 32 #define NFS_COOKIESIZE 4 #define NFS_FIFO_DEV (-1) #define NFSMODE_FMT
26、 0170000 #define NFSMODE_DIR 0040000 /这是个目录;类型是 NFDIR #define NFSMODE_CHR 0020000 /这是个字符专有文件;类型应该是NFCHR #define NFSMODE_BLK 0060000 /这是个块专有文件:类型应该是NFBLK #define NFSMODE_REG 0100000 /这是个普通文件;类型应该是NFREG #define NFSMODE_LNK 0120000 /这是个符号连接,类型应该是NFLNK #define NFSMODE_SOCK 0140000 /这是个有名的插口,类型应该是NFSOCK
27、#define NFSMODE_FIFO 0010000 NFS的调用返回值协议定义一个常量枚举类型,被用于报告差错状态。每个远程调用都返回其中的一个值。该协议的集合命名为stat,如下: enum nfs_stat NFS_OK = 0, NFSERR_PERM = 1, NFSERR_NOENT = 2, NFSERR_IO = 5, NFSERR_NXIO = 6, NFSERR_EAGAIN = 11, NFSERR_ACCES = 13, NFSERR_EXIST = 17, NFSERR_XDEV = 18, NFSERR_NODEV = 19, NFSERR_NOTDIR = 2
28、0, NFSERR_ISDIR = 21, NFSERR_INVAL = 22, /* that Sun forgot */ NFSERR_FBIG = 27, NFSERR_NOSPC = 28, NFSERR_ROFS = 30, NFSERR_OPNOTSUPP = 45, NFSERR_NAMETOOLONG = 63, NFSERR_NOTEMPTY = 66, NFSERR_DQUOT = 69, NFSERR_STALE = 70, NFSERR_WFLUSH = 99 ;NFS的文件类型:NFS使用和UNIX相同的基本文件类型。它定义了服务器在指定文件类型时可使用的枚举值。 e
29、num nfs_ftype NFNON = 0, /说明不是一个文件 NFREG = 1, /一般的数据文件 NFDIR = 2, /是一个目录文件 NFBLK = 3, /是一个块设备文件 NFCHR = 4, /是一个字符设备文件 NFLNK = 5, /是一个符号链接 NFSOCK = 6, NFBAD = 7, NFFIFO = 8 ;NFS的文件句柄:在目前的linux版本中,文件句柄定义为一个32字节长度的数组。在Sun MicroSystem的NFS标准中,文件句柄分为许多个字段,其中有必要提及的是其中的随机生成的一个文件索引结点号。文件生成号的使用主要出于对网络文件访问安全性的
30、考虑出发。因为一旦客户机知道了远程文件系统服务主机的文件目录结构,以及产生文件句柄的方式,可以很容易地构造出某个指定路径上的文件句柄,并通过该句柄对远程文件系统进行访问。这样,就违背了网络访问的安全性原则,因此在标准的NFS文件系统中,当文件系统服务器收到客户机的访问请求时,除了返回相应文件的文件句柄以外,还动态地随机生成此文件对应的文件生成号,一般是一个32字节的字符串,提供给客户机。这样,以后客户机在访问服务器的文件系统时,通过检查文件句柄结构中所带的文件生成号是否匹配,就可以决定是否是一次合法的访问。这种机制保证了NFS文件系统远程访问的安全性。 struct nfs_fh char d
31、ataNFS_FHSIZE; ;NFS的远程过程定义:这里只定义了各个远程过程的程序号,具体每个过程的功能将在后面介绍。 #define NFS_PROGRAM 100003 #define NFS_VERSION 2 #define NFSPROC_NULL 0 #define NFSPROC_GETATTR 1 #define NFSPROC_SETATTR 2 #define NFSPROC_ROOT 3 #define NFSPROC_LOOKUP 4 #define NFSPROC_READLINK 5 #define NFSPROC_READ 6 #define NFSPROC_WRITECACHE 7 #define NFSPROC_WRITE 8 #define NFSPROC_CREA
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1