fcntl 无法锁定 /dev/null 并挂起

fcntl 无法锁定 /dev/null 并挂起

这是一个最小的工作示例,但仅适用于我的机器:

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 fnctlF_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网络而不是写入网络。该测试套件是针对不同的组件的,由位于不同大陆的不同团队编写。所以我也不清楚 :)

相关内容