第 3 章 Linux NFS 网络文件系统

作者: Brinnatt 分类: ARM64 Linux 进阶架构 发布时间: 2022-01-21 13:39

类似 ext 家族、xfs 格式的本地文件系统,它们都是通过单个文件名称空间(name space)来包含很多文件,并提供基本的文件管理和空间分配功能。这类文件系统和存在上面的文件都是存放在本地主机上的。

实际上,还有网络文件系统。顾名思义,就是跨网络的文件系统,将远程主机上的文件系统(或目录)存放在本地主机上,就像它本身就是本地文件系统一样。在 Windows 环境下有 cifs 协议实现的网络文件系统,在 Unix 环境下,最出名是由 NFS 协议实现的 NFS 文件系统。

3.1、RPC 框架

要介绍 NFS,必然要先介绍 RPC。RPC 是 remote procedure call 的简写,人们都将其译为 "远程过程调用",它是一种框架,这种框架在大型公司应用非常多。而 NFS 正是其中一种,此外 NIS、hadoop 也是使用 rpc 框架实现的。

3.1.1、RPC 原理

所谓的 remote procedure call,就是在本地调用远程主机上的 procedure。

以本地执行 "cat -n ~/abc.txt" 命令为例,在本地执行 cat 命令时,会发起某些系统调用(如 open()、read()、close() 等),并将 cat 的选项和参数传递给这些函数,于是最终实现了文件的查看功能。

如何实现远程 cat,甚至其他远程命令?通常有两种可能实现的方式:

  1. 使用 ssh 类的工具,将要执行的命令传递到远程主机上并执行。但 ssh 无法直接调用远程主机上 cat 所发起的那些系统调用(如 open()、read()、close() 等)。

  2. 使用网络 socket 的方式,告诉远程服务进程要调用的函数。但这样的主机间进程通信方式一般都是 daemon 类服务,daemon 类的客户端(即服务的消费方)每调用一个服务的功能,都需要编写一堆实现网络通信相关的代码。不仅容易出错,还比较复杂。

    而 rpc 是最好的解决方式。rpc 是一种框架,在此框架中已经集成了网络通信代码和封包、解包方式(编码、解码)。以下是 rpc 整个过程,以 cat NFS 文件系统中的 a.sh 文件为例。

    rpc stub

  3. nfs 客户端执行 cat a.sh,由于 a.sh 是 NFS 文件系统内的文件,所以 cat 会发起一些 procedure 调用(如open/read/close),这些 procedure 对应的 ID 号码和对应的参数会发送给 rpc client(可能是单个 procedure ID,也可能是多个 procedure 组合在一起一次性发送给 rpc client,在 NFSv4 上是后者)。

  4. rpc client 会将这些数据进行编码封装(封装和解封装功能由 stub 代码实现),封装后的消息称为 "call message"。

  5. call message 通过网络发送给 rpc server,rpc server 会对封装的数据进行解封提取,于是就得到了要调用的 procedures ID 和对应的参数,然后将它们交给 NFS 服务进程,最终调用 procedure ID 对应的 procedure 来执行,并返回结果。

  6. NFS 服务发起 procedure 调用后,会得到数据(可能是数据本身,可能是状态消息等),于是将返回结果交给 rpc server,rpc server 会将这些数据封装,这部分数据称为 "reply message"。

  7. 然后将 reply message 通过网络发送给 rpc client,rpc client 解封提取,于是得到最终的返回结果。

3.1.2、RPC 工具介绍

在 ARM64 RedFlag ATM Linux for Phytium 7.5.1804.14 操作系统上,rpc server 由 rpcbind 程序实现,该程序由 rpcbind 包提供。

[root@arm64v8 ~]# yum install rpcbind
[root@arm64v8 ~]# rpm -ql rpcbind | grep bin/
/usr/sbin/rpcbind
/usr/sbin/rpcinfo
[root@arm64v8 ~]#

其中 rpcbind 是 rpc 主程序,在 rpc 服务端该程序必须处于已运行状态,其默认监听在 111 端口。rpcinfo 是 rpc 相关信息查询工具。

对于 rpc 而言,直接管理的是 programs,programs 由一个或多个 procedure 组成。这些 program 称为 RPC program 或 RPC service。

rpc programs

其中 NFS、NIS、hadoop 等称为网络服务,它们由多个进程或程序(program)组成。

例如 NFS 包括 rpc.nfsd、rpc.mountd、rpc.statd 和 rpc.idmapd 等 programs,其中每个 program 都包含了一个或多个 procedure,例如 rpc.nfsd 这个程序包含了如 OPEN、CLOSE、READ、COMPOUND、GETATTR 等 procedure,rpc.mountd 也主要有 MNT 和 UMNT 两个 procedure。

对于 RPC 而言,它是不知道 NFS/NIS/hadoop 这一层的,它直接管理 programs。每个 program 启动时都需要找 111 端口的 rpc 服务登记注册,然后 RPC 服务会为该 program 映射一个 program number 以及分配一个端口号。每个 program 都有一个唯一与之对应的 program number,它们的映射关系定义在 /etc/rpc 文件中。

以后 rpc server 将使用 program number 来判断要调用的是哪个 program 中的哪个 procedure(因为这些都是 rpc client 封装在 "call message" 中的),并将解包后的数据传递给该 program 和 procedure。

例如只启动 rpcbind 时。

[root@arm64v8 ~]# systemctl start rpcbind.service
[root@arm64v8 ~]# 
[root@arm64v8 ~]# rpcinfo -p localhost
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   tcp    111  portmapper
    100000    4   udp    111  portmapper
    100000    3   udp    111  portmapper
    100000    2   udp    111  portmapper
[root@arm64v8 ~]#

其中第一列就是 program number,第二列 vers 表示对应 program 的版本号,最后一列为 RPC 管理的 RPC service 名,其实就是各 program 对应的称呼。

当客户端获取到 rpc 所管理的 service 的端口后,就可以与该端口进行通信了。但注意,即使客户端已经获取了端口号,客户端仍会借助 rpc 做为中间人进行通信。也就是说,无论何时,客户端和 rpc 所管理的服务的通信都必须通过 rpc 来完成。之所以如此,是因为只有 rpc 才能封装和解封装数据。

既然客户端不能直接拿着端口号和 rpc service 通信,那还提供端口号干嘛?这个端口号是为 rpc server 提供的,rpc server 解包数据后,会将数据通过此端口交给对应的 rpc service。

3.2、启动 NFS

NFS 本身是很复杂的,它由很多进程组成。这些进程的启动程序由 nfs-utils 包提供。由于 nfs 是使用 RPC 框架实现的,所以需要先安装好 rpcbind。不过安装 nfs-utils 时会自动安装 rpcbind。

[root@arm64v8 ~]# yum install nfs-utils -y
[root@arm64v8 ~]# rpm -ql nfs-utils | grep /usr/sbin
/usr/sbin/blkmapd
/usr/sbin/exportfs
/usr/sbin/mountstats
/usr/sbin/nfsdcltrack
/usr/sbin/nfsidmap
/usr/sbin/nfsiostat
/usr/sbin/nfsstat
/usr/sbin/rpc.gssd
/usr/sbin/rpc.idmapd
/usr/sbin/rpc.mountd
/usr/sbin/rpc.nfsd
/usr/sbin/rpcdebug
/usr/sbin/showmount
/usr/sbin/sm-notify
/usr/sbin/start-statd
[root@arm64v8 ~]#

其中以 "rpc." 开头的程序都是 rpc service,分别实现不同的功能,启动它们时每个都需要向 rpcbind 进行登记注册。

[root@arm64v8 ~]# systemctl start nfs.service
[root@arm64v8 ~]# 
[root@arm64v8 ~]# rpcinfo -p localhost
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   tcp    111  portmapper
    100000    4   udp    111  portmapper
    100000    3   udp    111  portmapper
    100000    2   udp    111  portmapper
    100024    1   udp  56416  status
    100024    1   tcp  53771  status
    100005    1   udp  20048  mountd
    100005    1   tcp  20048  mountd
    100005    2   udp  20048  mountd
    100005    2   tcp  20048  mountd
    100005    3   udp  20048  mountd
    100005    3   tcp  20048  mountd
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    3   tcp   2049  nfs_acl
    100003    3   udp   2049  nfs
    100227    3   udp   2049  nfs_acl
    100021    1   udp  54716  nlockmgr
    100021    3   udp  54716  nlockmgr
    100021    4   udp  54716  nlockmgr
    100021    1   tcp  36983  nlockmgr
    100021    3   tcp  36983  nlockmgr
    100021    4   tcp  36983  nlockmgr
[root@arm64v8 ~]#
  • 可以看到,每个 program 都启动了不同版本的功能。其中 nfs program 为 rpc.nfsd 对应的 program,为 nfs 服务的主进程,端口号为 2049。
  • mountd 对应的 program 为 rpc.mountd,它为客户端的 mount 和 umount 命令提供服务,即挂载和卸载 NFS 文件系统时会联系 mountd 服务,由 mountd 维护相关挂载信息。
  • nlockmgr 对应的 program 为 rpc.statd,用于维护文件锁和文件委托相关功能,在 NFSv4 以前,称之为 NSM(network status manager)。
  • nfs_acl 和 status,很显然,它们是访问控制列表和状态信息维护的 program。

再看看启动的相关进程信息。

[root@arm64v8 ~]# ps aux | grep -E "[n]fs|[r]pc"
root       649  0.0  0.0      0     0 ?        I<   20:44   0:00 [rpciod]
rpc        679  0.0  0.0   9848  3324 ?        Ss   20:44   0:00 /sbin/rpcbind -w
rpcuser   1477  0.1  0.0   6964  3120 ?        Ss   20:50   0:00 /usr/sbin/rpc.statd
root      1483  0.0  0.0   6264  1652 ?        Ss   20:50   0:00 /usr/sbin/rpc.idmapd
root      1485  0.0  0.0   6976  1728 ?        Ss   20:50   0:00 /usr/sbin/rpc.mountd
root      1495  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1496  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1497  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1498  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1499  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1500  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1501  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
root      1502  0.0  0.0      0     0 ?        S    20:50   0:00 [nfsd]
[root@arm64v8 ~]#
  • 其中有一项 /usr/sbin/rpc.idmapd 进程,该进程是提供服务端的 uid/gid <==> username/groupname 的映射翻译服务。客户端的 uid/gid <==> username/groupname 的映射翻译服务则由 "nfsidmap" 工具实现,详细说明见下文。

3.3、配置导出目录和挂载使用

3.3.1、配置 nfs 导出目录

在将服务端的目录共享(share)或者说导出(export)给客户端之前,需要先配置好要导出的目录。比如何人可访问该目录,该目录是否可写,以何人身份访问导出目录等。

配置导出目录的配置文件为 /etc/exports 或 /etc/exports.d/*.exports 文件,在 nfs 服务启动时,会自动加载这些配置文件中的所有导出项。以下是导出示例:

/www    172.16.0.0/16(rw,async,no_root_squash)
  • 其中 /www 是导出目录,即共享给客户端的目录;172.16.0.0/16 是访问控制列表 ACL,只有该网段的客户端主机才能访问该导出目录,即挂载该导出目录;
  • 紧跟在主机列表后的括号及括号中定义的是该导出目录对该主机的导出选项,例如(rw, async, no_root_squash)表示客户端挂载 /www 后,该目录可读写、异步、可保留 root 用户的权限,具体的导出选项稍后列出。

以下是可接收的几种导出方式:

/www1    (rw,async,no_root_squash)                                  # 导出给所有主机,此时称为导出给world
/www2    172.16.1.1(rw,async)                                       # 仅导出给单台主机172.16.1.1
/www3    172.16.0.0/16(rw,async) 192.168.10.3(rw,no_root_squash)    # 导出给网段172.16.0.0/16,还导出给单台
                                                                    # 主机192.168.10.3,且它们的导出选项不同

/www4    www.a.com(rw,async)                                        # 导出给单台主机www.a.com主机,但要求能解析该主机名
/www     *.b.com(rw,async)                                          # 导出给b.com下的所有主机,要求能解析对应主机名

以下是常用的一些导出选项说明,更多的导出选项见 man exports:常见的默认项是:ro, sync, root_squash, no_all_squash, wdelay。

导出选项 选项说明
rw、ro 导出目录可读写还是只读(read-only)。
sync、async 同步共享还是异步共享。
异步时,客户端提交要写入的数据到服务端,服务端接收数据后直接响应客户端,但此时数据并不一定已经写入磁盘中;
同步则是必须等待服务端已将数据写入磁盘后才响应客户端。
也就是说,给定异步导出选项时,虽然能提升一些性能,但在服务端突然故障或重启时有丢失一部分数据的风险。
当然,对于只读(ro)的导出目录,设置 sync 或 async 是没有任何差别的。
anonuid
anongid
此为匿名用户(anonymous)的 uid 和 gid 值,默认都为 65534,在 /etc/passwd 和 /etc/shadow 中它们对应的用户名为 nfsnobody。
该选项指定的值用于身份映射被压缩时。
root_squash
no_root_squash
是否将发起请求(即客户端进行访问时)的 uid/gid=0 的 root 用户映射为 anonymous 用户。即是否压缩 root 用户的权限。
all_squash
no_all_squash
是否将发起请求(即客户端进行访问时)的所有用户都映射为 anonymous 用户,即是否压缩所有用户的权限。

对于 root 用户,将取 (no_)root_squash(no_)all_squash 的交集。例如,no_root_squashall_squash 同时设置时,root 仍被压缩,root_squashno_all_squash 同时设置时,root 也被压缩。

有些导出选项需要配合其他设置。例如,导出选项设置为 rw,但如果目录本身没有 w 权限,或者 mount 时指定了 ro 挂载选项,则同样不允许写操作。

在配置文件写好要导出的目录后,直接重启 nfs 服务即可,它会读取这些配置文件。随后就可以在客户端执行 mount 命令进行挂载。

例如,exports 文件内容如下:

/vol/vol0       *(rw,no_root_squash)
/vol/vol2       *(rw,no_root_squash)
/backup/archive *(rw,no_root_squash)

3.3.2、挂载 nfs 文件系统

然后去客户端上挂载它们。

[root@KylinV10 ~]# mount -t nfs 10.1.1.2:/vol/vol0 /mp1
[root@KylinV10 ~]# mount 10.1.1.2:/vol/vol2 /mp2
[root@KylinV10 ~]# mount 10.1.1.2:/backup/archive /mp3
[root@KylinV10 ~]#
  • 挂载时 "-t nfs" 可以省略,因为对于 mount 而言,只有挂载 nfs 文件系统才会写成 host:/path 格式。当然,除了 mount 命令,nfs-utils 包还提供了独立的 mount.nfs 命令,它其实和 "mount -t nfs" 命令是一样的。

mount 挂载时可以指定挂载选项,其中包括 mount 通用挂载选项,如 rw/ro,atime/noatime,async/sync,auto/noauto 等,也包括针对 nfs 文件系统的挂载选项。以下列出几个常见的,更多的内容查看 man nfs 和 man mount。

选项 参数意义 默认值
suid
nosuid
如果挂载的文件系统上有设置了 suid 的二进制程序,使用 nosuid 可以取消它的 suid suid
rw
ro
尽管服务端提供了 rw 权限,但是挂载时设定 ro,则还是 ro 权限
权限取交集
rw
exec
noexec
是否可执行挂载的文件系统里的二进制文件 exec
user
nouser
是否运行普通用户进行档案的挂载和卸载 nouser
auto
noauto
auto 等价于 mount -a,意思是将 /etc/fstab 里设定的全部重挂一遍 auto
sync
nosync
同步挂载还是异步挂载 async
atime
noatime
是否修改 atime,对于 nfs 而言,该选项是无效的,理由见下文
diratime
nodiratime
是否修改目录 atime,对于 nfs 而言,该挂载选项是无效的,理由见下文
remount 重新挂载

以下是针对 nfs 文件系统的挂载选项。其中没有给出关于缓存选项(ac/noac、cto/nocto、lookupcache)的说明,它们可以直接采用默认值,如果想要了解缓存相关内容,可以查看 man nfs。

选项 功能 默认值
fg
bg
挂载失败后 mount 命令的行为。默认为 fg,表示挂载失败时将直接报错退出。
如果是 bg,挂载失败后会创建一个子进程不断在后台挂载,而父进程 mount 自身则立即退出并返回 0 状态码。
fg
timeo NFS 客户端等待下一次重发 NFS 请求的时间间隔,单位为十分之一秒。
基于 TCP 的 NFS 的默认 timeo 的值为 600(60秒)。
hard
soft
决定 NFS 客户端当 NFS 请求超时时的恢复行为方式。如果是 hard,将无限重新发送 NFS 请求。
例如在客户端使用 df -h 查看文件系统时就会不断等待。
设置 soft,当 retrans 次数耗尽时,NFS 客户端将认为 NFS 请求失败,从而使得 NFS 客户端返回一个错误给调用它的程序。
hard
retrans NFS 客户端最多发送的请求次数,次数耗尽后将报错表示连接失败。如果 hard 挂载选项生效,则会进一步尝试恢复连接。 3
rsize
wsize
一次读出(rsize)和写入(wsize)的区块大小。如果网络带宽大,这两个值设置大一点能提升传输能力。最好设置到带宽的临界值。
单位为字节,大小只能为 1024 的倍数,且最大只能设置为 1M。

注意三点:

  1. 所谓的 soft 在特定的环境下超时后会导致静态数据中断。因此,仅当客户端响应速度比数据完整性更重要时才使用 soft 选项。

    使用基于 TCP 的 NFS(除非显示指定使用 UDP,否则现在总是默认使用 TCP)或增加 retrans 重试次数可以降低使用 soft 选项带来的风险。

    如果真的出现 NFS 服务端下线,导致 NFS 客户端无限等待的情况,可以强制将 NFS 文件系统卸载,卸载方法:

    umount -f -l MOUNT_POINT

    其中 "-f" 是强制卸载,"-l" 是 lazy umount,表示将该文件系统从当前目录树中剥离,让所有对该文件系统内的文件引用都强制失效。对于丢失了 NFS 服务端的文件系统,卸载时 "-l" 选项是必须的。

  2. 由于 nfs 的客户端挂载后会缓存文件的属性信息,其中包括各种文件时间戳,所以 mount 指定时间相关的挂载选项是没有意义的,它们不会有任何效果,包括 atime/noatime,diratime/nodiratime,relatime/norelatime 以及 strictatime/nostrictatime 等。具体可见 man nfs 中 "DATA AND METADATA COHERENCE" 段的 "File timestamp maintainence" 说明。

  3. 如果是要开机挂载 NFS 文件系统,方式自然是写入到 /etc/fstab 文件或将 mount 命令放入 rc.local 文件中。

    如果是将 /etc/fstab 中,那么在系统环境初始化(exec /etc/rc.d/rc.sysinit)的时候会加载 fstab 中的内容,如果挂载 fstab 中的文件系统出错,则会导致系统环境初始化失败,结果是系统开机失败。

    所以,要开机挂载 nfs 文件系统,则需要在 /etc/fstab 中加入一个挂载选项 "_rnetdev""_netdev"(centos 7 中已经没有 "_rnetdev"),防止无法联系 nfs 服务端时导致开机启动失败。例如:

    10.1.1.2:/www    /mnt    nfs    defaults,_rnetdev    0    0

当导出目录后,将在 /var/lib/nfs/etab 文件中写入一条对应的导出记录,这是 nfs 维护的导出表,该表的内容会交给 rpc.mountd 进程,并在必要的时候(mountd 接受到客户端的 mount 请求时),将此导出表中的内容加载到内核中,内核也单独维护一张导出表。

3.3.3、nfs 伪文件系统

nfs pseudo filesystem

服务端导出 /vol/vol0、/vol/vol2 和 /backup/archive 后,其中 vol0 和 vol2 是连在一个目录下的,但它们和 archive 目录没有连在一起,nfs 采用伪文件系统的方式来桥接这些不连接的导出目录。桥接的方式是创建那些未导出的连接目录,如伪 vol 目录,伪 backup 目录以及顶级的伪根。

当客户端挂载后,每次访问导出目录时,其实都是通过找到伪文件系统(文件系统都有 id,在 nfs 上伪文件系统的 id 称为 fsid)并定位到导出目录的。

3.4、showmount 命令

使用 showmount 命令可以查看某一台主机的导出目录情况。因为涉及到 rpc 请求,所以如果 rpc 出问题,showmount 一样会傻傻地等待。

主要有 3 个选项:

showmount [ -ade]  host
-a:以host:dir格式列出客户端名称/IP以及所挂载的目录。但注意该选项是读取NFS服务端/var/lib/nfs/rmtab文件,
  :而该文件很多时候并不准确,所以showmount -a的输出信息很可能并非准确无误的
-e:显示NFS服务端所有导出列表。
-d:仅列出已被客户端挂载的导出目录。

另外 showmount 的结果是排序过的,所以和实际的导出目录顺序可能并不一致。

例如:

[root@arm64v8 ~]# showmount -e
Export list for arm64v8:
/backup/archive *
/vol/vol2       *
/vol/vol0       *
[root@arm64v8 ~]#

3.5、nfs 身份映射

NFS 的目的是导出目录给各客户端,因此导出目录中的文件在服务端和客户端上必然有两套属性、权限集。

  • 例如,服务端导出目录中某 a 文件的所有者和所属组都为 A,但在客户端上不存在 A,那么在客户端上如何显示 a 文件的所有者等属性?

  • 例如,在客户端上,以用户 B 在导出目录中创建了一个文件 b,如果服务端上没有用户 B,在服务端上该如何决定文件 b 的所有者等属性?

NFS 采用 uid/gid <==> username/groupname 映射的方式解决客户端和服务端两套属性问题。由于服务端只能控制它自己一端的身份映射,所以客户端也同样需要身份映射组件。也就是说,服务端和客户端两端都需要对导出的所有文件的所有者和所属组进行映射。

注意:服务端的身份映射组件为 rpc.idmapd,它以守护进程方式工作。而客户端使用 nfsidmap 工具进行身份映射。

服务端映射时以 uid/gid 为基准,意味着客户端以身份 B(假设对应 uid=Xb,gid=Yb) 创建的文件或修改了文件的所有者属性时,在服务端将从 /etc/passwd(此处不考虑其他用户验证方式)文件中搜索 uid=Xb,gid=Yb 的用户,如果能搜索到,则设置该文件的所有者和所属组为此 uid/gid 对应的 username/groupname,如果搜索不到,则文件所有者和所属组直接显示为 uid/gid 的值。

客户端映射时以 username/groupname 为基准,意味着服务端上文件所有者为 A 时,则在客户端上搜索 A 用户名,如果搜索到,则文件所有者显示为 A,否则都将显示为 nobody。注意,客户端不涉及任何 uid/gid 转换翻译过程,即使客户端上 A 用户的 uid 和服务端上 A 用户的 uid 不同,也仍显示为用户 A。也就是说,客户端上文件所有者只有两种结果,要么和服务端用户同名,要么显示为 nobody。

综上考虑,强烈建议客户端和服务端的用户身份要统一,且尽量让各 uid、gid 能对应上。

3.6、使用 exportfs 命令导出目录

除了启动 nfs 服务加载配置文件 /etc/exports 来导出目录,使用 exportfs 命令也可以直接导出目录,它无需加载配置文件 /etc/exports,当然 exportfs 也可以加载 /etc/exports 文件来导出目录。实际上,nfs 服务启动脚本中就是使用 exportfs 命令来导出 /etc/exports 中内容的。

[root@arm64v8 ~]# grep exportfs /usr/lib/systemd/system/nfs.service 
ExecStartPre=-/usr/sbin/exportfs -r
ExecStopPost=/usr/sbin/exportfs -au
ExecStopPost=/usr/sbin/exportfs -f
ExecReload=-/usr/sbin/exportfs -r
[root@arm64v8 ~]#

当然,无论如何,nfsd 等守护进程是必须已经运行好的。

以下是 CentOS 7 上 exportfs 命令的用法。

-a     导出或卸载所有目录。
-o options,...
       指定一系列导出选项(如rw,async,root_squash),这些导出选项在exports(5)的man文档中有记录。
-i     忽略/etc/exports和/etc/exports.d目录下文件。此时只有命令行中给定选项和默认选项会生效。
-r     重新导出所有目录,并同步修改/var/lib/nfs/etab文件中关于/etc/exports和/etc/exports.d/
       *.exports的信息(即还会重新导出/etc/exports和/etc/exports.d/*等导出配置文件中的项)。该
       选项会移除/var/lib/nfs/etab中已经被删除和无效的导出项。
-u     卸载(即不再导出)一个或多个导出目录。
-f     如果/prof/fs/nfsd或/proc/fs/nfs已被挂载,即工作在新模式下,该选项将清空内核中导出表中
       的所有导出项。客户端下一次请求挂载导出项时会通过rpc.mountd将其添加到内核的导出表中。
-v     输出详细信息。
-s     显示适用于/etc/exports的当前导出目录列表。
  1. 导出 /www 目录给客户端 10.1.1.3。

    [root@arm64v8 ~]# exportfs 10.1.1.3:/www
    [root@arm64v8 ~]# showmount -e
    Export list for arm64v8:
    /backup/archive *
    /vol/vol2       *
    /vol/vol0       *
    /www            10.1.1.3
  2. 导出 /www 目录给所有人,并指定导出选项。

    [root@arm64v8 ~]# exportfs :/www -o rw,no_root_squash
    [root@arm64v8 ~]# showmount -e
    Export list for arm64v8:
    /backup/archive *
    /vol/vol2       *
    /vol/vol0       *
    /www            (everyone)
    [root@arm64v8 ~]#
  3. 导出 exports 文件中的内容。

    [root@arm64v8 ~]# exportfs -a
  4. 重新导出所有已导出的目录。包括 exports 文件中和 exportfs 单独导出的目录。

    [root@arm64v8 ~]# exportfs -ar
  5. 卸载所有已导出的目录,包括 exports 文件中的内容和 exportfs 单独导出的内容。即其本质为清空内核维护的导出表。

    [root@arm64v8 ~]# exportfs -au
    [root@arm64v8 ~]# showmount -e
    Export list for arm64v8:
    [root@arm64v8 ~]#
  6. 只卸载某一个导出目录。

    [root@arm64v8 ~]# exportfs -u 10.1.1.3:/www

3.7、rpcdebug 命令

在很多时候 NFS 客户端或者服务端出现异常,例如连接不上、锁状态丢失、连接非常慢等等问题,都可以对 NFS 进行调试来发现问题出在哪个环节。

NFS 有不少进程都可以直接支持调试选项,但最直接的调试方式是调试 rpc,因为 NFS 的每个请求和响应都会经过 RPC 去封装。但显然,调试 RPC 比直接调试 NFS 时更难分析出问题所在。以下只介绍如何调试 RPC。

rpc 单独提供一个调试工具 rpcdebug。

[root@arm64v8 ~]# rpcdebug -vh
usage: rpcdebug [-v] [-h] [-m module] [-s flags...|-c flags...]
       set or cancel debug flags.

Module     Valid flags
rpc        xprt call debug nfs auth bind sched trans svcsock svcdsp misc cache all
nfs        vfs dircache lookupcache pagecache proc xdr file root callback client mount fscache pnfs pnfs_ld state all
nfsd       sock fh export svc proc fileop auth repcache xdr lockd all
nlm        svc client clntlock svclock monitor clntsubs svcsubs hostcache xdr all
[root@arm64v8 ~]#
选项说明:

-v:显示更详细信息
-h:显示帮助信息
-m:指定调试模块,有rpc/nfs/nfsd/nlm共4个模块可调试。
  :顾名思义,调试rpc模块就是直接调试rpc的问题,将记录rpc相关的日志信息;
  :调试nfs是调试nfs客户端的问题,将记录nfs客户端随之产生的日志信息;
  :nfsd是调试nfs服务端问题,将记录nfsd随之产生的日志信息;
  :nlm是调试nfs锁管理器相关问题,将只记录锁相关信息
-s:指定调试的修饰符,每个模块都有不同的修饰符,见上面的usage中"Valid flags"列的信息
-c:清除或清空已设置的调试flage

例如设置调试 nfs 客户端的信息。

[root@arm64v8 ~]# rpcdebug -m nfs -s all
nfs        vfs dircache lookupcache pagecache proc xdr file root callback client mount fscache pnfs pnfs_ld state
[root@arm64v8 ~]#
  • 当有信息出现时,将记录到 syslog 中。
标签云