diff --git a/block/blk-zoned.c b/block/blk-zoned.c index a0ce17e2143f..c5226bcaaa94 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -899,6 +899,19 @@ static int blkdev_report_zone_fallback(struct block_device *bdev, return blkdev_do_report_zones(bdev, sector, 1, &args); } +/* + * For devices that natively support zone append operations, we do not use zone + * write plugging for zone append writes, which makes the zone condition + * tracking invalid once zone append was used. In that case fall back to a + * regular report zones to get correct information. + */ +static inline bool blkdev_has_cached_report_zones(struct block_device *bdev) +{ + return disk_need_zone_resources(bdev->bd_disk) && + (bdev_emulates_zone_append(bdev) || + !test_bit(GD_ZONE_APPEND_USED, &bdev->bd_disk->state)); +} + /** * blkdev_get_zone_info - Get a single zone information from cached data * @bdev: Target block device @@ -932,6 +945,9 @@ int blkdev_get_zone_info(struct block_device *bdev, sector_t sector, memset(zone, 0, sizeof(*zone)); sector = ALIGN_DOWN(sector, zone_sectors); + if (!blkdev_has_cached_report_zones(bdev)) + return blkdev_report_zone_fallback(bdev, sector, zone); + rcu_read_lock(); zones_cond = rcu_dereference(disk->zones_cond); if (!disk->zone_wplugs_hash || !zones_cond) { @@ -1035,11 +1051,7 @@ int blkdev_report_zones_cached(struct block_device *bdev, sector_t sector, if (!nr_zones || sector >= capacity) return 0; - /* - * If we do not have any zone write plug resources, fallback to using - * the regular zone report. - */ - if (!disk_need_zone_resources(disk)) { + if (!blkdev_has_cached_report_zones(bdev)) { struct blk_report_zones_args args = { .cb = cb, .data = data, @@ -1115,6 +1127,7 @@ static void blk_zone_reset_all_bio_endio(struct bio *bio) for (sector = 0; sector < capacity; sector += bdev_zone_sectors(bio->bi_bdev)) disk_zone_set_cond(disk, sector, BLK_ZONE_COND_EMPTY); + clear_bit(GD_ZONE_APPEND_USED, &disk->state); } static void blk_zone_finish_bio_endio(struct bio *bio) @@ -1474,6 +1487,9 @@ static void blk_zone_wplug_handle_native_zone_append(struct bio *bio) struct blk_zone_wplug *zwplug; unsigned long flags; + if (!test_bit(GD_ZONE_APPEND_USED, &disk->state)) + set_bit(GD_ZONE_APPEND_USED, &disk->state); + /* * We have native support for zone append operations, so we are not * going to handle @bio through plugging. However, we may already have a diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f0ab02e0a673..6a498aa7f7e7 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -173,6 +173,7 @@ struct gendisk { #define GD_ADDED 4 #define GD_SUPPRESS_PART_SCAN 5 #define GD_OWNS_QUEUE 6 +#define GD_ZONE_APPEND_USED 7 struct mutex open_mutex; /* open/close mutex */ unsigned open_partitions; /* number of open partitions */