Message ID | 20220516165416.171196-3-p.raghav@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v4,01/13] block: make blkdev_nr_zones and blk_queue_zone_no generic for npo2 zsze | expand |
Hi Damien, I copied your comments from the previous thread to avoid confusion. On 2022-05-16 16:00, Damien Le Moal wrote: > On 2022/05/16 15:39, Pankaj Raghav wrote: >> Checking if a given sector is aligned to a zone is a common >> operation that is performed for zoned devices. Add >> blk_queue_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 based logic in the block layer using the helpers wherever >> possible. >> >> @@ -490,14 +490,29 @@ 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 zone size", >> + disk->disk_name); > > This fits on one line, no ? > Yeah. I don't know why my formatter decided to do that. I will fix it. Thanks. >> + return -ENODEV; >> + } >> + >> + /* >> + * Don't allow zoned device with non power_of_2 zone size with >> + * zone capacity less than zone size. >> + */ >> + if (!is_power_of_2(zone->len) && >> + zone->capacity < zone->len) { >> + pr_warn("%s: Invalid zoned size with non power of 2 zone size and zone capacity < zone size", >> + disk->disk_name); > > Very long... What about: > > pr_warn("%s: Invalid zone capacity for non power of 2 zone size", > disk->disk_name); > This looks better. I will fix it up! >> return -ENODEV; >> } >> >> args->zone_sectors = zone->len; >> - args->nr_zones = (capacity + zone->len - 1) >> ilog2(zone->len); >> + /* >> + * Division is used to calculate nr_zones for both power_of_2 >> + * and non power_of_2 zone sizes as it is not in the hot path. >> + */ > > This comment is not very useful. > I also saw you mentioning the comment was not useful in nvme code for a similar scenario. Hannes brought up a point about making it explicit when we are not using any special path for power of 2 zone sizes as in most cases we do branching if the zone size is power of 2 to avoid division. >> + 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", >> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h >> index 22fe512ee..32d7bd7b1 100644 >> --- a/include/linux/blkdev.h >> +++ b/include/linux/blkdev.h >> @@ -686,6 +686,22 @@ static inline unsigned int blk_queue_zone_no(struct request_queue *q, >> return div64_u64(sector, zone_sectors); >> } >> >> +static inline bool blk_queue_is_zone_start(struct request_queue *q, sector_t sec) >> +{ >> + sector_t zone_sectors = blk_queue_zone_sectors(q); >> + u64 remainder = 0; >> + >> + if (!blk_queue_is_zoned(q)) >> + return false; >> + >> + if (is_power_of_2(zone_sectors)) >> + return IS_ALIGNED(sec, zone_sectors); >> + >> + div64_u64_rem(sec, zone_sectors, &remainder); >> + /* if there is a remainder, then the sector is not aligned */ > > Hmmm... Fairly obvious. Not sure this comment is useful. > True. I will remove it. >> + return remainder == 0; >> +} >> + >> static inline bool blk_queue_zone_is_seq(struct request_queue *q, >> sector_t sector) >> { >> @@ -732,6 +748,12 @@ static inline unsigned int blk_queue_zone_no(struct request_queue *q, >> { >> return 0; >> } >> + >> +static inline bool blk_queue_is_zone_start(struct request_queue *q, sector_t sec) >> +{ >> + return false; >> +} >> + >> static inline unsigned int queue_max_open_zones(const struct request_queue *q) >> { >> return 0; > >
diff --git a/block/blk-core.c b/block/blk-core.c index f305cb66c..b7051b7ea 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -634,8 +634,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) || - !blk_queue_zone_is_seq(q, pos)) + if (!blk_queue_is_zone_start(q, 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 140230134..cfc2fb804 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -289,10 +289,10 @@ int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op, return -EINVAL; /* Check alignment (handle eventual smaller last zone) */ - if (sector & (zone_sectors - 1)) + if (!blk_queue_is_zone_start(q, sector)) return -EINVAL; - if ((nr_sectors & (zone_sectors - 1)) && end_sector != capacity) + if (!blk_queue_is_zone_start(q, nr_sectors) && end_sector != capacity) return -EINVAL; /* @@ -490,14 +490,29 @@ 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 zone size", + disk->disk_name); + return -ENODEV; + } + + /* + * Don't allow zoned device with non power_of_2 zone size with + * zone capacity less than zone size. + */ + if (!is_power_of_2(zone->len) && + zone->capacity < zone->len) { + pr_warn("%s: Invalid zoned size with non power of 2 zone size and zone capacity < zone size", + disk->disk_name); return -ENODEV; } args->zone_sectors = zone->len; - args->nr_zones = (capacity + zone->len - 1) >> ilog2(zone->len); + /* + * Division is used to calculate nr_zones for both power_of_2 + * and non power_of_2 zone sizes as it is not in the hot path. + */ + 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", diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 22fe512ee..32d7bd7b1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -686,6 +686,22 @@ static inline unsigned int blk_queue_zone_no(struct request_queue *q, return div64_u64(sector, zone_sectors); } +static inline bool blk_queue_is_zone_start(struct request_queue *q, sector_t sec) +{ + sector_t zone_sectors = blk_queue_zone_sectors(q); + u64 remainder = 0; + + if (!blk_queue_is_zoned(q)) + return false; + + if (is_power_of_2(zone_sectors)) + return IS_ALIGNED(sec, zone_sectors); + + div64_u64_rem(sec, zone_sectors, &remainder); + /* if there is a remainder, then the sector is not aligned */ + return remainder == 0; +} + static inline bool blk_queue_zone_is_seq(struct request_queue *q, sector_t sector) { @@ -732,6 +748,12 @@ static inline unsigned int blk_queue_zone_no(struct request_queue *q, { return 0; } + +static inline bool blk_queue_is_zone_start(struct request_queue *q, sector_t sec) +{ + return false; +} + static inline unsigned int queue_max_open_zones(const struct request_queue *q) { return 0;