Search code examples
linuxfreebsdnfslocking

Unable to flock as nonroot user


My environment is a FreeBSD 12 server running nfs. The clients I have tried include a CentOS 7 and Artix Linux.

When I try to flock a file as a normal user, the flock syscall fails with ENOLCK. When I try to flock as root however, it succeeds and behaves as expected. That is, if I flock the same file from two clients, the second client will block until the first client releases the lock.

Interestingly the locking does work when the client is another FreeBSD 12 installation.

EDIT: Here's an example:

user@client$ flock /projects/testfile ls
flock: /projects/testfile: No locks available

Here's the strace:

execve("/usr/bin/flock", ["flock", "/projects/testfile", "ls"], 0x7ffe68f60370 /* 34 vars */) = 0
brk(NULL)                               = 0x560012532000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffc4bd04660) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/haswell/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/haswell/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/haswell/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/haswell", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/tls", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/haswell/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/haswell/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/haswell/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/haswell", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/mpi/openmpi/lib", {st_mode=S_IFDIR|0775, st_size=1454, ...}) = 0
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/tls/haswell/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/tls/haswell/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/tls/haswell/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/tls/haswell", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/tls/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/tls/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/tls/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/tls", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/haswell/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/haswell/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/haswell/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/haswell", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib/x86_64", 0x7ffc4bd038a0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/pgi/linux86-64/18.4/lib", {st_mode=S_IFDIR|0755, st_size=3480, ...}) = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=259146, ...}) = 0
mmap(NULL, 259146, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff2a1391000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0  \0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=35096, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff2a138f000
mmap(NULL, 39416, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff2a1385000
mmap(0x7ff2a1387000, 16384, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7ff2a1387000
mmap(0x7ff2a138b000, 8192, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7ff2a138b000
mmap(0x7ff2a138d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7ff2a138d000
close(3)                                = 0
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360=\2\0\0\0\0\0"..., 832) = 832
lseek(3, 792, SEEK_SET)                 = 792
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\37\245\323=\353Gzs\267\5\27\265R\0\7U"..., 68) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2141696, ...}) = 0
lseek(3, 792, SEEK_SET)                 = 792
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\37\245\323=\353Gzs\267\5\27\265R\0\7U"..., 68) = 68
lseek(3, 864, SEEK_SET)                 = 864
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 1852992, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff2a11c0000
mprotect(0x7ff2a11e2000, 1675264, PROT_NONE) = 0
mmap(0x7ff2a11e2000, 1359872, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7ff2a11e2000
mmap(0x7ff2a132e000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16e000) = 0x7ff2a132e000
mmap(0x7ff2a137b000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7ff2a137b000
mmap(0x7ff2a1381000, 13888, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff2a1381000
close(3)                                = 0
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/mpi/openmpi/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/opt/pgi/linux86-64/18.4/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340f\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=155600, ...}) = 0
lseek(3, 808, SEEK_SET)                 = 808
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 131528, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff2a119f000
mmap(0x7ff2a11a5000, 61440, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7ff2a11a5000
mmap(0x7ff2a11b4000, 24576, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7ff2a11b4000
mmap(0x7ff2a11ba000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0x7ff2a11ba000
mmap(0x7ff2a11bc000, 12744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff2a11bc000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff2a119c000
arch_prctl(ARCH_SET_FS, 0x7ff2a119c740) = 0
mprotect(0x7ff2a137b000, 16384, PROT_READ) = 0
mprotect(0x7ff2a11ba000, 4096, PROT_READ) = 0
mprotect(0x7ff2a138d000, 4096, PROT_READ) = 0
mprotect(0x56001243e000, 4096, PROT_READ) = 0
mprotect(0x7ff2a13fb000, 4096, PROT_READ) = 0
munmap(0x7ff2a1391000, 259146)          = 0
set_tid_address(0x7ff2a119ca10)         = 5376
set_robust_list(0x7ff2a119ca20, 24)     = 0
rt_sigaction(SIGRTMIN, {sa_handler=0x7ff2a11a5130, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7ff2a11b14d0}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {sa_handler=0x7ff2a11a51d0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7ff2a11b14d0}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
brk(NULL)                               = 0x560012532000
brk(0x560012553000)                     = 0x560012553000
openat(AT_FDCWD, "/projects/testfile", O_RDONLY|O_CREAT|O_NOCTTY, 0666) = 3
flock(3, LOCK_EX)                       = -1 ENOLCK (No locks available)
write(2, "flock: ", 7flock: )                  = 7
write(2, "/projects/testfile", 18/projects/testfile)      = 18
write(2, ": No locks available\n", 21: No locks available
)  = 21
close(1)                                = 0
close(2)                                = 0
exit_group(71)                          = ?
+++ exited with 71 +++

Here's it working as root:

On client one I try locking the file (vim is just so I can control when to unlock easily by quitting):

root@client1$ flock /projects/testfile vim

Client one gets the lock. successfully and vim starts. On client two I then do the same:

root@client2$ flock /projects/testfile vim

Client two blocks until I close vim on client one.


Solution

  • It turns out I made a stupid mistake. The file was owned by root. My test file had gotten deleted at some point (it was already out there for a separate locking issue) and I must have recreated it as root without thinking.

    Normal users can't lock a file for which they don't have permission.