Package: lsof
Version: 4.91+dfsg-1
Severity: normal

Dear Maintainer,

The output of lsof is misleading when it comes to "flock" and "OFD"
file locks on Linux.

Background: there are three types of advisory file locks in Linux:

- "flock" or "BSD" locks, which are created by the flock system call.
  These are associated with a particular *open file description*, so
  they are inherited by child processes.

- "fcntl" or "POSIX" locks, which are created by the fcntl system call
  with the F_SETLK or F_SETLKW option.  These are associated with a
  particular *process ID*, so they are not inherited by child
  processes.

- "OFD" locks, which are created by the fcntl system call with the
  F_OFD_SETLK or F_OFD_SETLKW option.  These are like flock locks in
  that they are associated with an open file description, but they are
  like fcntl locks in that they apply to a particular range of bytes.

The kernel reports all of these locks via /proc/locks, and lsof parses
that file and tries to indicate which processes are currently holding
locks on which files.

However, the information in /proc/locks is incomplete and in some
cases inaccurate: for flock and OFD locks, it tells you that *some
process* is holding a lock on the file, but it doesn't tell you which
one(s), since the lock may have been inherited across a fork.  The
proc(5) manpage states:

    Because OFD locks are not owned by a single process (since
    multiple processes may have file descriptors that refer to the
    same open file description), the value -1 is displayed in [the
    process ID field] for OFD locks.  (Before kernel 4.14, a bug meant
    that the PID of the process that initially acquired the lock was
    displayed instead of the value -1.)

The manpage doesn't mention that exactly the same "bug" also applies
to flock locks.

As far as I can see, this does appear to be a limitation of the
kernel: I don't know of any way that lsof could possibly figure out
which processes, or which file descriptors, are associated with a
particular lock.

So although I believe this is a bug in lsof, I don't think it is one
that lsof can fix by itself.

Nonetheless, it's a limitation that probably should be better
documented, and perhaps lsof's output could be improved to reflect
this uncertainty - for example, it could display a '?' in the lock
column to indicate "*some* process has a lock on this file; this
particular process might or might not."


Here is an example program:

#define _GNU_SOURCE
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
    int fd1, fd2, fd3, fd4, status;
    pid_t child;
    struct flock fl = { 0 };
    char cmd[100];

    fd1 = open("/tmp/file1", O_RDWR | O_CREAT, 0600);
    fd2 = open("/tmp/file1", O_RDWR | O_CREAT, 0600);
    fd3 = open("/tmp/file2", O_RDWR | O_CREAT, 0600);
    fd4 = open("/tmp/file2", O_RDWR | O_CREAT, 0600);
    if (fd1 < 0 || fd2 < 0 || fd3 < 0 || fd4 < 0)
        err(1, "open");

    if (flock(fd1, LOCK_SH))
        err(1, "flock");

    fl.l_type = F_WRLCK;
    if (fcntl(fd3, F_OFD_SETLKW, &fl))
        err(1, "fcntl");

    child = fork();
    if (child < 0)
        err(1, "fork");
    else if (child == 0) {
        snprintf(cmd, sizeof(cmd), "lsof -p %d,%d -a -d 3-99",
                 getppid(), getpid());
        system(cmd);
    }
    else {
        wait(&status);
    }
    return 0;
}

Running this program produces:

COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
a.out   5615 benjamin    3uR  REG   0,44        0 517883 /tmp/file1
a.out   5615 benjamin    4uR  REG   0,44        0 517883 /tmp/file1
a.out   5615 benjamin    5u   REG   0,44        0 517884 /tmp/file2
a.out   5615 benjamin    6u   REG   0,44        0 517884 /tmp/file2
a.out   5616 benjamin    3u   REG   0,44        0 517883 /tmp/file1
a.out   5616 benjamin    4u   REG   0,44        0 517883 /tmp/file1
a.out   5616 benjamin    5u   REG   0,44        0 517884 /tmp/file2
a.out   5616 benjamin    6u   REG   0,44        0 517884 /tmp/file2

The flock lock is indicated (with an "R") for the parent process, but
not for the child process; the OFD lock is not indicated at all.  (If
you run the same program on an older kernel, it will show a "W" in the
fourth and fifth lines.)

To be *really* precise, file descriptors 3 and 5 are the ones holding
the locks; those FDs should have an "R" or "W" next to them while 4
and 6 shouldn't.


-- System Information:
Debian Release: 10.2
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable-debug'), (500, 'stable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.19.0-6-amd64 (SMP w/40 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages lsof depends on:
ii  libc6        2.28-10
ii  libselinux1  2.8-1+b1

lsof recommends no packages.

Versions of packages lsof suggests:
ii  perl  5.28.1-6

-- debconf-show failed

Reply via email to