在 CentOS/Redhat 环境中编译 NFS

NFS 在 Redhat 内核中默认以模块的方式编译安装,因此编译 NFS 代码无需编译整个内核,仅需要编译 NFS 模块及其相关模块,然后将模块进行替换即可。

NFS 源码结构

NFS 从架构上分客户端和服务端,详细参考 NFS 架构

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 目录的相关实现

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 文件系统的操作转换成具体文件系统的操作

编译 NFS

编译 NFS 需要满足两个前置条件:

  • 获取对应版本的内核源码。内核版本可以使用uname -r查看,具体获取方法可以参考这里
  • 安装内核编译软件依赖包。

编译内核模块步骤如下:

  • 进入模块目录,如fs/nfs
  • 运行make CONFIG_XXX=m -C <kernel_devel_path> M=$(pwd) modules。其中,CONFIG_XXX是模块在内核配置项中的名称,<kernel_devel_path>是内核开发包的位置,一般位于/usr/src/kernels/<unamr -r>注意区分该位置和内核源码位置

模块就像 rpm 软件包一样,可以安装、卸载,模块和模块之间也存在依赖关系。命令如下:

1
2
3
4
5
6
7
# 查看所有被加载的模块
lsmod
lsmod |grep <module_name>
# 安装模块
insmod <module_ko>
# 卸载模块
rmmod <module_name>

编译依赖模块

NFS 模块依赖于fscache模块。先通过lsmod |grep fscache查看该模块是否安装,如已安装可以跳过本节继续进行。

进入源码目录fs/fscache,使用如下命令进行编译。

1
make CONFIG_FSCACHE=m -C <kernel_devel_path> M=<kernel sourece path>/fs/fscache modules

编译完成后安装模块:

1
insmod <kernel sourece path>/fs/fscache/fscache.ko

编译 NFS

进入源码目录,客户端进入fs/nfs,服务端进入fs/nfsd,运行编译模块命令:

1
2
3
4
# client
make CONFIG_NFS_FS=m -C <kernel_devel_path> M=<kernel sourece path>/fs/nfs modules
# server
make CONFIG_NFSD=m -C <kernel_devel_path> M=<kernel sourece path>/fs/nfsd modules

编译完成后,fs/nfs目录下会生成nfs.ko/nfsv3.ko/nfsv4.kofs/nfsd目录下会生成nfsd.ko

安装 NFS 模块

在安装模块之前,需要查看该模块是否已被系统加载:

1
lsmod |grep nfs

如果已被加载,需要先卸载该模块和其他依赖该模块的模块

nfsnfsv3/nfsv4依赖,卸载前卸载这两个依赖模块。如提示Module xxx is in use,检查是否有 NFS 挂载

nfsd被十多个进程、服务依赖,卸载前运行systemctl stop nfs-server/proc-fs-nfsd.mount

sunrpc被更多服务、模块依赖,可以通过lsmod |grep sunrpc查看依赖模块,停止systemctl stop var-lib-nfs-rpc_pipefs.mount

卸载已加载模块后,可以直接安装新编译的内核模块。

1
2
3
4
# client
insmod nfsv3.ko/nfsv4.ko/nfs.ko
# server
insmod nfsd