btrfs lockdep issue

Christian Borntraeger <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <[email protected]>
Chris,

in our CI we do get lockdep errors for btrfs:

======================================================
WARNING: possible circular locking dependency detected
7.2.0-20260712.rc2.git0.e3321fa3034d.300.fc44.s390x+debug #1 Not tainted
------------------------------------------------------
(udev-worker)/1653 is trying to acquire lock:
0000006919232220 (&type->i_mutex_dir_key#2){++++}-{3:3}, at: lookup_slow+0x3e/0x70
but task is already holding lock:
00000069238564d8 (&fs_devs->device_list_mutex){+.+.}-{3:3}, at: device_list_add.constprop.0+0x148/0xc60
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #5 (&fs_devs->device_list_mutex){+.+.}-{3:3}:
        lock_acquire+0x150/0x3f0
        __mutex_lock+0xba/0xdc0
        mutex_lock_nested+0x32/0x40
        write_all_supers+0x7a/0x670
        btrfs_sync_log+0xae6/0xdd0
        btrfs_sync_file+0x4fa/0x7a0
        __s390x_sys_fsync+0x52/0xa0
        __do_syscall+0x172/0x750
        system_call+0x72/0x90
-> #4 (&fs_info->tree_log_mutex){+.+.}-{3:3}:
        lock_acquire+0x150/0x3f0
        __mutex_lock+0xba/0xdc0
        mutex_lock_nested+0x32/0x40
        btrfs_sync_log+0xaba/0xdd0
        btrfs_sync_file+0x4fa/0x7a0
        __s390x_sys_fsync+0x52/0xa0
        __do_syscall+0x172/0x750
        system_call+0x72/0x90
-> #3 (btrfs_trans_num_extwriters){.+.+}-{0:0}:
        lock_acquire+0x150/0x3f0
        join_transaction+0x108/0x680
        start_transaction+0x21a/0x660
        btrfs_join_transaction+0x32/0x40
        btrfs_dirty_inode+0x52/0xf0
        touch_atime+0x90/0xc0
        filemap_read+0x446/0x450
        vfs_read+0x208/0x370
        ksys_read+0x88/0x120
        __do_syscall+0x172/0x750
        system_call+0x72/0x90
-> #2 (btrfs_trans_num_writers){.+.+}-{0:0}:
        reacquire_held_locks+0x14c/0x240
        __lock_release.isra.0+0xd8/0x380
        lock_release+0xf6/0x270
        percpu_up_read+0x28/0xf0
        __btrfs_end_transaction+0x178/0x1f0
        btrfs_dirty_inode+0x82/0xf0
        touch_atime+0x90/0xc0
        btrfs_file_mmap_prepare+0x8c/0xa0
        __mmap_region+0x214/0x780
        mmap_region+0x108/0x160
        do_mmap+0x402/0x5a0
        vm_mmap_pgoff+0x156/0x230
        ksys_mmap_pgoff+0x17e/0x220
        __s390x_sys_old_mmap+0xa8/0x140
        __do_syscall+0x172/0x750
        system_call+0x72/0x90
-> #1 (&mm->mmap_lock){++++}-{3:3}:
        lock_acquire+0x150/0x3f0
        __might_fault+0x7a/0xa0
        filldir64+0x11c/0x210
        offset_readdir+0x92/0x200
        iterate_dir+0xcc/0x2d0
        __do_sys_getdents64+0x7a/0x130
        __do_syscall+0x172/0x750
        system_call+0x72/0x90
-> #0 (&type->i_mutex_dir_key#2){++++}-{3:3}:
        check_prev_add+0x160/0xf40
        __lock_acquire+0x12aa/0x15a0
        lock_acquire+0x150/0x3f0
        down_read+0x5a/0x280
        lookup_slow+0x3e/0x70
        path_lookupat+0x1f0/0x370
        filename_lookup+0xce/0x1f0
        kern_path+0x48/0x70
        is_same_device+0x146/0x300
        device_list_add.constprop.0+0x1be/0xc60
        btrfs_scan_one_device+0x13a/0x2f0
        btrfs_control_ioctl+0x110/0x1e0
        __s390x_sys_ioctl+0xfa/0x130
        __do_syscall+0x172/0x750
        system_call+0x72/0x90
other info that might help us debug this:
Chain exists of:
   &type->i_mutex_dir_key#2 --> &fs_info->tree_log_mutex --> &fs_devs->device_list_mutex
  Possible unsafe locking scenario:
        CPU0                    CPU1
        ----                    ----
   lock(&fs_devs->device_list_mutex);
                                lock(&fs_info->tree_log_mutex);
                                lock(&fs_devs->device_list_mutex);
   rlock(&type->i_mutex_dir_key#2);
  *** DEADLOCK ***
2 locks held by (udev-worker)/1653:
  #0: 0000016c727051c8 (uuid_mutex){+.+.}-{3:3}, at: btrfs_control_ioctl+0x102/0x1e0
  #1: 00000069238564d8 (&fs_devs->device_list_mutex){+.+.}-{3:3}, at: device_list_add.constprop.0+0x148/0xc60
stack backtrace:
CPU: 2 UID: 0 PID: 1653 Comm: (udev-worker) Not tainted 7.2.0-20260712.rc2.git0.e3321fa3034d.300.fc44.s390x+debug #1 PREEMPT
Hardware name: IBM 3931 A01 701 (LPAR)
Call Trace:
  [<0000016c70680e3e>] dump_stack_lvl+0xae/0x108
  [<0000016c7078aa44>] print_circular_bug+0x1a4/0x230
  [<0000016c7078ac5c>] check_noncircular+0x18c/0x1b0
  [<0000016c7078c030>] check_prev_add+0x160/0xf40
  [<0000016c7078fbaa>] __lock_acquire+0x12aa/0x15a0
  [<0000016c7078fff0>] lock_acquire+0x150/0x3f0
  [<0000016c7180e2fa>] down_read+0x5a/0x280
  [<0000016c70b88dde>] lookup_slow+0x3e/0x70
  [<0000016c70b8f5d0>] path_lookupat+0x1f0/0x370
  [<0000016c70b900ae>] filename_lookup+0xce/0x1f0
  [<0000016c70b90218>] kern_path+0x48/0x70
  [<0000016c70f5b4a6>] is_same_device+0x146/0x300
  [<0000016c70f67cfe>] device_list_add.constprop.0+0x1be/0xc60
  [<0000016c70f688da>] btrfs_scan_one_device+0x13a/0x2f0
  [<0000016c70ed9cb0>] btrfs_control_ioctl+0x110/0x1e0
  [<0000016c70b97d0a>] __s390x_sys_ioctl+0xfa/0x130
  [<0000016c718004d2>] __do_syscall+0x172/0x750
  [<0000016c718155d2>] system_call+0x72/0x90



As I dont know the btrfs code, I fed this into the bob AI and it came
out with this.

---snip---
The issue occurs in device_list_add() when is_same_device() is called
while holding device_list_mutex. The is_same_device() function performs
kern_path() lookups which acquire directory inode locks (i_mutex_dir_key),
creating a potential deadlock scenario.

The lockdep chain:
   CPU0: holds device_list_mutex, tries to acquire i_mutex_dir_key
   CPU1: holds tree_log_mutex, tries to acquire device_list_mutex
   (tree_log_mutex -> i_mutex_dir_key dependency exists via fsync path)
---snip---

and proposes
---snip---
Replace the is_same_device() call with a direct comparison of dev_t
values (device->devt vs path_devt). This is sufficient to determine if
the device path refers to the same block device, and avoids the
problematic filesystem path lookup while holding the mutex.

The path_devt is already obtained earlier via lookup_bdev(), and
device->devt is set during device registration, making this comparison
both safe and more efficient than the original string-based path
comparison.


---
  fs/btrfs/volumes.c | 8 +++++++-
  1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 1234567890ab..abcdef123456 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -895,7 +895,13 @@ static noinline struct btrfs_device *device_list_add(const char *path,
  				MAJOR(path_devt), MINOR(path_devt),
  				current->comm, task_pid_nr(current));
  
-	} else if (!device->name || !is_same_device(device, path)) {
+	/*
+	 * Check if device path changed by comparing devt instead of calling
+	 * is_same_device() which does kern_path() lookups while holding
+	 * device_list_mutex, causing potential circular locking dependency
+	 * with i_mutex_dir_key.
+	 */
+	} else if (!device->name || device->devt != path_devt) {
  		const char *old_name;
  
  		/*
---snip---


So if you want to fix this yourself, go for it, if you think the fix proposal is fine
and want a proper patch, let me know and I will respin this properly myself (and I will
also add that to our CI first).

Christian
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.