From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.10-rc1 commit f4ad06f2bb8476548b08f89919ee65abc4e40212 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5ETAB CVE: NA
-------------------------------------------------
Replace bd_invalidate with a new BDEV_NEED_PART_SCAN flag in a bd_flags variable to better describe the condition.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Josef Bacik josef@toxicpanda.com Reviewed-by: Johannes Thumshirn johannes.thumshirn@wdc.com Signed-off-by: Jens Axboe axboe@kernel.dk
Conflicts: fs/block_dev.c include/linux/blk_types.h
Signed-off-by: Luo Meng luomeng12@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- block/genhd.c | 2 +- block/partition-generic.c | 6 +++--- drivers/block/nbd.c | 8 ++++---- fs/block_dev.c | 12 ++++++------ include/linux/fs.h | 4 +++- 5 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index fc24384e2c85..afa3cf525f43 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -646,7 +646,7 @@ static void register_disk(struct device *parent, struct gendisk *disk) if (!bdev) goto exit;
- bdev->bd_invalidated = 1; + set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); err = blkdev_get(bdev, FMODE_READ, NULL); if (err < 0) goto exit; diff --git a/block/partition-generic.c b/block/partition-generic.c index 2261566741f4..ae3761fed854 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -546,7 +546,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); check_disk_size_change(disk, bdev, true); - bdev->bd_invalidated = 0; + clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) return 0; if (IS_ERR(state)) { @@ -662,7 +662,7 @@ int invalidate_partitions(struct gendisk *disk, struct block_device *bdev) { int res;
- if (!bdev->bd_invalidated) + if (!test_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags)) return 0;
res = drop_partitions(disk, bdev); @@ -671,7 +671,7 @@ int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
set_capacity(disk, 0); check_disk_size_change(disk, bdev, false); - bdev->bd_invalidated = 0; + clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); /* tell userspace that the media / partition table may have changed */ kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c2e5ba599418..f1986d8bb47c 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -317,7 +317,7 @@ static void nbd_size_update(struct nbd_device *nbd, bool start) if (start) set_blocksize(bdev, config->blksize); } else - bdev->bd_invalidated = 1; + set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); bdput(bdev); } kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE); @@ -1343,7 +1343,7 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b return ret;
if (max_part) - bdev->bd_invalidated = 1; + set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); mutex_unlock(&nbd->config_lock); ret = wait_event_interruptible(config->recv_wq, atomic_read(&config->recv_threads) == 0); @@ -1518,9 +1518,9 @@ static int nbd_open(struct block_device *bdev, fmode_t mode) refcount_set(&nbd->config_refs, 1); refcount_inc(&nbd->refs); mutex_unlock(&nbd->config_lock); - bdev->bd_invalidated = 1; + set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); } else if (nbd_disconnected(nbd->config)) { - bdev->bd_invalidated = 1; + set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); } out: mutex_unlock(&nbd_index_mutex); diff --git a/fs/block_dev.c b/fs/block_dev.c index 9868b21b8ef9..f521b7cf907f 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -922,7 +922,7 @@ struct block_device *bdget(dev_t dev) bdev->bd_inode = inode; bdev->bd_block_size = i_blocksize(inode); bdev->bd_part_count = 0; - bdev->bd_invalidated = 0; + bdev->bd_flags = 0; inode->i_mode = S_IFBLK; inode->i_rdev = dev; inode->i_bdev = bdev; @@ -1404,7 +1404,7 @@ static void flush_disk(struct block_device *bdev, bool kill_dirty) "resized disk %s\n", bdev->bd_disk ? bdev->bd_disk->disk_name : ""); } - bdev->bd_invalidated = 1; + set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); }
/** @@ -1457,7 +1457,7 @@ int revalidate_disk(struct gendisk *disk)
mutex_lock(&bdev->bd_mutex); check_disk_size_change(disk, bdev, ret == 0); - bdev->bd_invalidated = 0; + clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); mutex_unlock(&bdev->bd_mutex); bdput(bdev); return ret; @@ -1520,7 +1520,7 @@ static void bdev_disk_changed(struct block_device *bdev, bool invalidate) up_read(&disk->lookup_sem); } else { check_disk_size_change(bdev->bd_disk, bdev, !invalidate); - bdev->bd_invalidated = 0; + clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); } }
@@ -1605,7 +1605,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) * The latter is necessary to prevent ghost * partitions on a removed medium. */ - if (bdev->bd_invalidated && + if (test_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags) && (!ret || ret == -ENOMEDIUM)) bdev_disk_changed(bdev, ret == -ENOMEDIUM);
@@ -1642,7 +1642,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) if (bdev->bd_disk->fops->open) ret = bdev->bd_disk->fops->open(bdev, mode); /* the same as first opener case, read comment there */ - if (bdev->bd_invalidated && + if (test_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags) && (!ret || ret == -ENOMEDIUM)) bdev_disk_changed(bdev, ret == -ENOMEDIUM); if (ret) diff --git a/include/linux/fs.h b/include/linux/fs.h index bcd2131ca06c..480936c2d938 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -459,6 +459,8 @@ struct address_space { */ struct request_queue;
+#define BDEV_NEED_PART_SCAN 0 + struct block_device { dev_t bd_dev; /* not a kdev_t - it's a search key */ int bd_openers; @@ -479,7 +481,7 @@ struct block_device { struct hd_struct * bd_part; /* number of times partitions within this device have been opened. */ unsigned bd_part_count; - int bd_invalidated; + unsigned long bd_flags; struct gendisk * bd_disk; struct request_queue * bd_queue; struct backing_dev_info *bd_bdi;
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.10-rc1 commit 38430f0876fa8b9549ec434f569dce03e057c076 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5ETAB CVE: NA
-------------------------------------------------
We can only scan for partitions on the whole disk, so move the flag from struct block_device to struct gendisk.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk
Conflicts: block/genhd.c drivers/ide/ide-gd.c fs/block_dev.c include/linux/blk_types.h
Signed-off-by: Luo Meng luomeng12@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- block/genhd.c | 2 +- block/partition-generic.c | 6 +++--- drivers/block/nbd.c | 8 ++++---- fs/block_dev.c | 11 +++++------ include/linux/fs.h | 3 --- include/linux/genhd.h | 2 ++ 6 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index afa3cf525f43..82c5b6e0afdb 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -646,7 +646,7 @@ static void register_disk(struct device *parent, struct gendisk *disk) if (!bdev) goto exit;
- set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + set_bit(GD_NEED_PART_SCAN, &disk->state); err = blkdev_get(bdev, FMODE_READ, NULL); if (err < 0) goto exit; diff --git a/block/partition-generic.c b/block/partition-generic.c index ae3761fed854..b8481079c58a 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -546,7 +546,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); check_disk_size_change(disk, bdev, true); - clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + clear_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) return 0; if (IS_ERR(state)) { @@ -662,7 +662,7 @@ int invalidate_partitions(struct gendisk *disk, struct block_device *bdev) { int res;
- if (!test_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags)) + if (!test_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state)) return 0;
res = drop_partitions(disk, bdev); @@ -671,7 +671,7 @@ int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
set_capacity(disk, 0); check_disk_size_change(disk, bdev, false); - clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + clear_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); /* tell userspace that the media / partition table may have changed */ kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index f1986d8bb47c..43a9acaa2e86 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -317,7 +317,7 @@ static void nbd_size_update(struct nbd_device *nbd, bool start) if (start) set_blocksize(bdev, config->blksize); } else - set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + set_bit(GD_NEED_PART_SCAN, &nbd->disk->state); bdput(bdev); } kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE); @@ -1343,7 +1343,7 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b return ret;
if (max_part) - set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + set_bit(GD_NEED_PART_SCAN, &nbd->disk->state); mutex_unlock(&nbd->config_lock); ret = wait_event_interruptible(config->recv_wq, atomic_read(&config->recv_threads) == 0); @@ -1518,9 +1518,9 @@ static int nbd_open(struct block_device *bdev, fmode_t mode) refcount_set(&nbd->config_refs, 1); refcount_inc(&nbd->refs); mutex_unlock(&nbd->config_lock); - set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); } else if (nbd_disconnected(nbd->config)) { - set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); } out: mutex_unlock(&nbd_index_mutex); diff --git a/fs/block_dev.c b/fs/block_dev.c index f521b7cf907f..e255c3b65224 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -922,7 +922,6 @@ struct block_device *bdget(dev_t dev) bdev->bd_inode = inode; bdev->bd_block_size = i_blocksize(inode); bdev->bd_part_count = 0; - bdev->bd_flags = 0; inode->i_mode = S_IFBLK; inode->i_rdev = dev; inode->i_bdev = bdev; @@ -1404,7 +1403,7 @@ static void flush_disk(struct block_device *bdev, bool kill_dirty) "resized disk %s\n", bdev->bd_disk ? bdev->bd_disk->disk_name : ""); } - set_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); }
/** @@ -1457,7 +1456,7 @@ int revalidate_disk(struct gendisk *disk)
mutex_lock(&bdev->bd_mutex); check_disk_size_change(disk, bdev, ret == 0); - clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + clear_bit(GD_NEED_PART_SCAN, &disk->state); mutex_unlock(&bdev->bd_mutex); bdput(bdev); return ret; @@ -1520,7 +1519,7 @@ static void bdev_disk_changed(struct block_device *bdev, bool invalidate) up_read(&disk->lookup_sem); } else { check_disk_size_change(bdev->bd_disk, bdev, !invalidate); - clear_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags); + clear_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); } }
@@ -1605,7 +1604,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) * The latter is necessary to prevent ghost * partitions on a removed medium. */ - if (test_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags) && + if (test_bit(GD_NEED_PART_SCAN, &disk->state) && (!ret || ret == -ENOMEDIUM)) bdev_disk_changed(bdev, ret == -ENOMEDIUM);
@@ -1642,7 +1641,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) if (bdev->bd_disk->fops->open) ret = bdev->bd_disk->fops->open(bdev, mode); /* the same as first opener case, read comment there */ - if (test_bit(BDEV_NEED_PART_SCAN, &bdev->bd_flags) && + if (test_bit(GD_NEED_PART_SCAN, &disk->state) && (!ret || ret == -ENOMEDIUM)) bdev_disk_changed(bdev, ret == -ENOMEDIUM); if (ret) diff --git a/include/linux/fs.h b/include/linux/fs.h index 480936c2d938..025b98fbab05 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -459,8 +459,6 @@ struct address_space { */ struct request_queue;
-#define BDEV_NEED_PART_SCAN 0 - struct block_device { dev_t bd_dev; /* not a kdev_t - it's a search key */ int bd_openers; @@ -481,7 +479,6 @@ struct block_device { struct hd_struct * bd_part; /* number of times partitions within this device have been opened. */ unsigned bd_part_count; - unsigned long bd_flags; struct gendisk * bd_disk; struct request_queue * bd_queue; struct backing_dev_info *bd_bdi; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 58a819484fb4..f3fc01f0e84c 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -208,6 +208,8 @@ struct gendisk { void *private_data;
int flags; + unsigned long state; +#define GD_NEED_PART_SCAN 0 struct rw_semaphore lookup_sem; struct kobject *slave_dir;
From: Luo Meng luomeng12@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5ETAB CVE: NA
--------------------------------
Warning reports as follows:
WARNING: CPU: 3 PID: 674 at fs/block_dev.c:1272 bd_link_disk_holder+0xcd/0x270 Modules linked in: null_blk(+) CPU: 3 PID: 674 Comm: dmsetup Not tainted 5.10.0-16691-gf6076432827d-dirty #158 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20190727_073836-4 RIP: 0010:bd_link_disk_holder+0xcd/0x270 Code: 69 73 ee 00 44 89 e8 5b 48 83 05 c5 bf 6d 0c 01 5d 41 5c 41 5d 41 5e 41 8 RSP: 0018:ffffc9000049bbb8 EFLAGS: 00010202 RAX: ffff888104e39038 RBX: ffff888104185000 RCX: 0000000000000000 RDX: 0000000000000001 RSI: ffffffffaa085692 RDI: 0000000000000000 RBP: ffff88810cc2ae00 R08: ffffffffa853659b R09: 0000000000000000 R10: ffffc9000049bbb0 R11: 720030626c6c756e R12: ffff88810e800000 R13: ffff88810e800090 R14: ffff888103570c98 R15: ffff888103570c80 FS: 00007fb49dc13dc0(0000) GS:ffff88813bd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ff994ebde70 CR3: 000000010d54a000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: dm_get_table_device+0x175/0x300 dm_get_device+0x238/0x360 linear_ctr+0xee/0x170 dm_table_add_target+0x199/0x4b0 table_load+0x18c/0x480 ? table_clear+0x190/0x190 ctl_ioctl+0x21d/0x640 ? check_preemption_disabled+0x140/0x150 dm_ctl_ioctl+0x12/0x20 __se_sys_ioctl+0xb1/0x100 __x64_sys_ioctl+0x1e/0x30 do_syscall_64+0x45/0x70 entry_SYSCALL_64_after_hwframe+0x44/0xa9
This can reproduce by concurrent operations: 1. modprobe null_blk 2. echo -e "0 10000 linear /dev/nullb0 0" > table dmsetup create xxx table
t1: create disk a | t2: dm setup | device_add_disk | dev->devt = devt | | dm_get_table_device | open_table_device | blkdev_get_by_dev -> succeed | bd_link_disk_holder | -> holder_dir is still NULL register_disk -> create holder_dir kobject_create_and_add
device_add_disk() will set devt before creating holder_dir, which leaves a window that dm_get_table_device() can find the disk by devt while it's holder_dir is NULL.
So move GENHD_FL_UP in blk_register_queue() to avoid this warning and fix a NULL-ptr in __blk_mq_sched_bio_merge().
Signed-off-by: Luo Meng luomeng12@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- block/blk-sysfs.c | 6 ++++++ block/genhd.c | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 7ce092ab0f05..50b61a92b08d 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -938,6 +938,12 @@ int blk_register_queue(struct gendisk *disk) return ret; } } + + /* + * Set the flag at last, so that block devcie can't be opened + * before it's registration is done. + */ + disk->flags |= GENHD_FL_UP; ret = 0; unlock: mutex_unlock(&q->sysfs_lock); diff --git a/block/genhd.c b/block/genhd.c index 82c5b6e0afdb..94b0fe34a755 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -696,8 +696,6 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, WARN_ON(!disk->minors && !(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
- disk->flags |= GENHD_FL_UP; - retval = blk_alloc_devt(&disk->part0, &devt); if (retval) { WARN_ON(1);
From: Luo Meng luomeng12@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5ETAB CVE: NA
--------------------------------
Because add state in gendisk and remove flags in block_device, to fix the kabi chage.
Signed-off-by: Luo Meng luomeng12@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- include/linux/fs.h | 1 + include/linux/genhd.h | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h index 025b98fbab05..bcd2131ca06c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -479,6 +479,7 @@ struct block_device { struct hd_struct * bd_part; /* number of times partitions within this device have been opened. */ unsigned bd_part_count; + int bd_invalidated; struct gendisk * bd_disk; struct request_queue * bd_queue; struct backing_dev_info *bd_bdi; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index f3fc01f0e84c..50c76a59d7e2 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -180,6 +180,8 @@ struct blk_integrity {
#endif /* CONFIG_BLK_DEV_INTEGRITY */
+#define GD_NEED_PART_SCAN 0 + struct gendisk { /* major, first_minor and minors are input parameters only, * don't use directly. Use disk_devt() and disk_max_parts(). @@ -208,8 +210,6 @@ struct gendisk { void *private_data;
int flags; - unsigned long state; -#define GD_NEED_PART_SCAN 0 struct rw_semaphore lookup_sem; struct kobject *slave_dir;
@@ -226,11 +226,12 @@ struct gendisk { #ifndef __GENKSYMS__ unsigned long *user_ro_bitmap; atomic64_t sync_io_sectors; /* RAID */ + unsigned long state; #else KABI_RESERVE(1) KABI_RESERVE(2) -#endif KABI_RESERVE(3) +#endif KABI_RESERVE(4) };