Skip to content

LTlock fails on btrfs #152

Open
Open

Description

@nckx

Hi!

The following test failure happens only when building on btrfs. Since everyone can easily reproduce that, and I'm clueless about lsof internals, I'll just leave this here:

Optional tests:
LTbigf ... OK
LTdnlc ... /tmp/guix-build-lsof-4.94.0.drv-0/lsof-4.94.0-checkout/tests found: 100.00%
           OK
LTlock ... lock mismatch: expected W, got " "
           lock mismatch: expected R, got " "
           lock mismatch: expected w, got " "
           lock mismatch: expected r, got " "
Failed tests: 1

make: *** [Makefile:118: opt] Error 1
command "make" "standard" "optional" failed with status 2

Activity

  1. masatake commented on Mar 21, 2021

    @masatake
    Contributor

    Which distribution do you use?

  2. nckx commented on Mar 21, 2021

    @nckx
    ContributorAuthor

    The bug isn't distribution-specific, but I use & first encountered it on Guix System.

  3. masatake commented on Mar 21, 2021

    @masatake
    Contributor

    The bug isn't distribution-specific, but I use & first encountered it on Guix System.

    Thank you. I was confused with btrfs with zfs.
    I will inspect this issue.

  4. self-assigned this
    on Mar 21, 2021
  5. masatake commented on Mar 21, 2021

    @masatake
    Contributor

    Do you use btfs as your root file system?
    I would like to know the detail of the way to reproduce.

  6. nckx commented on Mar 21, 2021

    @nckx
    ContributorAuthor

    Do you use btfs as your root file system?

    Yes.

    I would like to know the detail of the way to reproduce.

    Sure! But note that / or not doesn't matter: simply create any btrfs file system and unpack & build lsof on it. Something like:

    dd if=/dev/zero of=/tmp/img bs=1M count=512
    mkfs.btrfs /tmp/img
    mount -o loop /tmp/img /mnt
    cd /mnt
    git clone https://github.com/lsof-org/lsof
    cd lsof
    ./Configure linux
    make
    cd tests
    make opt
    # LTlock should fail with the message above
    
  7. nckx commented on Mar 21, 2021

    @nckx
    ContributorAuthor

    By the way, @masatake, the above is from memory, and was tried on an Ubuntu box (just to make sure the distro really doesn't matter after telling you it shouldn't 😉 ).

    I don't have access to it now but if you still can't reproduce it, I can copy/paste my exact bash history tomorrow. It will be almost identical to what I wrote.

    Thanks for responding so promptly!

  8. nckx commented on Mar 21, 2021

    @nckx
    ContributorAuthor

    This report is about something else, but seems to exhibit the same failure: #61

  9. masatake commented on Jun 20, 2021

    @masatake
    Contributor

    I found strange things about device minor number(s).

    findmnt reports the minor number of mount point of btrfs is 67.
    stat reports the minor number of a file under the mount point of btrfs is 68.
    /proc/locks says the minor number of a locked file under the mount point of btrfs is 0x43 (== 67).

    I guess lsof is confused with the mismatch of numbers.

    [jet@living]/mnt% findmnt  -oTARGET,SOURCE,FSTYPE,MAJ:MIN /mnt
    findmnt  -oTARGET,SOURCE,FSTYPE,MAJ:MIN /mnt
    TARGET SOURCE     FSTYPE MAJ:MIN
    /mnt   /dev/loop1 btrfs    0:67 
    [jet@living]/mnt% stat /mnt/ /mnt/lsof/
    stat /mnt/ /mnt/lsof/
      File: /mnt/
      Size: 8         	Blocks: 32         IO Block: 4096   directory
    Device: 44h/68d	Inode: 256         Links: 1
    Access: (0777/drwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
    Context: system_u:object_r:unlabeled_t:s0
    Access: 2021-06-21 05:56:49.675987656 +0900
    Modify: 2021-06-21 05:56:24.801910504 +0900
    Change: 2021-06-21 05:56:24.801910504 +0900
     Birth: 2021-06-21 05:56:24.000000000 +0900
      File: /mnt/lsof/
      Size: 1196      	Blocks: 0          IO Block: 4096   directory
    Device: 44h/68d	Inode: 257         Links: 1
    Access: (0755/drwxr-xr-x)  Uid: ( 1000/     jet)   Gid: ( 1000/     jet)
    Context: unconfined_u:object_r:unlabeled_t:s0
    Access: 2021-06-21 06:27:15.316102351 +0900
    Modify: 2021-06-21 06:27:12.934091866 +0900
    Change: 2021-06-21 06:27:12.934091866 +0900
     Birth: 2021-06-21 05:56:24.801910504 +0900
    object_r:unlabeled_t:s0
    Access: 2021-06-21 06:25:43.109696511 +0900
    Modify: 2021-06-21 06:25:43.109696511 +0900
    Change: 2021-06-21 06:25:43.109696511 +0900
     Birth: 2021-06-21 06:25:43.109696511 +0900
    [jet@living]/mnt% stat /mnt/lsof/tests/config.LTlock2630449 
    stat /mnt/lsof/tests/config.LTlock2630449 
      File: /mnt/lsof/tests/config.LTlock2630449
      Size: 2048      	Blocks: 8          IO Block: 4096   regular file
    Device: 44h/68d	Inode: 842         Links: 1
    Access: (0600/-rw-------)  Uid: ( 1000/     jet)   Gid: ( 1000/     jet)
    Context: unconfined_u:object_r:unlabeled_t:s0
    Access: 2021-06-21 06:25:43.109696511 +0900
    Modify: 2021-06-21 06:25:43.109696511 +0900
    Change: 2021-06-21 06:25:43.109696511 +0900
     Birth: 2021-06-21 06:25:43.109696511 +0900
    [jet@living]/mnt% grep 842 /proc/locks 
    grep 842 /proc/locks 
    17: POSIX  ADVISORY  WRITE 2630449 00:43:842 0 EOF
    
  10. masatake commented on Jun 20, 2021

    @masatake
    Contributor

    I guess this is something to do with the subvolume feature of btrfs.

  11. masatake commented on Jun 20, 2021

    @masatake
    Contributor

    As the test case shows lsof cannot report the lock information (RW) for a locked file on btrfs correctly.

  12. masatake commented on Jun 21, 2021

    @masatake
    Contributor
  13. removed their assignment
    on Sep 17, 2022
  14. hugojosealmeida commented on Oct 30, 2026

    @hugojosealmeida
    Contributor

    Hey, I just found this issue in a context of LTlock failure in circleci job, and I have reproduced this in a Ubuntu 22.04 container.
    A direct check confirms the cause: for a locked file on btrfs, /proc/locks reports device 00:3d while stat reports st_dev 0x3e (one greater); lsof's FD column therefore lacks the lock character (3u instead of 3uW).

    Now I am curious about if this is same failure as per #374 (comment) (to be checked later!)

    This is only an hypothesis, see as follow:

    In lib/dialects/linux/dnode.c, get_locks() parses /proc/locks and keys each lock on (pid, dev, inode), where dev comes from the MAJOR:MINOR field. check_lock() then compares that lp->dev against Lf->dev, which is stat(2)'s st_dev. On most filesystems these agree, but btrfs uses an anonymous superblock whose st_dev is one greater than the device number reported in /proc/locks (an inode-257 file reports 00:3d in /proc/locks but st_dev 0x3e). The mismatch means check_lock() never assigns Lf->lock, leaving it as a space. The smallest plausible fix is to normalize the comparison in check_lock() (or the device stored in get_locks()) so that a btrfs /proc/locks device one less than Lf->dev is treated as the same file, ideally guarded by a btrfs mount/filesystem check to avoid false matches.

    I have done a local change that normalizes the device comparison in check_lock() for btrfs. On btrfs, /proc/locks reports a device number one less than stat(2)'s st_dev, so Lf->dev == lp->dev never matched. The comparison now also accepts Lf->dev == lp->dev + 1 when the file resides on a btrfs mount.

    Basically:

    • lib/dialects/linux/dlsof.h: added int is_btrfs to struct mounts.
    • lib/dialects/linux/dmnt.c: set mp->is_btrfs from the /proc/mounts filesystem type.
    • lib/dialects/linux/dnode.c: added btrfs_dev() guard and updated check_lock().

    and the LTlock on btrfs is OK

    I suppose this includes some risks as:

    • it assumes btrfs always reports the /proc/locks device as exactly one less than st_dev. A kernel/btrfs change could break this again.
    • It uses whole dev_t + 1 arithmetic; an unusual minor-number boundary could theoretically not map to the same major/minor pair.
    • btrfs_dev() relies on the cached mount table from readmnt(), so mount changes after the first read may be stale.
    • The normalization is intentionally limited to btrfs, so other filesystems with a similar off-by-one device discrepancy remain unfixed.
    • My tests covers LTlock on btrfs, ext4, and overlay, but not all btrfs configurations (subvolumes, multiple btrfs mounts, different kernels).

    This activity is AI Assisted.

  15. hugojosealmeida commented on Nov 3, 2026

    @hugojosealmeida
    Contributor

    I have done some investigation to confirm that it is a genuine lock-reporting bug on Btrfs. The code matches locks using PID, device number and inode. However, Btrfs can report different device numbers through  stat()  and  /proc/locks , causing lsof to omit the lock indicator even when the file is locked.

    I did some changes, Linux-only fix in  dproc.c , without touching the existing lock parser. When the original lookup misses, lsof uses the  lock:  records from  /proc/PID/fdinfo/FD . These records are associated with the specific open descriptor, so no device-number comparison or arithmetic workaround is needed.

    I have done some verification on Btrfs to confirm that the (original) code missed all four lock indicators ( W ,  R ,  w ,  r ), while my changes reported them correctly. Some snapshot tests also confirmed that an unlocked file with the same inode number in another subvolume remained unlocked. Ext4 and targeted compatibility tests passed.

    I also ran the full Linux (docker) and native macOS suites. The lock regression passed, but the suites were not entirely green by now. Need to check further.

  16. hugojosealmeida commented on Nov 3, 2026

    @hugojosealmeida
    Contributor

    @jiegec Could you have a look to the previous comment?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions