Commit efcf5932 authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe

block: avoid to touch unloaded module instance when opening bdev

disk->fops->owner is grabbed in blkdev_get_no_open() after the disk
kobject refcount is increased. This way can't make sure that
disk->fops->owner is still alive since del_gendisk() still can move
on if the kobject refcount of disk is grabbed by open() and
disk->fops->open() isn't called yet.

Fixes the issue by moving try_module_get() into blkdev_get_by_dev()
with ->open_mutex() held, then we can drain the in-progress open()
in del_gendisk(). Meantime new open() won't succeed because disk
becomes not alive.

This way is reasonable because blkdev_get_no_open() needn't to touch
disk->fops or defined callbacks.

Cc: Christoph Hellwig <hch@lst.de>
Cc: czhong@redhat.com
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20211111020343.316126-1-ming.lei@redhat.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 2b504bd4
...@@ -753,8 +753,7 @@ struct block_device *blkdev_get_no_open(dev_t dev) ...@@ -753,8 +753,7 @@ struct block_device *blkdev_get_no_open(dev_t dev)
if (!bdev) if (!bdev)
return NULL; return NULL;
if ((bdev->bd_disk->flags & GENHD_FL_HIDDEN) || if ((bdev->bd_disk->flags & GENHD_FL_HIDDEN)) {
!try_module_get(bdev->bd_disk->fops->owner)) {
put_device(&bdev->bd_device); put_device(&bdev->bd_device);
return NULL; return NULL;
} }
...@@ -764,7 +763,6 @@ struct block_device *blkdev_get_no_open(dev_t dev) ...@@ -764,7 +763,6 @@ struct block_device *blkdev_get_no_open(dev_t dev)
void blkdev_put_no_open(struct block_device *bdev) void blkdev_put_no_open(struct block_device *bdev)
{ {
module_put(bdev->bd_disk->fops->owner);
put_device(&bdev->bd_device); put_device(&bdev->bd_device);
} }
...@@ -820,12 +818,14 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder) ...@@ -820,12 +818,14 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
ret = -ENXIO; ret = -ENXIO;
if (!disk_live(disk)) if (!disk_live(disk))
goto abort_claiming; goto abort_claiming;
if (!try_module_get(disk->fops->owner))
goto abort_claiming;
if (bdev_is_partition(bdev)) if (bdev_is_partition(bdev))
ret = blkdev_get_part(bdev, mode); ret = blkdev_get_part(bdev, mode);
else else
ret = blkdev_get_whole(bdev, mode); ret = blkdev_get_whole(bdev, mode);
if (ret) if (ret)
goto abort_claiming; goto put_module;
if (mode & FMODE_EXCL) { if (mode & FMODE_EXCL) {
bd_finish_claiming(bdev, holder); bd_finish_claiming(bdev, holder);
...@@ -847,7 +847,8 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder) ...@@ -847,7 +847,8 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
if (unblock_events) if (unblock_events)
disk_unblock_events(disk); disk_unblock_events(disk);
return bdev; return bdev;
put_module:
module_put(disk->fops->owner);
abort_claiming: abort_claiming:
if (mode & FMODE_EXCL) if (mode & FMODE_EXCL)
bd_abort_claiming(bdev, holder); bd_abort_claiming(bdev, holder);
...@@ -956,6 +957,7 @@ void blkdev_put(struct block_device *bdev, fmode_t mode) ...@@ -956,6 +957,7 @@ void blkdev_put(struct block_device *bdev, fmode_t mode)
blkdev_put_whole(bdev, mode); blkdev_put_whole(bdev, mode);
mutex_unlock(&disk->open_mutex); mutex_unlock(&disk->open_mutex);
module_put(disk->fops->owner);
blkdev_put_no_open(bdev); blkdev_put_no_open(bdev);
} }
EXPORT_SYMBOL(blkdev_put); EXPORT_SYMBOL(blkdev_put);
......
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