mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 14:44:10 +08:00
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: Christoph Hellwig <hch@lst.de> Reviewed-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/20210514131842.1600568-2-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
9a66e6bd7e
commit
6c60ff048c
@ -29,8 +29,6 @@
|
|||||||
|
|
||||||
static struct kobject *block_depr;
|
static struct kobject *block_depr;
|
||||||
|
|
||||||
DECLARE_RWSEM(bdev_lookup_sem);
|
|
||||||
|
|
||||||
/* for extended dynamic devt allocation, currently only one major is used */
|
/* for extended dynamic devt allocation, currently only one major is used */
|
||||||
#define NR_EXT_DEVT (1 << MINORBITS)
|
#define NR_EXT_DEVT (1 << MINORBITS)
|
||||||
static DEFINE_IDA(ext_devt_ida);
|
static DEFINE_IDA(ext_devt_ida);
|
||||||
@ -609,13 +607,8 @@ void del_gendisk(struct gendisk *disk)
|
|||||||
blk_integrity_del(disk);
|
blk_integrity_del(disk);
|
||||||
disk_del_events(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);
|
mutex_lock(&disk->part0->bd_mutex);
|
||||||
|
disk->flags &= ~GENHD_FL_UP;
|
||||||
blk_drop_partitions(disk);
|
blk_drop_partitions(disk);
|
||||||
mutex_unlock(&disk->part0->bd_mutex);
|
mutex_unlock(&disk->part0->bd_mutex);
|
||||||
|
|
||||||
@ -629,8 +622,6 @@ void del_gendisk(struct gendisk *disk)
|
|||||||
remove_inode_hash(disk->part0->bd_inode);
|
remove_inode_hash(disk->part0->bd_inode);
|
||||||
|
|
||||||
set_capacity(disk, 0);
|
set_capacity(disk, 0);
|
||||||
disk->flags &= ~GENHD_FL_UP;
|
|
||||||
up_write(&bdev_lookup_sem);
|
|
||||||
|
|
||||||
if (!(disk->flags & GENHD_FL_HIDDEN)) {
|
if (!(disk->flags & GENHD_FL_HIDDEN)) {
|
||||||
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
|
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
|
||||||
|
@ -1298,6 +1298,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode)
|
|||||||
struct gendisk *disk = bdev->bd_disk;
|
struct gendisk *disk = bdev->bd_disk;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!(disk->flags & GENHD_FL_UP))
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
if (!bdev->bd_openers) {
|
if (!bdev->bd_openers) {
|
||||||
if (!bdev_is_partition(bdev)) {
|
if (!bdev_is_partition(bdev)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -1332,8 +1335,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode)
|
|||||||
whole->bd_part_count++;
|
whole->bd_part_count++;
|
||||||
mutex_unlock(&whole->bd_mutex);
|
mutex_unlock(&whole->bd_mutex);
|
||||||
|
|
||||||
if (!(disk->flags & GENHD_FL_UP) ||
|
if (!bdev_nr_sectors(bdev)) {
|
||||||
!bdev_nr_sectors(bdev)) {
|
|
||||||
__blkdev_put(whole, mode, 1);
|
__blkdev_put(whole, mode, 1);
|
||||||
bdput(whole);
|
bdput(whole);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
@ -1364,16 +1366,12 @@ struct block_device *blkdev_get_no_open(dev_t dev)
|
|||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
|
|
||||||
down_read(&bdev_lookup_sem);
|
|
||||||
bdev = bdget(dev);
|
bdev = bdget(dev);
|
||||||
if (!bdev) {
|
if (!bdev) {
|
||||||
up_read(&bdev_lookup_sem);
|
|
||||||
blk_request_module(dev);
|
blk_request_module(dev);
|
||||||
down_read(&bdev_lookup_sem);
|
|
||||||
|
|
||||||
bdev = bdget(dev);
|
bdev = bdget(dev);
|
||||||
if (!bdev)
|
if (!bdev)
|
||||||
goto unlock;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
disk = bdev->bd_disk;
|
disk = bdev->bd_disk;
|
||||||
@ -1383,14 +1381,11 @@ struct block_device *blkdev_get_no_open(dev_t dev)
|
|||||||
goto put_disk;
|
goto put_disk;
|
||||||
if (!try_module_get(bdev->bd_disk->fops->owner))
|
if (!try_module_get(bdev->bd_disk->fops->owner))
|
||||||
goto put_disk;
|
goto put_disk;
|
||||||
up_read(&bdev_lookup_sem);
|
|
||||||
return bdev;
|
return bdev;
|
||||||
put_disk:
|
put_disk:
|
||||||
put_disk(disk);
|
put_disk(disk);
|
||||||
bdput:
|
bdput:
|
||||||
bdput(bdev);
|
bdput(bdev);
|
||||||
unlock:
|
|
||||||
up_read(&bdev_lookup_sem);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +306,6 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev,
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_SYSFS */
|
#endif /* CONFIG_SYSFS */
|
||||||
|
|
||||||
extern struct rw_semaphore bdev_lookup_sem;
|
|
||||||
|
|
||||||
dev_t blk_lookup_devt(const char *name, int partno);
|
dev_t blk_lookup_devt(const char *name, int partno);
|
||||||
void blk_request_module(dev_t devt);
|
void blk_request_module(dev_t devt);
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
|
Loading…
Reference in New Issue
Block a user