On Thu, May 30, 2024 at 02:40:33PM +0900, Damien Le Moal wrote:
> Commit ecfe43b11b02 ("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: ecfe43b11b02 ("block: Remember zone capacity when revalidating zones")
> Signed-off-by: Damien Le Moal <[email protected]>
> ---
>  block/blk-zoned.c | 16 +++++++++++-----
>  1 file changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/block/blk-zoned.c b/block/blk-zoned.c
> index 03aa4eead39e..402a50a1ac4d 100644
> --- a/block/blk-zoned.c
> +++ b/block/blk-zoned.c
> @@ -450,6 +450,11 @@ static inline bool disk_zone_is_conv(struct gendisk 
> *disk, sector_t sector)
>       return test_bit(disk_zone_no(disk, sector), disk->conv_zones_bitmap);
>  }
>  
> +static bool disk_zone_is_last(struct gendisk *disk, struct blk_zone *zone)
> +{
> +     return zone->start + zone->len >= get_capacity(disk);
> +}
> +
>  static bool disk_insert_zone_wplug(struct gendisk *disk,
>                                  struct blk_zone_wplug *zwplug)
>  {
> @@ -1693,11 +1698,13 @@ static int blk_revalidate_seq_zone(struct blk_zone 
> *zone, unsigned int idx,
>  
>       /*
>        * Remember the capacity of the first sequential zone and check
> -      * if it is constant for all zones.
> +      * if it is constant for all zones, ignoring the last zone as it can be
> +      * smaller.
>        */
>       if (!args->zone_capacity)
>               args->zone_capacity = zone->capacity;
> -     if (zone->capacity != args->zone_capacity) {
> +     if (!disk_zone_is_last(disk, zone) &&
> +         zone->capacity != args->zone_capacity) {
>               pr_warn("%s: Invalid variable zone capacity\n",
>                       disk->disk_name);
>               return -ENODEV;
> @@ -1732,7 +1739,6 @@ static int blk_revalidate_zone_cb(struct blk_zone 
> *zone, unsigned int idx,
>  {
>       struct blk_revalidate_zone_args *args = data;
>       struct gendisk *disk = args->disk;
> -     sector_t capacity = get_capacity(disk);
>       sector_t zone_sectors = disk->queue->limits.chunk_sectors;
>       int ret;
>  
> @@ -1743,7 +1749,7 @@ static int blk_revalidate_zone_cb(struct blk_zone 
> *zone, unsigned int idx,
>               return -ENODEV;
>       }
>  
> -     if (zone->start >= capacity || !zone->len) {
> +     if (zone->start >= get_capacity(disk) || !zone->len) {
>               pr_warn("%s: Invalid zone start %llu, length %llu\n",
>                       disk->disk_name, zone->start, zone->len);
>               return -ENODEV;
> @@ -1753,7 +1759,7 @@ static int blk_revalidate_zone_cb(struct blk_zone 
> *zone, unsigned int idx,
>        * All zones must have the same size, with the exception on an eventual
>        * smaller last zone.
>        */
> -     if (zone->start + zone->len < capacity) {
> +     if (!disk_zone_is_last(disk, zone)) {
>               if (zone->len != zone_sectors) {
>                       pr_warn("%s: Invalid zoned device with non constant 
> zone size\n",
>                               disk->disk_name);
> -- 
> 2.45.1
> 

Reviewed-by: Niklas Cassel <[email protected]>

Reply via email to