]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
721e931813f35355847fbf9020d51786aa83ff5a
[thirdparty/kernel/stable-queue.git] /
1 From fcc99734d1d4ced30167eb02e17f656735cb9928 Mon Sep 17 00:00:00 2001
2 From: Qu Wenruo <wqu@suse.com>
3 Date: Mon, 27 Apr 2020 14:50:14 +0800
4 Subject: btrfs: transaction: Avoid deadlock due to bad initialization timing of fs_info::journal_info
5
6 From: Qu Wenruo <wqu@suse.com>
7
8 commit fcc99734d1d4ced30167eb02e17f656735cb9928 upstream.
9
10 [BUG]
11 One run of btrfs/063 triggered the following lockdep warning:
12 ============================================
13 WARNING: possible recursive locking detected
14 5.6.0-rc7-custom+ #48 Not tainted
15 --------------------------------------------
16 kworker/u24:0/7 is trying to acquire lock:
17 ffff88817d3a46e0 (sb_internal#2){.+.+}, at: start_transaction+0x66c/0x890 [btrfs]
18
19 but task is already holding lock:
20 ffff88817d3a46e0 (sb_internal#2){.+.+}, at: start_transaction+0x66c/0x890 [btrfs]
21
22 other info that might help us debug this:
23 Possible unsafe locking scenario:
24
25 CPU0
26 ----
27 lock(sb_internal#2);
28 lock(sb_internal#2);
29
30 *** DEADLOCK ***
31
32 May be due to missing lock nesting notation
33
34 4 locks held by kworker/u24:0/7:
35 #0: ffff88817b495948 ((wq_completion)btrfs-endio-write){+.+.}, at: process_one_work+0x557/0xb80
36 #1: ffff888189ea7db8 ((work_completion)(&work->normal_work)){+.+.}, at: process_one_work+0x557/0xb80
37 #2: ffff88817d3a46e0 (sb_internal#2){.+.+}, at: start_transaction+0x66c/0x890 [btrfs]
38 #3: ffff888174ca4da8 (&fs_info->reloc_mutex){+.+.}, at: btrfs_record_root_in_trans+0x83/0xd0 [btrfs]
39
40 stack backtrace:
41 CPU: 0 PID: 7 Comm: kworker/u24:0 Not tainted 5.6.0-rc7-custom+ #48
42 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
43 Workqueue: btrfs-endio-write btrfs_work_helper [btrfs]
44 Call Trace:
45 dump_stack+0xc2/0x11a
46 __lock_acquire.cold+0xce/0x214
47 lock_acquire+0xe6/0x210
48 __sb_start_write+0x14e/0x290
49 start_transaction+0x66c/0x890 [btrfs]
50 btrfs_join_transaction+0x1d/0x20 [btrfs]
51 find_free_extent+0x1504/0x1a50 [btrfs]
52 btrfs_reserve_extent+0xd5/0x1f0 [btrfs]
53 btrfs_alloc_tree_block+0x1ac/0x570 [btrfs]
54 btrfs_copy_root+0x213/0x580 [btrfs]
55 create_reloc_root+0x3bd/0x470 [btrfs]
56 btrfs_init_reloc_root+0x2d2/0x310 [btrfs]
57 record_root_in_trans+0x191/0x1d0 [btrfs]
58 btrfs_record_root_in_trans+0x90/0xd0 [btrfs]
59 start_transaction+0x16e/0x890 [btrfs]
60 btrfs_join_transaction+0x1d/0x20 [btrfs]
61 btrfs_finish_ordered_io+0x55d/0xcd0 [btrfs]
62 finish_ordered_fn+0x15/0x20 [btrfs]
63 btrfs_work_helper+0x116/0x9a0 [btrfs]
64 process_one_work+0x632/0xb80
65 worker_thread+0x80/0x690
66 kthread+0x1a3/0x1f0
67 ret_from_fork+0x27/0x50
68
69 It's pretty hard to reproduce, only one hit so far.
70
71 [CAUSE]
72 This is because we're calling btrfs_join_transaction() without re-using
73 the current running one:
74
75 btrfs_finish_ordered_io()
76 |- btrfs_join_transaction() <<< Call #1
77 |- btrfs_record_root_in_trans()
78 |- btrfs_reserve_extent()
79 |- btrfs_join_transaction() <<< Call #2
80
81 Normally such btrfs_join_transaction() call should re-use the existing
82 one, without trying to re-start a transaction.
83
84 But the problem is, in btrfs_join_transaction() call #1, we call
85 btrfs_record_root_in_trans() before initializing current::journal_info.
86
87 And in btrfs_join_transaction() call #2, we're relying on
88 current::journal_info to avoid such deadlock.
89
90 [FIX]
91 Call btrfs_record_root_in_trans() after we have initialized
92 current::journal_info.
93
94 CC: stable@vger.kernel.org # 4.4+
95 Signed-off-by: Qu Wenruo <wqu@suse.com>
96 Reviewed-by: David Sterba <dsterba@suse.com>
97 Signed-off-by: David Sterba <dsterba@suse.com>
98 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
99
100 ---
101 fs/btrfs/transaction.c | 13 +++++++++++--
102 1 file changed, 11 insertions(+), 2 deletions(-)
103
104 --- a/fs/btrfs/transaction.c
105 +++ b/fs/btrfs/transaction.c
106 @@ -590,10 +590,19 @@ again:
107 }
108
109 got_it:
110 - btrfs_record_root_in_trans(h, root);
111 -
112 if (!current->journal_info)
113 current->journal_info = h;
114 +
115 + /*
116 + * btrfs_record_root_in_trans() needs to alloc new extents, and may
117 + * call btrfs_join_transaction() while we're also starting a
118 + * transaction.
119 + *
120 + * Thus it need to be called after current->journal_info initialized,
121 + * or we can deadlock.
122 + */
123 + btrfs_record_root_in_trans(h, root);
124 +
125 return h;
126
127 join_fail: