概述
因为工作中使用了 NFS,所以有时需要定位一些和 NFS 相关的问题,但是,对于 NFS 除了简单的使用之外,原理以及组件通信还有 IO 路径这些都不是很清楚,所以在这篇文章中我将总结一下 NFS Server 的通信架构以及 mount 的 IO 路径。
访问 Mount NFS 目录
这里的内容很多都和我以前写过的关于 Linux 文件系统模型 相关,所以可以先了解一下这篇文章再看下面的内容。
当我们通过 mount 挂载了一个 NFS 目录时,在 Linux 的文件系统中,会创建一个 vfsmount 和 superblock,用于记录 NFS 的挂载信息,然后将 vfsmount 对象加入到 VFS 的 mount 树和 Hash Table 中,这样就算是挂载好了。
然后,当访问的时候,首先打开的是文件对象,然后再定位到 vfsmount,再接着就可以访问到 superblock 了,这样就可以通过 NFS 的模块和 Server 进行通信了:
图 1:文件系统访问 |
---|
NFS 通信原理
图 2:NFS CS 通信原理 |
---|
NFS 的进程
rpc.nfsd 进程
NFS 服务的主进程,主要管理客户端是否能够接入 NFS 服务器以及数据的传输。
该进程固定监听 TCP/UDP 2049 端口。rpc.mountd 进程
管理和维护 NFS 文件系统,根据所设定的权限决定是否允许客户端挂载指定的共享目录。
该进程监听的端口默认是不固定的。rpc.lockd 进程(可选)
提供文件锁功能,防止多个客户端同时写入一个文件。
该进程监听的端口默认是不固定的。rpc.statd 进程(可选)
负责检查数据的状态及一致性,需要与 rpc.lockd 配合使用。
该进程监听的端口默认是不固定的。portmap
因为 rpc.mountd / rpc.lockd 以及 rpc.statd 的端口是不固定的,所以,nfs client 要想和 server 绑定则必须知道这些端口是什么,因此处理的方式是通过 111 端口查询这些端口信息是什么,然后再发起连接。
NFS 客户端挂载过程
- 首先服务器端启动 RPC 服务,并开启 111 端口;
- 启动 NFS 服务,并向 RPC 注册端口信息;
- 客户端启动 RPC 客户端,向服务端的 portmap(111 端口) 服务请求服务端的 NFS 端口信息;
- 服务端的 portmap 服务反馈给 Server 的端口信息给客户端;
- 客户端通过获取的 NFS 端口和服务端的 NFS 连接并进行数据的传输。
获取源代码
[root@liqiang.io]# git clone git://git.linux-nfs.org/projects/steved/nfs-utils.git