Commit 6c60ff04 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

block: prevent block device lookups at the beginning of del_gendisk



As an artifact of how gendisk lookup used to work in earlier kernels,
GENHD_FL_UP is only cleared very late in del_gendisk, and a global lock
is used to prevent opens from succeeding while del_gendisk is tearing
down the gendisk.  Switch to clearing the flag early and under bd_mutex
so that callers can use bd_mutex to stabilize the flag, which removes
the need for the global mutex.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20210514131842.1600568-2-hch@lst.de


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 9a66e6bd
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@

static struct kobject *block_depr;

DECLARE_RWSEM(bdev_lookup_sem);

/* for extended dynamic devt allocation, currently only one major is used */
#define NR_EXT_DEVT		(1 << MINORBITS)
static DEFINE_IDA(ext_devt_ida);
@@ -609,13 +607,8 @@ void del_gendisk(struct gendisk *disk)
	blk_integrity_del(disk);
	disk_del_events(disk);

	/*
	 * Block lookups of the disk until all bdevs are unhashed and the
	 * disk is marked as dead (GENHD_FL_UP cleared).
	 */
	down_write(&bdev_lookup_sem);

	mutex_lock(&disk->part0->bd_mutex);
	disk->flags &= ~GENHD_FL_UP;
	blk_drop_partitions(disk);
	mutex_unlock(&disk->part0->bd_mutex);

@@ -629,8 +622,6 @@ void del_gendisk(struct gendisk *disk)
	remove_inode_hash(disk->part0->bd_inode);

	set_capacity(disk, 0);
	disk->flags &= ~GENHD_FL_UP;
	up_write(&bdev_lookup_sem);

	if (!(disk->flags & GENHD_FL_HIDDEN)) {
		sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
+5 −10
Original line number Diff line number Diff line
@@ -1298,6 +1298,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode)
	struct gendisk *disk = bdev->bd_disk;
	int ret = 0;

	if (!(disk->flags & GENHD_FL_UP))
		return -ENXIO;

	if (!bdev->bd_openers) {
		if (!bdev_is_partition(bdev)) {
			ret = 0;
@@ -1332,8 +1335,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode)
			whole->bd_part_count++;
			mutex_unlock(&whole->bd_mutex);

			if (!(disk->flags & GENHD_FL_UP) ||
			    !bdev_nr_sectors(bdev)) {
			if (!bdev_nr_sectors(bdev)) {
				__blkdev_put(whole, mode, 1);
				bdput(whole);
				return -ENXIO;
@@ -1364,16 +1366,12 @@ struct block_device *blkdev_get_no_open(dev_t dev)
	struct block_device *bdev;
	struct gendisk *disk;

	down_read(&bdev_lookup_sem);
	bdev = bdget(dev);
	if (!bdev) {
		up_read(&bdev_lookup_sem);
		blk_request_module(dev);
		down_read(&bdev_lookup_sem);

		bdev = bdget(dev);
		if (!bdev)
			goto unlock;
			return NULL;
	}

	disk = bdev->bd_disk;
@@ -1383,14 +1381,11 @@ struct block_device *blkdev_get_no_open(dev_t dev)
		goto put_disk;
	if (!try_module_get(bdev->bd_disk->fops->owner))
		goto put_disk;
	up_read(&bdev_lookup_sem);
	return bdev;
put_disk:
	put_disk(disk);
bdput:
	bdput(bdev);
unlock:
	up_read(&bdev_lookup_sem);
	return NULL;
}

+0 −2
Original line number Diff line number Diff line
@@ -306,8 +306,6 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev,
}
#endif /* CONFIG_SYSFS */

extern struct rw_semaphore bdev_lookup_sem;

dev_t blk_lookup_devt(const char *name, int partno);
void blk_request_module(dev_t devt);
#ifdef CONFIG_BLOCK