Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit cd63999

Browse files
damien-lemoalaxboe
authored andcommitted
block: Fix validation of zoned device with a runt zone
Commit ecfe43b ("block: Remember zone capacity when revalidating zones") introduced checks to ensure that the capacity of the zones of a zoned device is constant for all zones. However, this check ignores the possibility that a zoned device has a smaller last zone with a size not equal to the capacity of other zones. Such device correspond in practice to an SMR drive with a smaller last zone and all zones with a capacity equal to the zone size, leading to the last zone capacity being different than the capacity of other zones. Correctly handle such device by fixing the check for the constant zone capacity in blk_revalidate_seq_zone() using the new helper function disk_zone_is_last(). This helper function is also used in blk_revalidate_zone_cb() when checking the zone size. Fixes: ecfe43b ("block: Remember zone capacity when revalidating zones") Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Niklas Cassel <cassel@kernel.org> Link: https://lore.kernel.org/r/20240530054035.491497-3-dlemoal@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent b164316 commit cd63999

File tree

1 file changed

+11
-5
lines changed

1 file changed

+11
-5
lines changed

block/blk-zoned.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,11 @@ static inline bool disk_zone_is_conv(struct gendisk *disk, sector_t sector)
450450
return test_bit(disk_zone_no(disk, sector), disk->conv_zones_bitmap);
451451
}
452452

453+
static bool disk_zone_is_last(struct gendisk *disk, struct blk_zone *zone)
454+
{
455+
return zone->start + zone->len >= get_capacity(disk);
456+
}
457+
453458
static bool disk_insert_zone_wplug(struct gendisk *disk,
454459
struct blk_zone_wplug *zwplug)
455460
{
@@ -1693,11 +1698,13 @@ static int blk_revalidate_seq_zone(struct blk_zone *zone, unsigned int idx,
16931698

16941699
/*
16951700
* Remember the capacity of the first sequential zone and check
1696-
* if it is constant for all zones.
1701+
* if it is constant for all zones, ignoring the last zone as it can be
1702+
* smaller.
16971703
*/
16981704
if (!args->zone_capacity)
16991705
args->zone_capacity = zone->capacity;
1700-
if (zone->capacity != args->zone_capacity) {
1706+
if (!disk_zone_is_last(disk, zone) &&
1707+
zone->capacity != args->zone_capacity) {
17011708
pr_warn("%s: Invalid variable zone capacity\n",
17021709
disk->disk_name);
17031710
return -ENODEV;
@@ -1732,7 +1739,6 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
17321739
{
17331740
struct blk_revalidate_zone_args *args = data;
17341741
struct gendisk *disk = args->disk;
1735-
sector_t capacity = get_capacity(disk);
17361742
sector_t zone_sectors = disk->queue->limits.chunk_sectors;
17371743
int ret;
17381744

@@ -1743,7 +1749,7 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
17431749
return -ENODEV;
17441750
}
17451751

1746-
if (zone->start >= capacity || !zone->len) {
1752+
if (zone->start >= get_capacity(disk) || !zone->len) {
17471753
pr_warn("%s: Invalid zone start %llu, length %llu\n",
17481754
disk->disk_name, zone->start, zone->len);
17491755
return -ENODEV;
@@ -1753,7 +1759,7 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
17531759
* All zones must have the same size, with the exception on an eventual
17541760
* smaller last zone.
17551761
*/
1756-
if (zone->start + zone->len < capacity) {
1762+
if (!disk_zone_is_last(disk, zone)) {
17571763
if (zone->len != zone_sectors) {
17581764
pr_warn("%s: Invalid zoned device with non constant zone size\n",
17591765
disk->disk_name);

0 commit comments

Comments
 (0)