低烧是多少度,疯狂的麦咭,哈尔滨冰雪大世界-js天分,前端技术分享,互联网圈秘闻

NFS 文件体系概述

NFS(Network File System,网络文件体系)是一种依据网络的文件体系。它可以将远端服务器文件体系的目录挂载到本地文件体系的目录上,答运用户或许运用程序像拜访本地文件体系的目录结构相同,拜访远端服务器文件体系的目录结构,而无需理睬远端服务器文件体系和本地文件体系的详细类型,十分方便地完结了目录和文件在不同机器上进行同享。尽管 NFS 不是仅有完结这个功用的文件体系,但它无疑是最成功一个。

NFS 的第一个版别是 SUN Microsystems 在 20 世纪 80 时代开发出来的,至今停止,NFS 阅历了 NFS,NFSv2,NFSv3 和 NFSv4 共四个版别。现在,NFS 最新的版别是 4.1,也被称为 pNFS(parallel NFS,并行网络文件体系)。

前四个版别的 NFS,作为一个文件体系,它简直具有了一个传统桌面文件体系最根本的结构特征和拜访特征,不同之处在于它的数据存储于远端服务器上,而不是本地设备上,因而不存在磁盘布局的处理。NFS 需求将本地操作转换为网络操作,并在远端服务器上完结,最终回来操作的成果。因而,NFS 更像是远端服务器文件体系在本地的一个文件体系署理,用户或许运用程序经过拜访文件体系署理来拜访实在的文件体系。

众所周知的是,NFS 的客户端在拜访远端服务器文件体系时,既需求经过服务器取得文件的特点信息,还需求经过服务器取得文件的数据信息,这使得 NFS 天然地具有将文件的特点信息和数据信息别离在不同服务器上进行拜访的特性,所以最终一个版别 NFS4.1/pNFS,将 Lustre/CephFS/GFS 等集群文件体系的规划思维引进到本身中,成为一个具有里程碑含义的 NFS 版别。它使得 NFS 的数据吞吐的速度和规划都得到了极大进步,为 NFS 的运用带了更为宽广的空间。

NFS 之所以备受瞩目,除了它在文件同享范畴上的优异体现外,还有一个要害原因在于它在 NAS 存储体系上运用。NAS 与 DAS 和 SAN 在存储范畴的竞赛中,NFS 发挥了活跃的效果,这更使得 NFS 越来越值得重视。

NFSv3 源代码结构

比较之前的两个版别,NFSv3 是一个较为安稳和成熟的 NFS 版别,而之后的 NFSv4 除了在安全和功用上有所进步外,还在网络衔接中加入了状况特点,因而显得杂乱一些。在此,本文以 NFSv3 为例来分析 NFS 文件体系的源代码结构,所用源码来自 Linux 2.4.9 内核。

依照 NFS 文件体系的规划与完结,NFS 文件体系首要分为三个部分:The Protocol(网络协议),Client Side(NFS 客户端)和 Server Side(NFS 服务器)。NFS 客户端供给了接口,确保用户或许运用程序能像拜访本地文件体系相同拜访 NFS 文件体系,NFS 服务器作为数据源,为 NFS 客户端供给实在的文件体系服务,而网络协议则使得 NFS 客户端和 NFS 服务器可以高效和可靠地进行通讯。NFS 网络协议运用的是 RPC(Remote Procedure Call,远程进程调用)/XDR(External Data Representation,外部数据表明)机制,因而本文将分析的要点放在 NFS 客户端和 NFS 服务器上。

Client Side 源代码

Client Side 的头文件在 include/linux/ 下面,C 文件在 fs/nfs 下面。

  • dir.c/file.c/inode.c/symlink.c/unlink.c:与文件操作相关的体系调用
  • read.c/write.c/flushd.c:文件读写
  • mount_clnt.c/nfs_root.c:将 NFS 文件体系作为 root 目录的相关完结
  • proc.c/nfs2xdr.c/nfs3proc.c/nfs3xdr.c:网络数据交换

与文件操作相关的体系调用都在 struct file_operations,struct inode_operations 这两个数据结构里边界说。文件的读操作 nfs_file_read 和写操作 nfs_file_write 被独自提出来,由于文件读写功用将直接联系到文件体系的胜败,本文在后面会要点论述其完结。

Server Side 源代码

Server Side 的头文件在 include/linux/nfsd 下面,C 文件在 fs/nfsd 下面。

  • auth.c/lockd.c/export.c/nfsctl.c/nfscache.c/nfsfh.c/stats.c:导出目录的拜访办理
  • nfssvc.c:NFS 服务 deamon 的完结
  • vfs.c:将 NFS 文件体系的操作转换成详细文件体系的操作
  • nfsproc.c/nfsxdr.c/nfs3proc.c/nfs3xdr.c:网络数据交换

导出目录的拜访办理首要处理网络文件体系完结面对的几个重要问题,包括目录导出服务,外部拜访的权限操控,多客户端以及客户端与服务器的文件并发操作等。

一个典型比如:rename 的调用进程

在 NFS 文件体系的文件操作中,除了 read 和 write 操作考虑到功用要素,专门运用了缓存机制外,其它的操作根本上都是同步完结的。本文以 rename 为例来进行阐明,如下图所示。首要用户或许运用程序开端调用文件操作,经过体系调用 sys_rename,抵达虚拟文件体系层 vfs_rename,然后交给 NFS 文件体系 nfs_rename 来处理。NFS 文件体系无法操作存储介质,它调用 NFS 客户端函数 nfs3_proc_rename 和 NFS 服务器函数 nfsd3_proc_rename 进行通讯,把文件操作转发到 NFS 服务器的虚拟文件体系层 vfs_rename,最终调用详细的文件体系如 ext2 的函数 ext2_raname,完结文件重命名。

图 1. rename 调用进程

与传统文件体系相同点

在论述 NFS 文件体系与传统桌面文件体系的相同点之前,咱们首要扼要回忆一下 Linux 操作体系上文件体系的体系结构。依照 Linux 文件体系分析的区分,Linux 文件体系从上至下首要由虚拟文件体系层,特定文件体系层和页高速缓存层三部分组成,如下图所示。当然,这种区分并不是必定的,例如在履行直接 I/O 调用时,是不需求进行页高速缓存的,别的,关于块设备的读写,进行页高速缓存之后还会有通用块层和 I/O 调度层的处理。

图 2. 文件体系体系结构

用户或许运用程序经过一致的体系调用接口对文件体系进行操作,然后体系调用进入虚拟文件体系层,虚拟文件体系依据文件体系类型,调用特定文件体系的操作函数。对用户和运用程序来说,由于接口完全相同,因而用户感觉不到差异,运用程序也可以无缝地移植到 NFS 文件体系上。Linux 经过一组目标对文件体系的操作,这组目标是 superblock(超级块目标),inode(索引节点目标),dentry(目录项目标)和 file(文件目标),如下图所示。一切文件体系都支撑这些目标,正是由于它们,VFS 层可以对 NFS 和其它文件体系天公地道,只管调用这些目标的数据和函数指针,把详细的文件体系数据布局和操作都留给特定的文件体系来完结。

图 3. VFS 目标

NFS 与其它文件体系相同,向内核声明和注册自己的文件体系类型。

static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME); 
... ...
module_init(init_nfs_fs)
module_exit(exit_nfs_fs)

相同,NFS 也需求依据自己的文件类型设置相应的文件操作函数。假如是正规文件,需求设置 inode 操作函数,file 操作函数,以及 address_space 操作函数;假如是目录文件,需求设置 inode 操作函数,file 操作函数;假如是链接,则只需设置 inode 操作函数。

static void 
nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
... ...
inode->i_op = &nfs_file_inode_operations;
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &nfs_file_operations;
inode->i_data.a_ops = &nfs_file_aops;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &nfs_dir_inode_operations;
inode->i_fop = &nfs_dir_operations;
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else
init_special_inode(inode, inode->i_mode, fattr->rdev);
... ...
}

与传统文件体系不同点

与内存文件体系,闪存文件体系和磁盘文件体系这些本地文件体系最大的不同在于,NFS 文件体系的数据是依据网络,而不是依据存储设备的,因而 NFS 文件体系在规划自己的 inode 和 superblock 数据结构,以及完结文件操作函数时,无需考虑数据布局状况。相同是由于依据网络,NFS 文件体系的权限操控和并发拜访的要求比本地文件体系更高,读写的缓存机制也大大有别于本地文件体系。

superblock 和 inode

清单 1. NFS 的 superblock 界说

struct rpc_clnt * client; /* RPC 客户端句柄 */ 
struct nfs_rpc_ops * rpc_ops; /* RPC 客户端函数向量表 */
int flags; /* 标识信息 */
unsigned int rsize; /* 每次读恳求的最小数据量 */
unsigned int rpages; /* 每次读恳求的最小数据量(以页为单位)*/
unsigned int wsize; /* 每次写恳求的最小数据量 */
unsigned int wpages; /* 每次写恳求的最小数据量(以页为单位)*/
unsigned int dtsize; /* 每次读目录信息的最小数据量 */
unsigned int bsize; /* NFS 服务器端的块巨细 */
unsigned int acregmin; /* 正规文件在缓存中驻留的最小答应时刻 */
unsigned int acregmax; /* 正规文件在缓存中驻留的最大答应时刻 */
unsigned int acdirmin; /* 目录文件在缓存中驻留的最小答应时刻 */
unsigned int acdirmax; /* 目录文件在缓存中驻留的最大答应时刻 */
unsigned int namelen; /* NFS 服务器端的主机称号最大长度 */
char * hostname; /* NFS 服务器端的主机称号 */
struct nfs_reqlist * rw_requests; /* 异步读写恳求行列信息 */

清单 2. NFS 的 inode 界说

__u64 fsid; /* 根目录(导出目录)信息 */ 
__u64 fileid; /* 当时文件信息 */
struct nfs_fh fh; /* 文件句柄 */
... ...
struct list_head read; /* 读数据页行列 */
struct list_head dirty; /* 脏数据页行列 */
struct list_head commit; /* 提交数据页行列 */
struct list_head writeback; /* 写回数据页行列 */
unsigned int nread, /* 读数据页数量 */
ndirty, /* 脏数据页数量 */
ncommit, /* 提交数据页数量 */
npages; /* 写回数据页数量 */
... ...

以上省掉了 superblock 和 inode 界说的公共部分,列出的仅是 NFS 文件体系 superblock 和 inode 界说的私有部分,由于只要这些私有界说才干体现出文件体系的规划准则。从这些界说可以看出,私有部分数据结构里边首要包括网络衔接和读写恳求两个方面相关的信息。superblock 里 client 界说了 RPC 协议的客户端衔接状况,rpc_ops 界说了 RPC 协议的客户端进口函数,如 nfs3_proc_read,nfs3_proc_write,nfs3_proc_create 等。inode 里 fh 是 NFS 客户端和 NFS 服务器彼此传递的要害参数,4 个页行列用于进行读写缓存,随后两末节将别离予以介绍。

file handle

file handle(fh 或许 fhandle)在 NFS 客户端和 NFS 服务器之间彼此传递,树立 NFS 客户端的 inode 和 NFS 服务器的 inode 的相关联系。它首要表征的是 NFS 服务器上 inode 和物理设备的信息。file handle 关于 NFS 客户端来说是通明的,NFS 客户端不需求知道它的详细内容。file handle 在 NFS 客户端的界说是 66 个字节,前两个字节组成一个无符号 short 型,表明 file handle 的巨细,后 64 个字节组成数据区,存储 file handle 的内容。

#define NFS_MAXFHSIZE 64 
struct nfs_fh {
unsigned short size;
unsigned char data[NFS_MAXFHSIZE];
};

file handle 在 NFS 服务器的界说由 knfsd_fh 数据结构表明,fh_size 表明 file handle 的巨细,数据区 fh_base 是一个联合体,有 fh_old,fh_pad,fh_new 三种界说,最大也是 64 个字节。考虑到当时的 NFS 版别是 v3,只看 fh_new 的界说。fh_version 表明 fh_new 界说的版别,当时版别是 1。fh_auth_type 表明认证办法,0 表明不认证。fh_fsid_type 表明根目录(即导出目录)的信息存储办法,假如是 0,那么从 fh_auth 开端前 2 个字节表明根目录地点设备的 major 号,后 2 个字节表明根目录地点设备的 minor 号,随后的 4 个字节表明根目录的 inode 索引号。fh_fileid_type 表明当时文件的信息存储办法,假如是 1,那么在表明完 fh_fsid 后,紧接着 4 个字节表明当时文件的 inode 索引号,之后 4 个字节表明当时文件的 inode generation 号。

struct nfs_fhbase_new { 
__u8 fb_version; /* == 1, even => nfs_fhbase_old */
__u8 fb_auth_type;
__u8 fb_fsid_type;
__u8 fb_fileid_type;
__u32 fb_auth[1];
};

read 和 write

前面介绍文件体系体系结构的时分,将它分为了虚拟文件体系,特定文件体系和页高速缓存三个层次。NFS 文件体系运用了这三个层次的功用,它本身完结了特定文件体系的功用,一起既为虚拟文件体系供给了完好的调用接口,也用到了页高速缓存来进步读写功用。就层次区分而言,与传统桌面文件体系比较,NFS 文件体系的读写操作不再需求通用块层和 I/O 调度层,而是运用了多个列表以及相关操作来进一步缓存数据,增强读写功率。当然 NFS 文件体系也不再运用存储设备驱动,而是经过网络协议来获取和提交数据。

图 4. 读写缓存机制

如上图所示,NFS 文件体系运用 read,writeback,dirty 和 commit 四个行列,每个行列的单元数据结构都是 nfs_page,每个 nfs_page 都有一个 page 变量指向页高速缓存。读办法 nfs_readpage 首要运用异步办法读取数据,假如异步办法失效,才运用同步办法,nfs_readpage_async 所读的数据都进入 read 行列中。写办法 nfs_writepage 假如写数据超越一页(缺省是 4096 字节),运用异步办法提交数据,不然运用同步办法。nfs_writepage_async 所写的数据首要进入 writeback 行列,假如数据发作更改,则进入 dirty 行列,假如将更改的数据提交到 NFS 服务器上,则进入 commit 行列。这些行列或许由于超时,或许由于单元数量多于最大值,将被释放掉。

权限认证和并发锁

NFSv3 版别运用 nfs_permission 做用户权限认证,用 nfs_revalidate 做文件合法性查看。前者调用 access 体系调用同步完结,后者调用 getattr 同步完结。为了使多个 NFS 客户端或许 NFS 客户端与 NFS 服务器对相同文件可以完结并发操作,NFS 运用 NLM(network lock management,网络锁办理)协议在 NFS 服务器上对文件进行翻开,读写和移除,使不同的拜访都有及时和同一的语义了解。

总结

本文分析了 NFS 文件体系的规划,首要分为三个部分,NFS 客户端,NFS 服务器和网络协议,并论述了三者的功用区分,介绍了它们是怎么组织起来,为用户或许运用程序供给文件服务。进一步的,本文运用 Linux 2.4.9 内核分析了 NFSv3 的源代码完结,从源代码层次阐明晰 NFS 文件体系的完结细节,要点介绍了它与传统桌面文件体系的相同和不同之处,使读者可以深化了解 NFS 文件体系的实质。pNFS 是 NFS 文件体系从桌面型文件体系到集群型文件体系的一个转机性版别,读者可自行阅览 pNFS 的源代码完结。在阅览之前,引荐读者首要阅览 Luster/CephFS/GFS 等文件体系相关的论文和材料,以便对集群文件体系的规划架构有个根本的知道。