Patch "block: protect iterate_bdevs() against concurrent close" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
block: protect iterate_bdevs() against concurrent close
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
block-protect-iterate_bdevs-against-concurrent-close.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
af309226db916e2c6e08d3eba3fa5c34225200c4Mon Sep 17 00:00:00 2001
From: Rabin Vincent <[email protected]>
Date: Thu, 1 Dec 2016 09:18:28 +0100
Subject: block: protect iterate_bdevs() against concurrent close
From: Rabin Vincent <[email protected]>
commit af309226db916e2c6e08d3eba3fa5c34225200c4 upstream.
If a block device is closed while iterate_bdevs() is handling it, the following NULL pointer dereference occurs because bdev->b_disk is NULL in bdev_get_queue(), which is called from blk_get_backing_dev_info() (in turn called by the mapping_cap_writeback_dirty() call in __filemap_fdatawrite_range()):
BUG: unable to handle kernel NULL pointer dereference at 0000000000000508 IP: [<ffffffff81314790>] blk_get_backing_dev_info+0x10/0x20 PGD 9e62067 PUD 9ee8067 PMD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: CPU: 1 PID: 2422 Comm: sync Not tainted 4.5.0-rc7+ #400 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) task: ffff880009f4d700 ti: ffff880009f5c000 task.ti: ffff880009f5c000 RIP: 0010:[<ffffffff81314790>] [<ffffffff81314790>] blk_get_backing_dev_info+0x10/0x20 RSP: 0018:ffff880009f5fe68 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88000ec17a38 RCX: ffffffff81a4e940 RDX: 7fffffffffffffff RSI: 0000000000000000 RDI: ffff88000ec176c0 RBP: ffff880009f5fe68 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000000 R12: ffff88000ec17860 R13: ffffffff811b25c0 R14: ffff88000ec178e0 R15: ffff88000ec17a38 FS: 00007faee505d700(0000) GS:ffff88000fb00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000508 CR3: 0000000009e8a000 CR4: 00000000000006e0 Stack: ffff880009f5feb8 ffffffff8112e7f5 0000000000000000 7fffffffffffffff 0000000000000000 0000000000000000 7fffffffffffffff 0000000000000001 ffff88000ec178e0 ffff88000ec17860 ffff880009f5fec8 ffffffff8112e81f Call Trace: [<ffffffff8112e7f5>] __filemap_fdatawrite_range+0x85/0x90 [<ffffffff8112e81f>] filemap_fdatawrite+0x1f/0x30 [<ffffffff811b25d6>] fdatawrite_one_bdev+0x16/0x20 [<ffffffff811bc402>] iterate_bdevs+0xf2/0x130 [<ffffffff811b2763>] sys_sync+0x63/0x90 [<ffffffff815d4272>] entry_SYSCALL_64_fastpath+0x12/0x76 Code: 0f 1f 44 00 00 48 8b 87 f0 00 00 00 55 48 89 e5 <48> 8b 80 08 05 00 00 5d RIP [<ffffffff81314790>] blk_get_backing_dev_info+0x10/0x20 RSP <ffff880009f5fe68> CR2: 0000000000000508 ---[ end trace 2487336ceb3de62d ]---
The crash is easily reproducible by running the following command, if an msleep(100) is inserted before the call to func() in iterate_devs():
while :; do head -c1 /dev/nullb0; done > /dev/null & while :; do sync; done
Fix it by holding the bd_mutex across the func() call and only calling func() if the bdev is opened.
--- fs/block_dev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/block_dev.c +6 -1
@@ -1950,6 +1950,7 @@ void iterate_bdevs(void (*func)(struct bspin_lock (&blockdev_superblock->s_inode_list_lock);list_for_each_entry (inode, &blockdev_superblock->s_inodes, i_sb_list) {struct address_space *mapping = inode->i_mapping; +struct block_device *bdev;spin_lock (&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
@@ -1970,8 +1971,12 @@ void iterate_bdevs(void (*func)(struct b*/ iput (old_inode); old_inode = inode; + bdev =I_BDEV (inode); -func (I_BDEV (inode), arg); +mutex_lock (&bdev->bd_mutex); +if (bdev->bd_openers) +func (bdev, arg); +mutex_unlock (&bdev->bd_mutex);spin_lock (&blockdev_superblock->s_inode_list_lock); }
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/block-protect-iterate_bdevs-against-concurrent-close.patch