Skip to content
Go back

排查 `flock` 在 NFSv3 上报 `No locks available` 而在 NFSv4 正常的问题

Edit page

排查 flock 在 NFSv3 上报 No locks available 而在 NFSv4 正常的问题

最近在一套 NFS 挂载环境里,我们遇到了一个很容易误判的问题:客户端对挂载目录里的文件执行 flock 时,直接报 No locks available;但把挂载卸掉重挂之后,flock 又突然恢复正常。

这个现象第一眼很容易让人怀疑是“客户端偶发异常”或者“文件已经被别人锁住了”,但继续往下排查会发现,真正的根因既不是 flock 命令本身,也不是 local_lock=none 这个挂载参数,而是 NFSv3 锁依赖的服务端 rpc-statd / status 没有正常提供。更容易让人误判的是,后面那次“突然恢复”其实并不是原问题自己好了,而是客户端在未显式指定版本时自动挂成了 NFSv4,走了另一套锁模型。本文把这次排查过程整理下来。

背景

客户端把服务端 10.0.1.44:/zgq-storage/zgq-fastone 挂到本地 /fs,最初看到的挂载信息类似下面这样:

10.0.1.44:/zgq-storage/zgq-fastone on /fs type nfs (
rw,relatime,vers=3,...,local_lock=none,addr=10.0.1.44)

业务侧需要依赖 flock 做文件级互斥,所以当下面这条最基本的命令都失败时,问题就必须先查清楚:

sudo flock /fs/123 ls

故障现象

在 NFSv3 挂载下,flock 的报错非常直接:

flock: /fs/123: No locks available

这类报错有几个很容易让人误判的地方:

  1. 从字面看,容易被理解成“当前文件已经没有可用锁了”。
  2. 挂载参数里有 local_lock=none,容易进一步被理解成“是不是客户端禁用了锁”。
  3. 后面如果执行一次不带 vers=3 的重新挂载,又可能发现 flock 突然恢复正常,看起来像是“卸载重挂就好了”。

但这几个直觉解释,其实都不是最终根因。

排查过程

1. 先确认客户端锁服务是否正常

因为当前挂载是 NFSv3,所以第一步先检查客户端自己的 rpcbindrpc-statdnlockmgr

systemctl status rpcbind rpc-statd
rpcinfo -p localhost | egrep 'status|nlockmgr'

客户端输出显示:

也就是说,客户端本机这条锁调用链基本是完整的,问题更像是在服务端,或者在客户端到服务端之间的 RPC 锁链路上。

2. 检查服务端是否真的提供了 NFSv3 锁相关 RPC 程序

下一步从客户端检查服务端暴露的 RPC 程序:

rpcinfo -p 10.0.1.44 | egrep 'nfs|mountd|status|nlockmgr'

结果里可以看到:

为了避免只看列表误判,又直接做了一次点对点检查:

rpcinfo -T tcp 10.0.1.44 status

返回结果是:

rpcinfo: RPC: Program not registered

这一步非常关键。它说明服务端虽然提供了 nlockmgr,但并没有注册 status,也就是 rpc-statd / NSM 这条链路缺失

3. 回到服务端确认 rpc-statd 状态

登录到服务端后继续检查:

systemctl status rpcbind rpc-statd nfs-server
rpcinfo -p localhost | egrep 'nfs|mountd|status|nlockmgr'

服务端的实际状态是:

到这里,问题基本已经定位了:服务端的 NFSv3 锁服务链路不完整

4. 为什么重新挂载后 flock 又好了

这个问题最容易让人绕进去。

当时卸载后执行的是:

sudo umount -lf /fs
sudo mount 10.0.1.44:/zgq-storage/zgq-fastone /fs
sudo mount | grep ' /fs '

结果发现新的挂载信息已经变成:

10.0.1.44:/zgq-storage/zgq-fastone on /fs type nfs4 (
rw,relatime,vers=4.2,...,local_lock=none,addr=10.0.1.44)

这说明后面“恢复正常”的那次,根本不是还在测 NFSv3,而是自动协商成了 NFSv4.2

NFSv4 的文件锁是协议内建的,不再依赖 NFSv3 + nlockmgr + rpc-statd/status 这套旁路机制,所以 flock 自然就恢复正常了。

换句话说:

不是“卸载重挂修好了 NFSv3 锁”,而是“重新挂载后换成了 NFSv4,走了另一套锁模型”。

根因分析

1. local_lock=none 不是“禁用锁”

这次排查里,local_lock=none 很容易误导人。

它并不等价于“这个挂载点不能加锁”,而更接近:

所以在 NFSv4 挂载下,即使同样看到 local_lock=noneflock 仍然完全可以正常工作。

2. NFSv3 的锁并不只依赖 nlockmgr

如果只看服务端的 RPC 列表,看到 nlockmgr 已经在,很多人会下意识以为“那锁服务应该没问题”。

NFSv3 上的文件锁链路并不是只要 nlockmgr 就够了,它通常还依赖:

这也是为什么服务端明明能正常导出 NFS、客户端也能正常读写文件,但 flock 还是会报:

No locks available

也就是说,这里坏的不是 NFS 数据读写本身,而是 NFSv3 的锁服务链路

3. NFSv4 正常,并不代表 NFSv3 也没问题

这次故障的另一个迷惑点是:当客户端重新挂成 NFSv4.2 后,flock 立刻正常。

如果没有顺手检查 mount 输出,很容易得出错误结论:

看起来像是客户端偶发异常,重挂一下就好了。

但真实情况是:

所以“v4 正常”只能说明 当前挂载协议下锁功能可用,并不能反推 “v3 那条链路没有问题”。

解决方案

如果必须继续使用 NFSv3,修复方式就是把服务端缺失的 rpc-statd 补起来。

在服务端执行:

systemctl enable --now rpc-statd
systemctl restart nfs-server

然后验证:

rpcinfo -T tcp localhost status
rpcinfo -p localhost | egrep 'status|nlockmgr'

修复后可以看到:

program 100024 version 1 ready and waiting

并且 rpcinfo -p localhost 里也出现了 status

接着回到客户端再确认一次:

rpcinfo -T tcp 10.0.1.44 status

如果返回:

program 100024 version 1 ready and waiting

说明客户端已经能访问到服务端的 status 服务,NFSv3 锁链路里最关键的缺口已经补齐。

验证方式

1. 强制按 NFSv3 重新挂载再测

为了避免再次“误挂成 NFSv4”,建议显式指定版本重新测试:

sudo umount -lf /fs
sudo mount -t nfs -o vers=3,proto=tcp 10.0.1.44:/zgq-storage/zgq-fastone /fs
mount | grep ' /fs '

确认输出里明确包含:

然后再执行:

sudo flock /fs/222 ls

2. 做一次跨节点互斥验证

比起只在单机上试一条 flock,更稳妥的方式是做一次双客户端互斥测试。

在机器 A 上:

flock /fs/lock.test sleep 300

在机器 B 上:

flock -w 3 /fs/lock.test true && echo got || echo blocked

如果机器 B 在等待超时后拿不到锁,说明跨节点锁互斥是生效的。

3. 注意防火墙与动态端口

这次修复后,statusnlockmgr 使用的端口是动态分配的,例如:

所以如果服务端重启后仍然异常,还要继续检查:

这些端口在客户端与服务端之间是否可达。实际生产里,最好把相关 RPC 端口固定下来,避免动态漂移带来新的问题。

小结

这次故障最终可以归纳成三点:

  1. flock: No locks availableNFSv3 场景下,首先要怀疑的是 锁服务链路不完整,而不只是“文件被锁住了”。
  2. local_lock=none 并不等于“禁用文件锁”;真正的区别在于当前挂载到底是 NFSv3 还是 NFSv4
  3. 如果业务确实依赖 flock,优先使用 NFSv4 往往更省心;如果必须使用 NFSv3,那就必须同时保证 rpc-statd/statusnlockmgr 以及相关 RPC 端口都正常。

参考资料


Edit page
Share this post on:

Next Post
基于 `cturra/docker-ntp` 的 NTP 容器 `chronyd.pid` Permission Denied 问题排查与迁移方案