linux-brain/fs/btrfs
Qu Wenruo 57be052c28 btrfs: transaction: Avoid deadlock due to bad initialization timing of fs_info::journal_info
commit fcc99734d1d4ced30167eb02e17f656735cb9928 upstream.

[BUG]
One run of btrfs/063 triggered the following lockdep warning:
  ============================================
  WARNING: possible recursive locking detected
  5.6.0-rc7-custom+ #48 Not tainted
  --------------------------------------------
  kworker/u24:0/7 is trying to acquire lock:
  ffff88817d3a46e0 (sb_internal#2){.+.+}, at: start_transaction+0x66c/0x890 [btrfs]

  but task is already holding lock:
  ffff88817d3a46e0 (sb_internal#2){.+.+}, at: start_transaction+0x66c/0x890 [btrfs]

  other info that might help us debug this:
   Possible unsafe locking scenario:

         CPU0
         ----
    lock(sb_internal#2);
    lock(sb_internal#2);

   *** DEADLOCK ***

   May be due to missing lock nesting notation

  4 locks held by kworker/u24:0/7:
   #0: ffff88817b495948 ((wq_completion)btrfs-endio-write){+.+.}, at: process_one_work+0x557/0xb80
   #1: ffff888189ea7db8 ((work_completion)(&work->normal_work)){+.+.}, at: process_one_work+0x557/0xb80
   #2: ffff88817d3a46e0 (sb_internal#2){.+.+}, at: start_transaction+0x66c/0x890 [btrfs]
   #3: ffff888174ca4da8 (&fs_info->reloc_mutex){+.+.}, at: btrfs_record_root_in_trans+0x83/0xd0 [btrfs]

  stack backtrace:
  CPU: 0 PID: 7 Comm: kworker/u24:0 Not tainted 5.6.0-rc7-custom+ #48
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  Workqueue: btrfs-endio-write btrfs_work_helper [btrfs]
  Call Trace:
   dump_stack+0xc2/0x11a
   __lock_acquire.cold+0xce/0x214
   lock_acquire+0xe6/0x210
   __sb_start_write+0x14e/0x290
   start_transaction+0x66c/0x890 [btrfs]
   btrfs_join_transaction+0x1d/0x20 [btrfs]
   find_free_extent+0x1504/0x1a50 [btrfs]
   btrfs_reserve_extent+0xd5/0x1f0 [btrfs]
   btrfs_alloc_tree_block+0x1ac/0x570 [btrfs]
   btrfs_copy_root+0x213/0x580 [btrfs]
   create_reloc_root+0x3bd/0x470 [btrfs]
   btrfs_init_reloc_root+0x2d2/0x310 [btrfs]
   record_root_in_trans+0x191/0x1d0 [btrfs]
   btrfs_record_root_in_trans+0x90/0xd0 [btrfs]
   start_transaction+0x16e/0x890 [btrfs]
   btrfs_join_transaction+0x1d/0x20 [btrfs]
   btrfs_finish_ordered_io+0x55d/0xcd0 [btrfs]
   finish_ordered_fn+0x15/0x20 [btrfs]
   btrfs_work_helper+0x116/0x9a0 [btrfs]
   process_one_work+0x632/0xb80
   worker_thread+0x80/0x690
   kthread+0x1a3/0x1f0
   ret_from_fork+0x27/0x50

It's pretty hard to reproduce, only one hit so far.

[CAUSE]
This is because we're calling btrfs_join_transaction() without re-using
the current running one:

btrfs_finish_ordered_io()
|- btrfs_join_transaction()		<<< Call #1
   |- btrfs_record_root_in_trans()
      |- btrfs_reserve_extent()
	 |- btrfs_join_transaction()	<<< Call #2

Normally such btrfs_join_transaction() call should re-use the existing
one, without trying to re-start a transaction.

But the problem is, in btrfs_join_transaction() call #1, we call
btrfs_record_root_in_trans() before initializing current::journal_info.

And in btrfs_join_transaction() call #2, we're relying on
current::journal_info to avoid such deadlock.

[FIX]
Call btrfs_record_root_in_trans() after we have initialized
current::journal_info.

CC: stable@vger.kernel.org # 4.4+
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-05-06 08:13:33 +02:00
..
tests Btrfs: fix race between adding and putting tree mod seq elements and nodes 2020-02-11 04:34:06 -08:00
acl.c Btrfs: setup a nofs context for memory allocation at __btrfs_set_acl 2019-03-23 20:10:00 +01:00
async-thread.c Btrfs: fix crash during unmount due to race with delayed inode workers 2020-04-17 10:48:49 +02:00
async-thread.h Btrfs: fix crash during unmount due to race with delayed inode workers 2020-04-17 10:48:49 +02:00
backref.c Btrfs: fix deadlock between fiemap and transaction commits 2019-08-25 10:47:54 +02:00
backref.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
btrfs_inode.h btrfs: use tagged writepage to mitigate livelock of snapshot 2019-02-12 19:47:11 +01:00
check-integrity.c btrfs: fix possible NULL-pointer dereference in integrity checks 2020-02-24 08:34:49 +01:00
check-integrity.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
compression.c btrfs: correctly validate compression type 2019-09-16 08:22:19 +02:00
compression.h btrfs: correctly validate compression type 2019-09-16 08:22:19 +02:00
ctree.c Btrfs: fix race between adding and putting tree mod seq elements and nodes 2020-02-11 04:34:06 -08:00
ctree.h Btrfs: fix race between adding and putting tree mod seq elements and nodes 2020-02-11 04:34:06 -08:00
dedupe.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
delayed-inode.c btrfs: use nofs allocations for running delayed items 2020-04-17 10:48:54 +02:00
delayed-inode.h btrfs: Remove fs_info from btrfs_delete_delayed_dir_index 2018-08-06 13:13:00 +02:00
delayed-ref.c Btrfs: fix race between adding and putting tree mod seq elements and nodes 2020-02-11 04:34:06 -08:00
delayed-ref.h btrfs: Remove fs_info from btrfs_add_delayed_data_ref 2018-08-06 13:12:34 +02:00
dev-replace.c btrfs: dev-replace: set result code of cancel by status of scrub 2019-12-05 09:20:21 +01:00
dev-replace.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
dir-item.c btrfs: Remove fs_info from btrfs_insert_delayed_dir_index 2018-08-06 13:13:00 +02:00
disk-io.c btrfs: set update the uuid generation as soon as possible 2020-04-17 10:48:49 +02:00
disk-io.h btrfs: Check the first key and level for cached extent buffer 2019-05-22 07:37:42 +02:00
export.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
export.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
extent_io.c btrfs: flush write bio if we loop in extent_write_cache_pages 2020-02-11 04:34:16 -08:00
extent_io.h Btrfs: allow clear_extent_dirty() to receive a cached extent state record 2019-12-05 09:20:22 +01:00
extent_map.c Btrfs: fix race between using extent maps and merging them 2020-02-19 19:51:56 +01:00
extent_map.h btrfs: use fs_info for btrfs_handle_em_exist tracepoint 2018-05-28 18:07:17 +02:00
extent-tree.c btrfs: fix block group leak when removing fails 2020-05-06 08:13:27 +02:00
file-item.c btrfs: safely advance counter when looking up bio csums 2020-02-24 08:34:49 +01:00
file.c btrfs: fix missing semaphore unlock in btrfs_sync_file 2020-04-17 10:48:49 +02:00
free-space-cache.c btrfs: check page->mapping when loading free space cache 2019-12-17 20:34:45 +01:00
free-space-cache.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
free-space-tree.c btrfs: Remove fs_info from btrfs_del_root 2018-08-06 13:13:00 +02:00
free-space-tree.h btrfs: Remove fs_info argument from add_to_free_space_tree 2018-05-28 18:07:36 +02:00
inode-item.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
inode-map.c Btrfs: fix inode cache waiters hanging on path allocation failure 2020-01-27 14:51:12 +01:00
inode-map.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
inode.c btrfs: fix log context list corruption after rename whiteout error 2020-03-25 08:06:12 +01:00
ioctl.c btrfs: abort transaction after failed inode updates in create_subvol 2019-12-31 16:34:43 +01:00
Kconfig btrfs: add SPDX header to Kconfig 2018-04-12 16:29:55 +02:00
locking.c btrfs: replace waitqueue_actvie with cond_wake_up 2018-05-28 18:23:09 +02:00
locking.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
lzo.c btrfs: lzo: Harden inline lzo compressed extent decompression 2018-05-30 16:46:43 +02:00
Makefile btrfs: Remove custom crc32c init code 2018-03-26 15:09:39 +02:00
math.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
ordered-data.c Btrfs: fix btrfs_wait_ordered_range() so that it waits for all ordered extents 2020-02-28 16:38:58 +01:00
ordered-data.h btrfs: remove remaing full_sync logic from btrfs_sync_file 2018-08-06 13:12:31 +02:00
orphan.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
print-tree.c btrfs: annotate unlikely branches after V0 extent type removal 2018-08-06 13:12:41 +02:00
print-tree.h btrfs: print-tree: debugging output enhancement 2018-04-20 19:18:16 +02:00
props.c btrfs: correctly validate compression type 2019-09-16 08:22:19 +02:00
props.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
qgroup.c btrfs: qgroup: ensure qgroup_rescan_running is only set when the worker is at least queued 2020-04-17 10:48:42 +02:00
qgroup.h btrfs: qgroup: Avoid calling qgroup functions if qgroup is not enabled 2018-11-13 11:08:56 -08:00
raid56.c btrfs: raid56: properly unmap parity page in finish_parity_scrub() 2019-04-03 06:26:21 +02:00
raid56.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
rcu-string.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
reada.c btrfs: don't prematurely free work in reada_start_machine_worker() 2019-12-31 16:36:16 +01:00
ref-verify.c btrfs: ref-verify: fix memory leaks 2020-02-19 19:51:56 +01:00
ref-verify.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
relocation.c btrfs: check commit root generation in should_ignore_root 2020-04-21 09:03:09 +02:00
root-tree.c btrfs: do not delete mismatched root refs 2020-01-23 08:21:31 +01:00
scrub.c btrfs: don't prematurely free work in scrub_missing_raid56_worker() 2019-12-31 16:36:16 +01:00
send.c btrfs: send: remove WARN_ON for readonly mount 2019-12-31 16:34:42 +01:00
send.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
struct-funcs.c btrfs: prune unused includes 2018-08-06 13:12:43 +02:00
super.c btrfs: log message when rw remount is attempted with unclean tree-log 2020-02-19 19:51:56 +01:00
sysfs.c btrfs: sysfs: don't leak memory when failing add fsid 2019-05-31 06:46:02 -07:00
sysfs.h btrfs: sysfs: Use enum/define value for feature array definitions 2018-05-28 18:23:39 +02:00
transaction.c btrfs: transaction: Avoid deadlock due to bad initialization timing of fs_info::journal_info 2020-05-06 08:13:33 +02:00
transaction.h Btrfs: fix deadlock between fiemap and transaction commits 2019-08-25 10:47:54 +02:00
tree-checker.c btrfs: tree-checker: Don't check max block group size as current max chunk size limit is unreliable 2018-12-08 12:59:10 +01:00
tree-checker.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
tree-defrag.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
tree-log.c btrfs: fix partial loss of prealloc extent past i_size after fsync 2020-05-06 08:13:33 +02:00
tree-log.h Btrfs: sync log after logging new name 2018-08-23 17:37:26 +02:00
ulist.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
ulist.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
uuid-tree.c btrfs: handle ENOENT in btrfs_uuid_tree_iterate 2019-12-31 16:34:44 +01:00
volumes.c btrfs: device stats, log when stats are zeroed 2020-02-24 08:34:49 +01:00
volumes.h btrfs: Remove btrfs_bio::flags member 2019-12-17 20:34:48 +01:00
xattr.c Btrfs: use nofs context when initializing security xattrs to avoid deadlock 2019-01-16 22:04:37 +01:00
xattr.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
zlib.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
zstd.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00