blockdev: Avoid two active bdev inodes for one device
authorJan Kara <jack@suse.cz>
Mon, 26 Feb 2018 12:01:42 +0000 (13:01 +0100)
committerJens Axboe <axboe@kernel.dk>
Mon, 26 Feb 2018 16:48:42 +0000 (09:48 -0700)
commit560e7cb2f3c7f09bbfb36cd0b900e24fddd20282
tree62ae10aef5f6b0c59124a14a89f22dd37ce20f09
parent56c0908c855afbb2bdda17c15d2879949a091ad3
blockdev: Avoid two active bdev inodes for one device

When blkdev_open() races with device removal and creation it can happen
that unhashed bdev inode gets associated with newly created gendisk
like:

CPU0 CPU1
blkdev_open()
  bdev = bd_acquire()
del_gendisk()
  bdev_unhash_inode(bdev);
remove device
create new device with the same number
  __blkdev_get()
    disk = get_gendisk()
      - gets reference to gendisk of the new device

Now another blkdev_open() will not find original 'bdev' as it got
unhashed, create a new one and associate it with the same 'disk' at
which point problems start as we have two independent page caches for
one device.

Fix the problem by verifying that the bdev inode didn't get unhashed
before we acquired gendisk reference. That way we make sure gendisk can
get associated only with visible bdev inodes.

Tested-by: Hou Tao <houtao1@huawei.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/block_dev.c