![fcntl 无法锁定 /dev/null 并挂起](https://linux22.com/image/1165206/fcntl%20%E6%97%A0%E6%B3%95%E9%94%81%E5%AE%9A%20%2Fdev%2Fnull%20%E5%B9%B6%E6%8C%82%E8%B5%B7.png)
这是一个最小的工作示例,但仅适用于我的机器:
int main(int argc, char* argv[]) {
int fd = open ("/dev/null", O_RDWR|O_CREAT);
if (fd < 0) {
printf("Failed to open file\n");
}
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
int res = fcntl(fd, F_SETLKW,&lock); // this hangs
if (res < 0) {
printf("Failed to lock\n");
}
close (fd);
return (0);
}
上面的程序只在我的计算机上挂起,并在其他 7 台机器上立即完成。我可以查看什么来调查此问题?
斯特拉斯显示当程序 (./t) 被 ^C 杀死时 fcntl 卡住了。
5249 execve("./t", ["./t"], [/* 23 vars */]) = 0
5249 brk(NULL) = 0x1cf6000
5249 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
5249 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
5249 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
5249 fstat(3, {st_mode=S_IFREG|0644, st_size=98358, ...}) = 0
5249 mmap(NULL, 98358, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f31a1118000
5249 close(3) = 0
5249 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
5249 open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
5249 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
5249 fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, ...}) = 0
5249 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f31a1117000
5249 mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f31a0b42000
5249 mprotect(0x7f31a0d02000, 2097152, PROT_NONE) = 0
5249 mmap(0x7f31a0f02000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7f31a0f02000
5249 mmap(0x7f31a0f08000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f31a0f08000
5249 close(3) = 0
5249 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f31a1116000
5249 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f31a1115000
5249 arch_prctl(ARCH_SET_FS, 0x7f31a1116700) = 0
5249 mprotect(0x7f31a0f02000, 16384, PROT_READ) = 0
5249 mprotect(0x600000, 4096, PROT_READ) = 0
5249 mprotect(0x7f31a1131000, 4096, PROT_READ) = 0
5249 munmap(0x7f31a1118000, 98358) = 0
5249 open("/dev/null", O_RDWR|O_CREAT, 03777762203636510) = 3
5249 fcntl(3, F_SETLKW, {l_type=F_WRLCK, l_whence=SEEK_SET, l_start=0, l_len=0}) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
5249 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
5249 +++ killed by SIGINT +++
答案1
我正在回答我自己的问题。@steeldriver 的评论非常有用,它帮助我了解了问题所在。
你要求 fnctl 获取独占(写)锁
l_type=F_WRLCK
,其中(根据man fnctl
)F_SETLKW
表示“...但如果文件上有冲突的锁,则等待该锁被释放”。你也许能够看到为什么存在冲突的锁lslocks
- 请参阅如何列出锁定文件的进程fnctl
?。如果发生冲突时您不想等待,请尝试F_SETLK
代替F_SETLKW
。无论如何,@vidarlo 的观点适用 - 写锁定似乎不是一个好主意/dev/null
。
对于那些对这个问题感兴趣的人,我的机器上被 docker daemon 锁住了/dev/null
。更多信息可以在这里找到:
https://github.com/moby/moby/issues/31182
至于为什么我需要锁定/dev/null
,我有一个测试套件,它写入/dev/null
网络而不是写入网络。该测试套件是针对不同的组件的,由位于不同大陆的不同团队编写。所以我也不清楚 :)