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
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) {
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,
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)
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