add patch fix-inode-checksum-calculation-if-i_extra_size-is-too-small
[ext4-patch-queue.git] / dont-lock-buffer-head-in-ext4_commit_super-if-holding-spinlock
blob08bcb6edd111c6dc04db0c593091bba4098d4b18
1 ext4: don't lock buffer in ext4_commit_super if holding spinlock
3 If there is an error reported in mballoc via ext4_grp_locked_error(),
4 the code is holding a spinlock, so ext4_commit_super() must not try to
5 lock the buffer head, or else it will trigger a BUG:
7   BUG: sleeping function called from invalid context at ./include/linux/buffer_head.h:358
8   in_atomic(): 1, irqs_disabled(): 0, pid: 993, name: mount
9   CPU: 0 PID: 993 Comm: mount Not tainted 4.9.0-rc1-clouder1 #62
10   Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.1-0-g4adadbd-20150316_085822-nilsson.home.kraxel.org 04/01/2014
11    ffff880006423548 ffffffff81318c89 ffffffff819ecdd0 0000000000000166
12    ffff880006423558 ffffffff810810b0 ffff880006423580 ffffffff81081153
13    ffff880006e5a1a0 ffff88000690e400 0000000000000000 ffff8800064235c0
14   Call Trace:
15     [<ffffffff81318c89>] dump_stack+0x67/0x9e
16     [<ffffffff810810b0>] ___might_sleep+0xf0/0x140
17     [<ffffffff81081153>] __might_sleep+0x53/0xb0
18     [<ffffffff8126c1dc>] ext4_commit_super+0x19c/0x290
19     [<ffffffff8126e61a>] __ext4_grp_locked_error+0x14a/0x230
20     [<ffffffff81081153>] ? __might_sleep+0x53/0xb0
21     [<ffffffff812822be>] ext4_mb_generate_buddy+0x1de/0x320
23 Since ext4_grp_locked_error() calls ext4_commit_super with sync == 0
24 (and it is the only caller which does so), avoid locking and unlocking
25 the buffer in this case.
27 This can result in races with ext4_commit_super() if there are other
28 problems (which is what commit 4743f83990614 was trying to address),
29 but a Warning is better than BUG.
31 Fixes: 4743f83990614
32 Cc: stable@vger.kernel.org # 4.9
33 Reported-by: Nikolay Borisov <kernel@kyup.com>
34 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
35 ---
36  fs/ext4/super.c | 5 +++--
37  1 file changed, 3 insertions(+), 2 deletions(-)
39 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
40 index e4f61c39328a..ff6f3ab09c7e 100644
41 --- a/fs/ext4/super.c
42 +++ b/fs/ext4/super.c
43 @@ -4537,7 +4537,8 @@ static int ext4_commit_super(struct super_block *sb, int sync)
44                                 &EXT4_SB(sb)->s_freeinodes_counter));
45         BUFFER_TRACE(sbh, "marking dirty");
46         ext4_superblock_csum_set(sb);
47 -       lock_buffer(sbh);
48 +       if (sync)
49 +               lock_buffer(sbh);
50         if (buffer_write_io_error(sbh)) {
51                 /*
52                  * Oh, dear.  A previous attempt to write the
53 @@ -4553,8 +4554,8 @@ static int ext4_commit_super(struct super_block *sb, int sync)
54                 set_buffer_uptodate(sbh);
55         }
56         mark_buffer_dirty(sbh);
57 -       unlock_buffer(sbh);
58         if (sync) {
59 +               unlock_buffer(sbh);
60                 error = __sync_dirty_buffer(sbh,
61                         test_opt(sb, BARRIER) ? WRITE_FUA : WRITE_SYNC);
62                 if (error)