From b37ecc177ca439336acdf275d69a2bb3f87bec1f Mon Sep 17 00:00:00 2001
From: Pankaj Raghav
Date: Fri, 23 Sep 2022 19:36:08 +0200
Subject: [PATCH] BACKPORT: FROMLIST: block: allow blk-zoned devices to have
non-power-of-2 zone size
Checking if a given sector is aligned to a zone is a common
operation that is performed for zoned devices. Add
bdev_is_zone_start helper to check for this instead of opencoding it
everywhere.
Convert the calculations on zone size to be generic instead of relying on
power-of-2(po2) based arithmetic in the block layer using the helpers
wherever possible.
The only hot path affected by this change for zoned devices with po2
zone size is in blk_check_zone_append() but bdev_is_zone_start() helper is
used to optimize the calculation for po2 zone sizes.
Finally, allow zoned devices with non po2 zone sizes provided that their
zone capacity and zone size are equal. The main motivation to allow zoned
devices with non po2 zone size is to remove the unmapped LBA between
zone capcity and zone size for devices that cannot have a po2 zone
capacity.
Reviewed-by: Luis Chamberlain
Reviewed-by: Hannes Reinecke
Reviewed-by: Bart Van Assche
Reviewed-by: Johannes Thumshirn
Signed-off-by: Pankaj Raghav
Bug: 197782466
Bug: 269471019
Link: https://lore.kernel.org/linux-block/20220923173618.6899-4-p.raghav@samsung.com/
Change-Id: I2ecc186d7b14f5508b6abfe9821526d39a21d7e4
Signed-off-by: Bart Van Assche
---
block/blk-core.c | 2 +-
block/blk-zoned.c | 20 ++++++++++++++++----
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index ee1d9b6a80d8..335add80c2ec 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -771,7 +771,7 @@ static inline blk_status_t blk_check_zone_append(struct request_queue *q,
return BLK_STS_NOTSUPP;
/* The bio sector must point to the start of a sequential zone */
- if (pos & (blk_queue_zone_sectors(q) - 1) ||
+ if (!bdev_is_zone_start(bio->bi_bdev, pos) ||
!blk_queue_zone_is_seq(q, pos))
return BLK_STS_IOERR;
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index a435b56e26c7..534863a23154 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -483,14 +483,26 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
* smaller last zone.
*/
if (zone->start == 0) {
- if (zone->len == 0 || !is_power_of_2(zone->len)) {
- pr_warn("%s: Invalid zoned device with non power of two zone size (%llu)\n",
- disk->disk_name, zone->len);
+ if (zone->len == 0) {
+ pr_warn("%s: Invalid zero zone size", disk->disk_name);
+ return -ENODEV;
+ }
+
+ /*
+ * Non power-of-2 zone size support was added to remove the
+ * gap between zone capacity and zone size. Though it is technically
+ * possible to have gaps in a non power-of-2 device, Linux requires
+ * the zone size to be equal to zone capacity for non power-of-2
+ * zoned devices.
+ */
+ if (!is_power_of_2(zone->len) && zone->capacity < zone->len) {
+ pr_err("%s: Invalid zone capacity %lld with non power-of-2 zone size %lld",
+ disk->disk_name, zone->capacity, zone->len);
return -ENODEV;
}
args->zone_sectors = zone->len;
- args->nr_zones = (capacity + zone->len - 1) >> ilog2(zone->len);
+ args->nr_zones = div64_u64(capacity + zone->len - 1, zone->len);
} else if (zone->start + args->zone_sectors < capacity) {
if (zone->len != args->zone_sectors) {
pr_warn("%s: Invalid zoned device with non constant zone size\n",