From 731dc4868311ee097757b8746eaa1b4f8b2b4f1c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 21 Oct 2019 10:37:59 +0200 Subject: bdev: Factor out bdev revalidation into a common helper Factor out code handling revalidation of bdev on disk change into a common helper. Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index 9c073dbdc1b0..88c6d35ec71d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1512,6 +1512,14 @@ EXPORT_SYMBOL(bd_set_size); static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); +static void bdev_disk_changed(struct block_device *bdev, bool invalidate) +{ + if (invalidate) + invalidate_partitions(bdev->bd_disk, bdev); + else + rescan_partitions(bdev->bd_disk, bdev); +} + /* * bd_mutex locking: * @@ -1594,12 +1602,9 @@ 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 (!ret) - rescan_partitions(disk, bdev); - else if (ret == -ENOMEDIUM) - invalidate_partitions(disk, bdev); - } + if (bdev->bd_invalidated && + (!ret || ret == -ENOMEDIUM)) + bdev_disk_changed(bdev, ret == -ENOMEDIUM); if (ret) goto out_clear; @@ -1632,12 +1637,9 @@ 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 (!ret) - rescan_partitions(bdev->bd_disk, bdev); - else if (ret == -ENOMEDIUM) - invalidate_partitions(bdev->bd_disk, bdev); - } + if (bdev->bd_invalidated && + (!ret || ret == -ENOMEDIUM)) + bdev_disk_changed(bdev, ret == -ENOMEDIUM); if (ret) goto out_unlock_bdev; } -- cgit v1.2.3 From cba22d86e0a10b7070d2e6a7379dbea51aa0883c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 21 Oct 2019 10:38:00 +0200 Subject: bdev: Refresh bdev size for disks without partitioning Currently, block device size in not updated on second and further open for block devices where partition scan is disabled. This is particularly annoying for example for DVD drives as that means block device size does not get updated once the media is inserted into a drive if the device is already open when inserting the media. This is actually always the case for example when pktcdvd is in use. Fix the problem by revalidating block device size on every open even for devices with partition scan disabled. Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index 88c6d35ec71d..d612468ee66b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1403,11 +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 : ""); } - - if (!bdev->bd_disk) - return; - if (disk_part_scan_enabled(bdev->bd_disk)) - bdev->bd_invalidated = 1; + bdev->bd_invalidated = 1; } /** @@ -1514,10 +1510,15 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); static void bdev_disk_changed(struct block_device *bdev, bool invalidate) { - if (invalidate) - invalidate_partitions(bdev->bd_disk, bdev); - else - rescan_partitions(bdev->bd_disk, bdev); + if (disk_part_scan_enabled(bdev->bd_disk)) { + if (invalidate) + invalidate_partitions(bdev->bd_disk, bdev); + else + rescan_partitions(bdev->bd_disk, bdev); + } else { + check_disk_size_change(bdev->bd_disk, bdev, !invalidate); + bdev->bd_invalidated = 0; + } } /* -- cgit v1.2.3 From 6917d0689993f46d97d40dd66c601d0fd5b1dbdd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 14 Nov 2019 15:34:33 +0100 Subject: block: merge invalidate_partitions into rescan_partitions A lot of the logic in invalidate_partitions and rescan_partitions is shared. Merge the two functions to simplify things. There is a small behavior change in that we now send the kevent change notice also if we were not invalidating but no partitions were found, which seems like the right thing to do. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index d612468ee66b..0af62b76d031 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1511,10 +1511,7 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); static void bdev_disk_changed(struct block_device *bdev, bool invalidate) { if (disk_part_scan_enabled(bdev->bd_disk)) { - if (invalidate) - invalidate_partitions(bdev->bd_disk, bdev); - else - rescan_partitions(bdev->bd_disk, bdev); + rescan_partitions(bdev->bd_disk, bdev, invalidate); } else { check_disk_size_change(bdev->bd_disk, bdev, !invalidate); bdev->bd_invalidated = 0; -- cgit v1.2.3 From a1548b674403c0de70cc29a1575689917ba60157 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 14 Nov 2019 15:34:34 +0100 Subject: block: move rescan_partitions to fs/block_dev.c Large parts of rescan_partitions aren't about partitions, and moving it to block_dev.c will allow for some further cleanups by merging it into its only caller. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index 0af62b76d031..ec10dacd18d0 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1416,8 +1416,8 @@ static void flush_disk(struct block_device *bdev, bool kill_dirty) * and adjusts it if it differs. When shrinking the bdev size, its all caches * are freed. */ -void check_disk_size_change(struct gendisk *disk, struct block_device *bdev, - bool verbose) +static void check_disk_size_change(struct gendisk *disk, + struct block_device *bdev, bool verbose) { loff_t disk_size, bdev_size; @@ -1508,6 +1508,40 @@ EXPORT_SYMBOL(bd_set_size); static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); +static int rescan_partitions(struct gendisk *disk, struct block_device *bdev, + bool invalidate) +{ + int ret; + +rescan: + ret = blk_drop_partitions(disk, bdev); + if (ret) + return ret; + + if (invalidate) + set_capacity(disk, 0); + else if (disk->fops->revalidate_disk) + disk->fops->revalidate_disk(disk); + + check_disk_size_change(disk, bdev, !invalidate); + bdev->bd_invalidated = 0; + + if (!get_capacity(disk)) { + /* + * Tell userspace that the media / partition table may have + * changed. + */ + kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); + return 0; + } + + ret = blk_add_partitions(disk, bdev); + if (ret == -EAGAIN) + goto rescan; + return ret; +} + + static void bdev_disk_changed(struct block_device *bdev, bool invalidate) { if (disk_part_scan_enabled(bdev->bd_disk)) { -- cgit v1.2.3 From 142fe8f4bb169e8632024d51c64653a8bf140561 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 14 Nov 2019 15:34:35 +0100 Subject: block: fix bdev_disk_changed for non-partitioned devices We still have to set the capacity to 0 if invalidating or call revalidate_disk if not even if the disk has no partitions. Fix that by merging rescan_partitions into bdev_disk_changed and just stubbing out blk_add_partitions and blk_drop_partitions for non-partitioned devices. Signed-off-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index ec10dacd18d0..ae16466a67f7 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1508,9 +1508,9 @@ EXPORT_SYMBOL(bd_set_size); static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); -static int rescan_partitions(struct gendisk *disk, struct block_device *bdev, - bool invalidate) +int bdev_disk_changed(struct block_device *bdev, bool invalidate) { + struct gendisk *disk = bdev->bd_disk; int ret; rescan: @@ -1526,32 +1526,21 @@ rescan: check_disk_size_change(disk, bdev, !invalidate); bdev->bd_invalidated = 0; - if (!get_capacity(disk)) { + if (get_capacity(disk)) { + ret = blk_add_partitions(disk, bdev); + if (ret == -EAGAIN) + goto rescan; + } else { /* * Tell userspace that the media / partition table may have * changed. */ kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); - return 0; } - ret = blk_add_partitions(disk, bdev); - if (ret == -EAGAIN) - goto rescan; return ret; } - -static void bdev_disk_changed(struct block_device *bdev, bool invalidate) -{ - if (disk_part_scan_enabled(bdev->bd_disk)) { - rescan_partitions(bdev->bd_disk, bdev, invalidate); - } else { - check_disk_size_change(bdev->bd_disk, bdev, !invalidate); - bdev->bd_invalidated = 0; - } -} - /* * bd_mutex locking: * -- cgit v1.2.3 From f0b870df80bc70dad432fd0c142bb709a49964f5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 14 Nov 2019 15:34:36 +0100 Subject: block: remove (__)blkdev_reread_part as an exported API In general drivers should never mess with partition tables directly. Unfortunately s390 and loop do for somewhat historic reasons, but they can use bdev_disk_changed directly instead when we export it as they satisfy the sanity checks we have in __blkdev_reread_part. Signed-off-by: Christoph Hellwig Reviewed-by: Stefan Haberland [dasd] Reviewed-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index ae16466a67f7..9558a2f064b1 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1513,6 +1513,8 @@ int bdev_disk_changed(struct block_device *bdev, bool invalidate) struct gendisk *disk = bdev->bd_disk; int ret; + lockdep_assert_held(&bdev->bd_mutex); + rescan: ret = blk_drop_partitions(disk, bdev); if (ret) @@ -1540,6 +1542,11 @@ rescan: return ret; } +/* + * Only exported for for loop and dasd for historic reasons. Don't use in new + * code! + */ +EXPORT_SYMBOL_GPL(bdev_disk_changed); /* * bd_mutex locking: -- cgit v1.2.3 From 979c690d9a017db14b7759a099478e3faad991ac Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 14 Nov 2019 15:34:37 +0100 Subject: block: move clearing bd_invalidated into check_disk_size_change Both callers of check_disk_size_change clear bd_invalidate directly after the call, so move the clearing into check_disk_size_change itself. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- fs/block_dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/block_dev.c') diff --git a/fs/block_dev.c b/fs/block_dev.c index 9558a2f064b1..ee63c2732fa2 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1433,6 +1433,7 @@ static void check_disk_size_change(struct gendisk *disk, if (bdev_size > disk_size) flush_disk(bdev, false); } + bdev->bd_invalidated = 0; } /** @@ -1462,7 +1463,6 @@ int revalidate_disk(struct gendisk *disk) mutex_lock(&bdev->bd_mutex); check_disk_size_change(disk, bdev, ret == 0); - bdev->bd_invalidated = 0; mutex_unlock(&bdev->bd_mutex); bdput(bdev); } @@ -1526,7 +1526,6 @@ rescan: disk->fops->revalidate_disk(disk); check_disk_size_change(disk, bdev, !invalidate); - bdev->bd_invalidated = 0; if (get_capacity(disk)) { ret = blk_add_partitions(disk, bdev); -- cgit v1.2.3