OrangePi_CM5/fs/btrfs
Anand Jain aa1af89a66 btrfs: fix lockdep warning while mounting sprout fs
[ Upstream commit c124706900c20dee70f921bb3a90492431561a0a ]

Following test case reproduces lockdep warning.

  Test case:

  $ mkfs.btrfs -f <dev1>
  $ btrfstune -S 1 <dev1>
  $ mount <dev1> <mnt>
  $ btrfs device add <dev2> <mnt> -f
  $ umount <mnt>
  $ mount <dev2> <mnt>
  $ umount <mnt>

The warning claims a possible ABBA deadlock between the threads
initiated by [#1] btrfs device add and [#0] the mount.

  [ 540.743122] WARNING: possible circular locking dependency detected
  [ 540.743129] 5.11.0-rc7+ #5 Not tainted
  [ 540.743135] ------------------------------------------------------
  [ 540.743142] mount/2515 is trying to acquire lock:
  [ 540.743149] ffffa0c5544c2ce0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: clone_fs_devices+0x6d/0x210 [btrfs]
  [ 540.743458] but task is already holding lock:
  [ 540.743461] ffffa0c54a7932b8 (btrfs-chunk-00){++++}-{4:4}, at: __btrfs_tree_read_lock+0x32/0x200 [btrfs]
  [ 540.743541] which lock already depends on the new lock.
  [ 540.743543] the existing dependency chain (in reverse order) is:

  [ 540.743546] -> #1 (btrfs-chunk-00){++++}-{4:4}:
  [ 540.743566] down_read_nested+0x48/0x2b0
  [ 540.743585] __btrfs_tree_read_lock+0x32/0x200 [btrfs]
  [ 540.743650] btrfs_read_lock_root_node+0x70/0x200 [btrfs]
  [ 540.743733] btrfs_search_slot+0x6c6/0xe00 [btrfs]
  [ 540.743785] btrfs_update_device+0x83/0x260 [btrfs]
  [ 540.743849] btrfs_finish_chunk_alloc+0x13f/0x660 [btrfs] <--- device_list_mutex
  [ 540.743911] btrfs_create_pending_block_groups+0x18d/0x3f0 [btrfs]
  [ 540.743982] btrfs_commit_transaction+0x86/0x1260 [btrfs]
  [ 540.744037] btrfs_init_new_device+0x1600/0x1dd0 [btrfs]
  [ 540.744101] btrfs_ioctl+0x1c77/0x24c0 [btrfs]
  [ 540.744166] __x64_sys_ioctl+0xe4/0x140
  [ 540.744170] do_syscall_64+0x4b/0x80
  [ 540.744174] entry_SYSCALL_64_after_hwframe+0x44/0xa9

  [ 540.744180] -> #0 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
  [ 540.744184] __lock_acquire+0x155f/0x2360
  [ 540.744188] lock_acquire+0x10b/0x5c0
  [ 540.744190] __mutex_lock+0xb1/0xf80
  [ 540.744193] mutex_lock_nested+0x27/0x30
  [ 540.744196] clone_fs_devices+0x6d/0x210 [btrfs]
  [ 540.744270] btrfs_read_chunk_tree+0x3c7/0xbb0 [btrfs]
  [ 540.744336] open_ctree+0xf6e/0x2074 [btrfs]
  [ 540.744406] btrfs_mount_root.cold.72+0x16/0x127 [btrfs]
  [ 540.744472] legacy_get_tree+0x38/0x90
  [ 540.744475] vfs_get_tree+0x30/0x140
  [ 540.744478] fc_mount+0x16/0x60
  [ 540.744482] vfs_kern_mount+0x91/0x100
  [ 540.744484] btrfs_mount+0x1e6/0x670 [btrfs]
  [ 540.744536] legacy_get_tree+0x38/0x90
  [ 540.744537] vfs_get_tree+0x30/0x140
  [ 540.744539] path_mount+0x8d8/0x1070
  [ 540.744541] do_mount+0x8d/0xc0
  [ 540.744543] __x64_sys_mount+0x125/0x160
  [ 540.744545] do_syscall_64+0x4b/0x80
  [ 540.744547] entry_SYSCALL_64_after_hwframe+0x44/0xa9

  [ 540.744551] other info that might help us debug this:
  [ 540.744552] Possible unsafe locking scenario:

  [ 540.744553] CPU0 				CPU1
  [ 540.744554] ---- 				----
  [ 540.744555] lock(btrfs-chunk-00);
  [ 540.744557] 					lock(&fs_devs->device_list_mutex);
  [ 540.744560] 					lock(btrfs-chunk-00);
  [ 540.744562] lock(&fs_devs->device_list_mutex);
  [ 540.744564]
   *** DEADLOCK ***

  [ 540.744565] 3 locks held by mount/2515:
  [ 540.744567] #0: ffffa0c56bf7a0e0 (&type->s_umount_key#42/1){+.+.}-{4:4}, at: alloc_super.isra.16+0xdf/0x450
  [ 540.744574] #1: ffffffffc05a9628 (uuid_mutex){+.+.}-{4:4}, at: btrfs_read_chunk_tree+0x63/0xbb0 [btrfs]
  [ 540.744640] #2: ffffa0c54a7932b8 (btrfs-chunk-00){++++}-{4:4}, at: __btrfs_tree_read_lock+0x32/0x200 [btrfs]
  [ 540.744708]
   stack backtrace:
  [ 540.744712] CPU: 2 PID: 2515 Comm: mount Not tainted 5.11.0-rc7+ #5

But the device_list_mutex in clone_fs_devices() is redundant, as
explained below.  Two threads [1]  and [2] (below) could lead to
clone_fs_device().

  [1]
  open_ctree <== mount sprout fs
   btrfs_read_chunk_tree()
    mutex_lock(&uuid_mutex) <== global lock
    read_one_dev()
     open_seed_devices()
      clone_fs_devices() <== seed fs_devices
       mutex_lock(&orig->device_list_mutex) <== seed fs_devices

  [2]
  btrfs_init_new_device() <== sprouting
   mutex_lock(&uuid_mutex); <== global lock
   btrfs_prepare_sprout()
     lockdep_assert_held(&uuid_mutex)
     clone_fs_devices(seed_fs_device) <== seed fs_devices

Both of these threads hold uuid_mutex which is sufficient to protect
getting the seed device(s) freed while we are trying to clone it for
sprouting [2] or mounting a sprout [1] (as above). A mounted seed device
can not free/write/replace because it is read-only. An unmounted seed
device can be freed by btrfs_free_stale_devices(), but it needs
uuid_mutex.  So this patch removes the unnecessary device_list_mutex in
clone_fs_devices().  And adds a lockdep_assert_held(&uuid_mutex) in
clone_fs_devices().

Reported-by: Su Yue <l@damenly.su>
Tested-by: Su Yue <l@damenly.su>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2021-09-26 14:09:00 +02:00
..
tests
…
Kconfig btrfs: disable build on platforms having page size 256K 2021-07-14 16:55:56 +02:00
Makefile
…
acl.c
…
async-thread.c
…
async-thread.h
…
backref.c
…
backref.h btrfs: add asserts for deleting backref cache nodes 2021-03-04 11:38:29 +01:00
block-group.c btrfs: fix race between writes to swap files and scrub 2021-03-09 11:11:11 +01:00
block-group.h btrfs: fix race between writes to swap files and scrub 2021-03-09 11:11:11 +01:00
block-rsv.c
…
block-rsv.h
…
btrfs_inode.h btrfs: fix race between marking inode needs to be logged and log syncing 2021-09-03 10:09:28 +02:00
check-integrity.c
…
check-integrity.h
…
compression.c btrfs: mark compressed range uptodate only if all bio succeed 2021-08-04 12:46:39 +02:00
compression.h
…
ctree.c btrfs: fix race when picking most recent mod log operation for an old root 2021-05-11 14:47:33 +02:00
ctree.h btrfs: fix race between writes to swap files and scrub 2021-03-09 11:11:11 +01:00
delalloc-space.c
…
delalloc-space.h
…
delayed-inode.c btrfs: abort transaction if we fail to update the delayed inode 2021-07-14 16:55:55 +02:00
delayed-inode.h
…
delayed-ref.c btrfs: account for new extents being deleted in total_bytes_pinned 2021-03-04 11:38:30 +01:00
delayed-ref.h btrfs: handle space_info::total_bytes_pinned inside the delayed ref itself 2021-03-04 11:38:30 +01:00
dev-replace.c
…
dev-replace.h
…
dir-item.c
…
discard.c
…
discard.h
…
disk-io.c btrfs: fix upper limit for max_inline for page size 64K 2021-09-22 12:27:54 +02:00
disk-io.h
…
export.c
…
export.h
…
extent-io-tree.h
…
extent-tree.c btrfs: check for missing device in btrfs_trim_fs 2021-07-28 14:35:45 +02:00
extent_io.c btrfs: return whole extents in fiemap 2021-06-03 09:00:43 +02:00
extent_io.h
…
extent_map.c
…
extent_map.h
…
file-item.c btrfs: fix error handling in btrfs_del_csums 2021-06-10 13:39:27 +02:00
file.c btrfs: fix race between marking inode needs to be logged and log syncing 2021-09-03 10:09:28 +02:00
free-space-cache.c btrfs: fix race between extent freeing/allocation when using bitmaps 2021-03-09 11:11:11 +01:00
free-space-cache.h
…
free-space-tree.c
…
free-space-tree.h
…
inode-item.c
…
inode-map.c
…
inode-map.h
…
inode.c btrfs: wake up async_delalloc_pages waiters after submit 2021-09-18 13:40:06 +02:00
ioctl.c btrfs: fix metadata extent leak after failure to create subvolume 2021-05-11 14:47:15 +02:00
locking.c
…
locking.h
…
lzo.c
…
misc.h
…
ordered-data.c
…
ordered-data.h
…
orphan.c
…
print-tree.c
…
print-tree.h
…
props.c
…
props.h
…
qgroup.c btrfs: fix sleep while in non-sleep context during qgroup removal 2021-03-30 14:31:53 +02:00
qgroup.h btrfs: export and rename qgroup_reserve_meta 2021-03-11 14:17:22 +01:00
raid56.c btrfs: fix raid6 qstripe kmap 2021-03-09 11:11:10 +01:00
raid56.h
…
rcu-string.h
…
reada.c
…
ref-verify.c
…
ref-verify.h
…
reflink.c btrfs: fix deadlock when cloning inline extents and low on available space 2021-06-10 13:39:28 +02:00
reflink.h
…
relocation.c btrfs: convert logic BUG_ON()'s in replace_path to ASSERT()'s 2021-05-11 14:47:22 +02:00
root-tree.c
…
scrub.c btrfs: fix race between writes to swap files and scrub 2021-03-09 11:11:11 +01:00
send.c btrfs: send: fix invalid path for unlink operations after parent orphanization 2021-07-14 16:55:40 +02:00
send.h
…
space-info.c
…
space-info.h btrfs: handle space_info::total_bytes_pinned inside the delayed ref itself 2021-03-04 11:38:30 +01:00
struct-funcs.c
…
super.c
…
sysfs.c btrfs: sysfs: fix format string for some discard stats 2021-07-14 16:55:55 +02:00
sysfs.h
…
transaction.c btrfs: clear defrag status of a root if starting transaction fails 2021-07-14 16:55:40 +02:00
transaction.h btrfs: fix race between marking inode needs to be logged and log syncing 2021-09-03 10:09:28 +02:00
tree-checker.c btrfs: tree-checker: do not error out if extent ref hash doesn't match 2021-06-10 13:39:12 +02:00
tree-checker.h
…
tree-defrag.c
…
tree-log.c btrfs: tree-log: check btrfs_lookup_data_extent return value 2021-09-18 13:40:31 +02:00
tree-log.h
…
ulist.c
…
ulist.h
…
uuid-tree.c
…
volumes.c btrfs: fix lockdep warning while mounting sprout fs 2021-09-26 14:09:00 +02:00
volumes.h
…
xattr.c btrfs: fix warning when creating a directory with smack enabled 2021-03-09 11:11:12 +01:00
xattr.h
…
zlib.c
…
zstd.c
…