首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

NFS 文件系统源代码剖析(2)

NFS 文件系统源代码剖析(2)

清单 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. 读写缓存机制
图 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 等文件系统相关的论文和资料,以便对集群文件系统的设计架构有个基本的认识。
继承事业,薪火相传
返回列表