The helper function blk_zone_wp_offset() is called from disk_zone_wplug_sync_wp_offset(), and again called from blk_revalidate_seq_zone() right after the call to disk_zone_wplug_sync_wp_offset(). Change disk_zone_wplug_sync_wp_offset() to return the wp_offset it used for updating the target zone write plug to avoid this double call. With this change, blk_zone_wp_offset() can be open coded directly in disk_zone_wplug_sync_wp_offset(). This open-coding introduces 2 changes: handle the BLK_COND_ZONE_ACTIVE case, and return UINT_MAX as the wp_offset for a full zone, since the write pointer of full zones is invalid. For the case where a zone does not have a zone write plug, disk_zone_wplug_sync_wp_offset() does nothing and returns 0. This in turn leads to blk_revalidate_seq_zone() to immediately return, which is exactly what we want (because there is no need to attempt removing a zone write plug that does not exist). Signed-off-by: Damien Le Moal --- block/blk-zoned.c | 64 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index c5226bcaaa94..2f4e45638601 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -794,46 +794,48 @@ static void disk_zone_wplug_set_wp_offset(struct gendisk *disk, disk_remove_zone_wplug(disk, zwplug); } -static unsigned int blk_zone_wp_offset(struct blk_zone *zone) -{ - switch (zone->cond) { - case BLK_ZONE_COND_IMP_OPEN: - case BLK_ZONE_COND_EXP_OPEN: - case BLK_ZONE_COND_CLOSED: - return zone->wp - zone->start; - case BLK_ZONE_COND_FULL: - return zone->len; - case BLK_ZONE_COND_EMPTY: - return 0; - case BLK_ZONE_COND_NOT_WP: - case BLK_ZONE_COND_OFFLINE: - case BLK_ZONE_COND_READONLY: - default: - /* - * Conventional, offline and read-only zones do not have a valid - * write pointer. - */ - return UINT_MAX; - } -} - -static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk, - struct blk_zone *zone) +static unsigned int disk_zone_wplug_sync_wp_offset(struct gendisk *disk, + struct blk_zone *zone) { struct blk_zone_wplug *zwplug; unsigned long flags; + unsigned int wp_offset; zwplug = disk_get_zone_wplug(disk, zone->start); if (!zwplug) - return; + return 0; spin_lock_irqsave(&zwplug->lock, flags); - if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE) - disk_zone_wplug_set_wp_offset(disk, zwplug, - blk_zone_wp_offset(zone)); + if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE) { + switch (zone->cond) { + case BLK_ZONE_COND_IMP_OPEN: + case BLK_ZONE_COND_EXP_OPEN: + case BLK_ZONE_COND_CLOSED: + case BLK_ZONE_COND_ACTIVE: + wp_offset = zone->wp - zone->start; + break; + case BLK_ZONE_COND_EMPTY: + wp_offset = 0; + break; + case BLK_ZONE_COND_FULL: + case BLK_ZONE_COND_NOT_WP: + case BLK_ZONE_COND_OFFLINE: + case BLK_ZONE_COND_READONLY: + default: + /* + * Conventional, full, offline and read-only zones do + * not have a valid write pointer. + */ + wp_offset = UINT_MAX; + break; + } + disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset); + } spin_unlock_irqrestore(&zwplug->lock, flags); disk_put_zone_wplug(zwplug); + + return wp_offset; } /** @@ -2095,9 +2097,7 @@ static int blk_revalidate_seq_zone(struct blk_zone *zone, unsigned int idx, if (!queue_emulates_zone_append(disk->queue) || !disk->zone_wplugs_hash) return 0; - disk_zone_wplug_sync_wp_offset(disk, zone); - - wp_offset = blk_zone_wp_offset(zone); + wp_offset = disk_zone_wplug_sync_wp_offset(disk, zone); if (!wp_offset || wp_offset >= zone->capacity) return 0; -- 2.51.1 Introduce the function bdev_zone_start() as a more explicit (and clear) replacement for ALIGN_DOWN() to get the start sector of a zone containing a particular sector of a zoned block device. Use this new helper in blkdev_get_zone_info() and blkdev_report_zones_cached(). Signed-off-by: Damien Le Moal --- block/blk-zoned.c | 4 ++-- include/linux/blkdev.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 2f4e45638601..e7e5542c538e 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -945,7 +945,7 @@ int blkdev_get_zone_info(struct block_device *bdev, sector_t sector, return -EINVAL; memset(zone, 0, sizeof(*zone)); - sector = ALIGN_DOWN(sector, zone_sectors); + sector = bdev_zone_start(bdev, sector); if (!blkdev_has_cached_report_zones(bdev)) return blkdev_report_zone_fallback(bdev, sector, zone); @@ -1063,7 +1063,7 @@ int blkdev_report_zones_cached(struct block_device *bdev, sector_t sector, return blkdev_do_report_zones(bdev, sector, nr_zones, &args); } - for (sector = ALIGN_DOWN(sector, zone_sectors); + for (sector = bdev_zone_start(bdev, sector); sector < capacity && idx < nr_zones; sector += zone_sectors, idx++) { ret = blkdev_get_zone_info(bdev, sector, &zone); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6a498aa7f7e7..2fff8a80dbd2 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1522,6 +1522,12 @@ static inline sector_t bdev_zone_sectors(struct block_device *bdev) return q->limits.chunk_sectors; } +static inline sector_t bdev_zone_start(struct block_device *bdev, + sector_t sector) +{ + return sector & ~(bdev_zone_sectors(bdev) - 1); +} + static inline sector_t bdev_offset_from_zone_start(struct block_device *bdev, sector_t sector) { -- 2.51.1