Commit 387af5e4 authored by Jan Kara's avatar Jan Kara Committed by Thadeu Lima de Souza Cascardo

block: Revalidate i_bdev reference in bd_aquire()

BugLink: http://bugs.launchpad.net/bugs/1659111

When a device gets removed, block device inode unhashed so that it is not
used anymore (bdget() will not find it anymore). Later when a new device
gets created with the same device number, we create new block device
inode. However there may be file system device inodes whose i_bdev still
points to the original block device inode and thus we get two active
block device inodes for the same device. They will share the same
gendisk so the only visible differences will be that page caches will
not be coherent and BDIs will be different (the old block device inode
still points to unregistered BDI).

Fix the problem by checking in bd_acquire() whether i_bdev still points
to active block device inode and re-lookup the block device if not. That
way any open of a block device happening after the old device has been
removed will get correct block device inode.
Tested-by: default avatarLekshmi Pillai <lekshmicpillai@in.ibm.com>
Acked-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
(back ported from commit cccd9fb9)

Conflicts:
	fs/block_dev.c
Signed-off-by: default avatarThiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
Acked-by: default avatarSeth Forshee <seth.forshee@canonical.com>
Acked-by: default avatarBrad Figg <brad.figg@canonical.com>
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
parent a8758699
......@@ -713,13 +713,22 @@ static struct block_device *bd_acquire(struct inode *inode)
spin_lock(&bdev_lock);
bdev = inode->i_bdev;
if (bdev) {
if (bdev && !inode_unhashed(bdev->bd_inode)) {
ihold(bdev->bd_inode);
spin_unlock(&bdev_lock);
return bdev;
}
spin_unlock(&bdev_lock);
/*
* i_bdev references block device inode that was already shut down
* (corresponding device got removed). Remove the reference and look
* up block device inode again just in case new device got
* reestablished under the same device number.
*/
if (bdev)
bd_forget(inode);
bdev = bdget(inode->i_rdev);
if (bdev) {
spin_lock(&bdev_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment