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

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.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 2b504bd4
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -753,8 +753,7 @@ struct block_device *blkdev_get_no_open(dev_t dev)

	if (!bdev)
		return NULL;
	if ((bdev->bd_disk->flags & GENHD_FL_HIDDEN) ||
	    !try_module_get(bdev->bd_disk->fops->owner)) {
	if ((bdev->bd_disk->flags & GENHD_FL_HIDDEN)) {
		put_device(&bdev->bd_device);
		return NULL;
	}
@@ -764,7 +763,6 @@ struct block_device *blkdev_get_no_open(dev_t dev)

void blkdev_put_no_open(struct block_device *bdev)
{
	module_put(bdev->bd_disk->fops->owner);
	put_device(&bdev->bd_device);
}

@@ -820,12 +818,14 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
	ret = -ENXIO;
	if (!disk_live(disk))
		goto abort_claiming;
	if (!try_module_get(disk->fops->owner))
		goto abort_claiming;
	if (bdev_is_partition(bdev))
		ret = blkdev_get_part(bdev, mode);
	else
		ret = blkdev_get_whole(bdev, mode);
	if (ret)
		goto abort_claiming;
		goto put_module;
	if (mode & FMODE_EXCL) {
		bd_finish_claiming(bdev, holder);

@@ -847,7 +847,8 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
	if (unblock_events)
		disk_unblock_events(disk);
	return bdev;

put_module:
	module_put(disk->fops->owner);
abort_claiming:
	if (mode & FMODE_EXCL)
		bd_abort_claiming(bdev, holder);
@@ -956,6 +957,7 @@ void blkdev_put(struct block_device *bdev, fmode_t mode)
		blkdev_put_whole(bdev, mode);
	mutex_unlock(&disk->open_mutex);

	module_put(disk->fops->owner);
	blkdev_put_no_open(bdev);
}
EXPORT_SYMBOL(blkdev_put);