]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.14.124/btrfs-fix-race-updating-log-root-item-during-fsync.patch
Linux 4.14.124
[thirdparty/kernel/stable-queue.git] / releases / 4.14.124 / btrfs-fix-race-updating-log-root-item-during-fsync.patch
1 From 06989c799f04810f6876900d4760c0edda369cf7 Mon Sep 17 00:00:00 2001
2 From: Filipe Manana <fdmanana@suse.com>
3 Date: Wed, 15 May 2019 16:03:17 +0100
4 Subject: Btrfs: fix race updating log root item during fsync
5
6 From: Filipe Manana <fdmanana@suse.com>
7
8 commit 06989c799f04810f6876900d4760c0edda369cf7 upstream.
9
10 When syncing the log, the final phase of a fsync operation, we need to
11 either create a log root's item or update the existing item in the log
12 tree of log roots, and that depends on the current value of the log
13 root's log_transid - if it's 1 we need to create the log root item,
14 otherwise it must exist already and we update it. Since there is no
15 synchronization between updating the log_transid and checking it for
16 deciding whether the log root's item needs to be created or updated, we
17 end up with a tiny race window that results in attempts to update the
18 item to fail because the item was not yet created:
19
20 CPU 1 CPU 2
21
22 btrfs_sync_log()
23
24 lock root->log_mutex
25
26 set log root's log_transid to 1
27
28 unlock root->log_mutex
29
30 btrfs_sync_log()
31
32 lock root->log_mutex
33
34 sets log root's
35 log_transid to 2
36
37 unlock root->log_mutex
38
39 update_log_root()
40
41 sees log root's log_transid
42 with a value of 2
43
44 calls btrfs_update_root(),
45 which fails with -EUCLEAN
46 and causes transaction abort
47
48 Until recently the race lead to a BUG_ON at btrfs_update_root(), but after
49 the recent commit 7ac1e464c4d47 ("btrfs: Don't panic when we can't find a
50 root key") we just abort the current transaction.
51
52 A sample trace of the BUG_ON() on a SLE12 kernel:
53
54 ------------[ cut here ]------------
55 kernel BUG at ../fs/btrfs/root-tree.c:157!
56 Oops: Exception in kernel mode, sig: 5 [#1]
57 SMP NR_CPUS=2048 NUMA pSeries
58 (...)
59 Supported: Yes, External
60 CPU: 78 PID: 76303 Comm: rtas_errd Tainted: G X 4.4.156-94.57-default #1
61 task: c00000ffa906d010 ti: c00000ff42b08000 task.ti: c00000ff42b08000
62 NIP: d000000036ae5cdc LR: d000000036ae5cd8 CTR: 0000000000000000
63 REGS: c00000ff42b0b860 TRAP: 0700 Tainted: G X (4.4.156-94.57-default)
64 MSR: 8000000002029033 <SF,VEC,EE,ME,IR,DR,RI,LE> CR: 22444484 XER: 20000000
65 CFAR: d000000036aba66c SOFTE: 1
66 GPR00: d000000036ae5cd8 c00000ff42b0bae0 d000000036bda220 0000000000000054
67 GPR04: 0000000000000001 0000000000000000 c00007ffff8d37c8 0000000000000000
68 GPR08: c000000000e19c00 0000000000000000 0000000000000000 3736343438312079
69 GPR12: 3930373337303434 c000000007a3a800 00000000007fffff 0000000000000023
70 GPR16: c00000ffa9d26028 c00000ffa9d261f8 0000000000000010 c00000ffa9d2ab28
71 GPR20: c00000ff42b0bc48 0000000000000001 c00000ff9f0d9888 0000000000000001
72 GPR24: c00000ffa9d26000 c00000ffa9d261e8 c00000ffa9d2a800 c00000ff9f0d9888
73 GPR28: c00000ffa9d26028 c00000ffa9d2aa98 0000000000000001 c00000ffa98f5b20
74 NIP [d000000036ae5cdc] btrfs_update_root+0x25c/0x4e0 [btrfs]
75 LR [d000000036ae5cd8] btrfs_update_root+0x258/0x4e0 [btrfs]
76 Call Trace:
77 [c00000ff42b0bae0] [d000000036ae5cd8] btrfs_update_root+0x258/0x4e0 [btrfs] (unreliable)
78 [c00000ff42b0bba0] [d000000036b53610] btrfs_sync_log+0x2d0/0xc60 [btrfs]
79 [c00000ff42b0bce0] [d000000036b1785c] btrfs_sync_file+0x44c/0x4e0 [btrfs]
80 [c00000ff42b0bd80] [c00000000032e300] vfs_fsync_range+0x70/0x120
81 [c00000ff42b0bdd0] [c00000000032e44c] do_fsync+0x5c/0xb0
82 [c00000ff42b0be10] [c00000000032e8dc] SyS_fdatasync+0x2c/0x40
83 [c00000ff42b0be30] [c000000000009488] system_call+0x3c/0x100
84 Instruction dump:
85 7f43d378 4bffebb9 60000000 88d90008 3d220000 e8b90000 3b390009 e87a01f0
86 e8898e08 e8f90000 4bfd48e5 60000000 <0fe00000> e95b0060 39200004 394a0ea0
87 ---[ end trace 8f2dc8f919cabab8 ]---
88
89 So fix this by doing the check of log_transid and updating or creating the
90 log root's item while holding the root's log_mutex.
91
92 Fixes: 7237f1833601d ("Btrfs: fix tree logs parallel sync")
93 CC: stable@vger.kernel.org # 4.4+
94 Signed-off-by: Filipe Manana <fdmanana@suse.com>
95 Signed-off-by: David Sterba <dsterba@suse.com>
96 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
97
98 ---
99 fs/btrfs/tree-log.c | 8 ++++++--
100 1 file changed, 6 insertions(+), 2 deletions(-)
101
102 --- a/fs/btrfs/tree-log.c
103 +++ b/fs/btrfs/tree-log.c
104 @@ -2907,6 +2907,12 @@ int btrfs_sync_log(struct btrfs_trans_ha
105 log->log_transid = root->log_transid;
106 root->log_start_pid = 0;
107 /*
108 + * Update or create log root item under the root's log_mutex to prevent
109 + * races with concurrent log syncs that can lead to failure to update
110 + * log root item because it was not created yet.
111 + */
112 + ret = update_log_root(trans, log);
113 + /*
114 * IO has been started, blocks of the log tree have WRITTEN flag set
115 * in their headers. new modifications of the log will be written to
116 * new positions. so it's safe to allow log writers to go in.
117 @@ -2925,8 +2931,6 @@ int btrfs_sync_log(struct btrfs_trans_ha
118
119 mutex_unlock(&log_root_tree->log_mutex);
120
121 - ret = update_log_root(trans, log);
122 -
123 mutex_lock(&log_root_tree->log_mutex);
124 if (atomic_dec_and_test(&log_root_tree->log_writers)) {
125 /*