lslocks是唯一能直接显示“哪个进程、持有什么类型锁、锁了哪段范围”的工具,它读取/proc/locks,支持flock和posix锁,需结合inode号精准匹配文件,输出含pid、type、mode及start–end范围。

怎么用 lslocks 查到文件锁的类型和持有者
lslocks 是唯一能直接告诉你“哪个进程、持有什么类型锁、锁了哪段范围”的工具。它读取内核的 /proc/locks,不依赖进程配合,对强制锁和建议性锁都有效(但注意:flock 锁在 lslocks 中显示为 FLOCK 类型,而 fcntl 锁显示为 POSIX)。
执行 lslocks | grep /path/to/file 通常查不到——因为 lslocks 默认输出的是挂载点路径或 inode 号匹配后的抽象路径,不是原始文件路径。正确做法是先获取目标文件 inode:
-
stat -c "%i" /path/to/file得到 inode 号 - 再查
lslocks | awk '$4 == "inode" && $5 == "123456" {print}'(把 123456 替换为实际 inode) - 或直接
lslocks --raw | grep "123456"
输出中重点关注:PID(持有者)、TYPE(FLOCK/POSIX)、MODE(READ/WRITE)、START–END(字节范围,全文件锁显示为 0–EOF)。
为什么 fuser -v 显示 “F” 却不能确认是写锁
fuser -v /path/to/file 输出里的 ACCESS 列中 F(大写)只表示“该进程打开了这个文件”,f(小写)才表示“以写模式打开”。但它完全不反映是否调用了 flock() 或 fcntl(F_SETLK) —— 也就是开了文件 ≠ 加了锁。
常见误判场景:
- 一个进程
open("/tmp/log", O_RDONLY)后没加锁,fuser仍显示F - 另一个进程用
flock(fd, LOCK_EX)加了独占锁,fuser也只显示F,无法区分 - 若进程已退出但文件描述符未关闭(比如子进程继承后没 close),
fuser仍会列出,但锁早已释放
所以 fuser 只适合快速定位“谁打开了这个文件”,不能替代锁状态判断。
如何从 /proc/pid/fdinfo/ 看到真实的 advisory 锁细节
Linux 2.6.22+ 内核中,每个打开的 fd 在 /proc/<pid>/fdinfo/<fd></fd></pid> 里会记录锁信息,这是目前最接近“进程级锁快照”的方式,但前提是你知道 PID。
操作步骤:
- 先用
lsof /path/to/file或sudo fuser -v /path/to/file拿到疑似持有锁的PID - 再查
ls -l /proc/<pid>/fd/</pid>找到对应 fd 编号(比如9) - 然后看
cat /proc/<pid>/fdinfo/9</pid>,搜索pos:下方是否有flags:行带lock字样;更关键的是找lock:开头的行(如lock: FLOCK EXCLUSIVE或lock: POSIX WRITE 0–EOF)
注意:fdinfo 不显示被阻塞的锁请求,只显示当前已生效的锁;且普通用户无权读其他用户的 /proc/<pid>/fdinfo/</pid>,必须用 sudo。
lsof 的 LOCK 列到底靠不靠谱
lsof /path/to/file 输出中有一列叫 LOCK,值可能是 N(no lock)、R(read lock)、W(write lock)。但这列信息来源不稳定:
- 它依赖内核是否向
lsof提供了锁元数据,不同内核版本差异大 - 对
flock()锁支持较好,但对fcntl字节范围锁常显示N即使锁已存在 - 某些发行版编译的
lsof默认不启用锁检测(需加-K参数,但很多系统没开)
所以除非你明确知道本地 lsof 编译时启用了锁支持且内核版本 ≥ 4.18,否则别信 LOCK 列。更稳妥的做法是:用 lslocks 看内核锁表 + /proc/pid/fdinfo 做交叉验证。
真正难的不是查锁,而是理解锁的语义边界:advisory lock 不阻塞 open/write 等系统调用,只对同样调用 flock() 或 fcntl() 的进程起作用。看到一个进程“开着文件”,不等于它“锁着文件”;看到 lslocks 里没条目,也不代表没人正在写——可能只是没加锁而已。











