summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Le Moal <dlemoal@kernel.org>2026-09-08 17:57:31 +0900
committerJens Axboe <axboe@kernel.dk>2026-09-15 06:53:06 -0600
commit496b9748884cf8b1c656a69eadc9f9f7eb84eb4e (patch)
treed22e84f971f675f95352c683c10fd3fa9475431f
parent73ef8afbe8c9a53c2f42811f9f2a7f862647d180 (diff)
downloadlinux-next-496b9748884cf8b1c656a69eadc9f9f7eb84eb4e.tar.gz
linux-next-496b9748884cf8b1c656a69eadc9f9f7eb84eb4e.zip
block: improve capacity handling during zone revalidation
While executing blk_revalidate_disk_zones(), a disk capacity is looked at using get_capacity() several times: on entry to blk_revalidate_disk_zones(), when allocating zone revalidation arguments in disk_revalidate_zone_resources(), while validating zones in blk_revalidate_zone_cb() and one last time at the end of blk_revalidate_disk_zones() to check that all zones have been inspected. Since this is all done while passthrough commands can be issued, it is possible that a capacity change operation (e.g. the removal of a storage element on a SCSI or SATA disk) is concurrently executed, potentially resulting in an inconsistent or conflicting revalidation with potentially out-of-bound accesses to the zone condition array. Prevent issues by using get_capacity() once on entry to blk_revalidate_disk_zones(), remembering this capacity as a field of struct blk_revalidate_zone_args and using that field while revalidating zones. A final second call to get_capacity() is done at the end of blk_revalidate_disk_zones() to ensure that the disk capacity has not changed, thus revalidating the capacity (and number of zones) itself. Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Hannes Reinecke <hare@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/20260908085745.1082697-3-dlemoal@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--block/blk-zoned.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index c7d8c767bb31..8b3b5c7bfd03 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -1993,6 +1993,7 @@ void disk_release_zone_resources(struct gendisk *disk)
struct blk_revalidate_zone_args {
struct gendisk *disk;
+ sector_t capacity;
u8 *zones_cond;
unsigned int nr_zones;
unsigned int nr_conv_zones;
@@ -2010,7 +2011,7 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
args->disk = disk;
args->nr_zones =
- DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
+ DIV_ROUND_UP_ULL(args->capacity, lim->chunk_sectors);
/* Cached zone conditions: 1 byte per zone */
args->zones_cond = kzalloc(args->nr_zones, GFP_NOIO);
@@ -2231,7 +2232,7 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
return -ENODEV;
}
- if (zone->start >= get_capacity(disk) || !zone->len) {
+ if (zone->start >= args->capacity || !zone->len) {
pr_warn("%s: Invalid zone start %llu, length %llu\n",
disk->disk_name, zone->start, zone->len);
return -ENODEV;
@@ -2302,8 +2303,9 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
{
struct request_queue *q = disk->queue;
sector_t zone_sectors = q->limits.chunk_sectors;
- sector_t capacity = get_capacity(disk);
- struct blk_revalidate_zone_args args = { };
+ struct blk_revalidate_zone_args args = {
+ .capacity = get_capacity(disk),
+ };
struct blk_report_zones_args rep_args = {
.cb = blk_revalidate_zone_cb,
.data = &args,
@@ -2314,7 +2316,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
return -EIO;
- if (!capacity)
+ if (!args.capacity)
return -ENODEV;
/*
@@ -2352,7 +2354,12 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
* If zones where reported, make sure that the entire disk capacity
* has been checked.
*/
- if (args.sector != capacity) {
+ if (args.capacity != get_capacity(disk)) {
+ pr_warn("%s: Capacity has changed\n", disk->disk_name);
+ ret = -ENODEV;
+ goto free_args;
+ }
+ if (args.sector != args.capacity) {
pr_warn("%s: Missing zones from sector %llu\n",
disk->disk_name, args.sector);
ret = -ENODEV;