The zoned block-device fields in the virtio-blk header are typed __virtio{32,64}, so their endianness follows VIRTIO_F_VERSION_1. The zoned feature is only defined for VIRTIO 1.x devices, and the virtio specification defines all of its fields as little-endian. Commit b16a1756c716 ("virtio_blk: mark all zone fields LE") tagged them __le* for exactly this reason, but commit f1ba4e674feb ("virtio-blk: fix to match virtio spec") re-applied the reviewed version of the original zoned series -- which predated b16a1756 -- and silently restored the __virtio* typing together with the matching virtio*_to_cpu() / virtio_cread() accessors in the driver. Restore the little-endian typing for the zoned configuration-space characteristics, the zone descriptor, the zone report header and the ZONE_APPEND in-header sector, and read them with le*_to_cpu() and virtio_cread_le() to match. There is no functional change on any spec-compliant device: zoned requires VIRTIO_F_VERSION_1, and for a VERSION_1 device virtio*_to_cpu() is identical to le*_to_cpu(). The change makes the uapi types describe the actual wire format and removes a latent endianness mismatch for a (non-conformant) legacy device on a big-endian guest. Fixes: f1ba4e674feb ("virtio-blk: fix to match virtio spec") Suggested-by: Michael S. Tsirkin Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito --- Testing: - Builds with no new warnings; sparse endian-clean (C=2, __CHECK_ENDIAN__, CONFIG_BLK_DEV_ZONED=y) both before and after. - Booted under QEMU with a host-managed zoned device exposed through virtio-blk. Zone revalidation, blkzone report and a sequential write / write-pointer check return correct values; blktests zbd device tests 001-006 (sysfs+ioctl, report zone, reset, write split, write ordering, revalidate) pass, with results identical before and after this change -- expected, since on a VIRTIO_F_VERSION_1 device virtio*_to_cpu() == le*_to_cpu(). drivers/block/virtio_blk.c | 38 +++++++++++++++------------------ include/uapi/linux/virtio_blk.h | 18 ++++++++-------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index b1c9a27fe00f3..5532cfbde7bfe 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -99,7 +99,7 @@ struct virtblk_req { * be the last byte. */ struct { - __virtio64 sector; + __le64 sector; u8 status; } zone_append; } in_hdr; @@ -335,14 +335,12 @@ static inline void virtblk_request_done(struct request *req) { struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); blk_status_t status = virtblk_result(virtblk_vbr_status(vbr)); - struct virtio_blk *vblk = req->mq_hctx->queue->queuedata; virtblk_unmap_data(req, vbr); virtblk_cleanup_cmd(req); if (req_op(req) == REQ_OP_ZONE_APPEND) - req->__sector = virtio64_to_cpu(vblk->vdev, - vbr->in_hdr.zone_append.sector); + req->__sector = le64_to_cpu(vbr->in_hdr.zone_append.sector); blk_mq_end_request(req, status); } @@ -589,13 +587,13 @@ static int virtblk_parse_zone(struct virtio_blk *vblk, { struct blk_zone zone = { }; - zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start); + zone.start = le64_to_cpu(entry->z_start); if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk)) zone.len = vblk->zone_sectors; else zone.len = get_capacity(vblk->disk) - zone.start; - zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap); - zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp); + zone.capacity = le64_to_cpu(entry->z_cap); + zone.wp = le64_to_cpu(entry->z_wp); switch (entry->z_type) { case VIRTIO_BLK_ZT_SWR: @@ -687,8 +685,7 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, if (ret) goto fail_report; - nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones), - nr_zones); + nz = min_t(u64, le64_to_cpu(report->nr_zones), nr_zones); if (!nz) break; @@ -698,8 +695,7 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, if (ret) goto fail_report; - sector = virtio64_to_cpu(vblk->vdev, - report->zones[i].z_start) + + sector = le64_to_cpu(report->zones[i].z_start) + vblk->zone_sectors; zone_idx++; } @@ -725,18 +721,18 @@ static int virtblk_read_zoned_limits(struct virtio_blk *vblk, lim->features |= BLK_FEAT_ZONED; - virtio_cread(vdev, struct virtio_blk_config, - zoned.max_open_zones, &v); + virtio_cread_le(vdev, struct virtio_blk_config, + zoned.max_open_zones, &v); lim->max_open_zones = v; dev_dbg(&vdev->dev, "max open zones = %u\n", v); - virtio_cread(vdev, struct virtio_blk_config, - zoned.max_active_zones, &v); + virtio_cread_le(vdev, struct virtio_blk_config, + zoned.max_active_zones, &v); lim->max_active_zones = v; dev_dbg(&vdev->dev, "max active zones = %u\n", v); - virtio_cread(vdev, struct virtio_blk_config, - zoned.write_granularity, &wg); + virtio_cread_le(vdev, struct virtio_blk_config, + zoned.write_granularity, &wg); if (!wg) { dev_warn(&vdev->dev, "zero write granularity reported\n"); return -ENODEV; @@ -750,8 +746,8 @@ static int virtblk_read_zoned_limits(struct virtio_blk *vblk, * virtio ZBD specification doesn't require zones to be a power of * two sectors in size, but the code in this driver expects that. */ - virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, - &vblk->zone_sectors); + virtio_cread_le(vdev, struct virtio_blk_config, zoned.zone_sectors, + &vblk->zone_sectors); if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) { dev_err(&vdev->dev, "zoned device with non power of two zone size %u\n", @@ -767,8 +763,8 @@ static int virtblk_read_zoned_limits(struct virtio_blk *vblk, lim->max_hw_discard_sectors = 0; } - virtio_cread(vdev, struct virtio_blk_config, - zoned.max_append_sectors, &v); + virtio_cread_le(vdev, struct virtio_blk_config, + zoned.max_append_sectors, &v); if (!v) { dev_warn(&vdev->dev, "zero max_append_sectors reported\n"); return -ENODEV; diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h index 3744e4da1b2a7..5af2a0300bb9d 100644 --- a/include/uapi/linux/virtio_blk.h +++ b/include/uapi/linux/virtio_blk.h @@ -140,11 +140,11 @@ struct virtio_blk_config { /* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */ struct virtio_blk_zoned_characteristics { - __virtio32 zone_sectors; - __virtio32 max_open_zones; - __virtio32 max_active_zones; - __virtio32 max_append_sectors; - __virtio32 write_granularity; + __le32 zone_sectors; + __le32 max_open_zones; + __le32 max_active_zones; + __le32 max_append_sectors; + __le32 write_granularity; __u8 model; __u8 unused2[3]; } zoned; @@ -241,11 +241,11 @@ struct virtio_blk_outhdr { */ struct virtio_blk_zone_descriptor { /* Zone capacity */ - __virtio64 z_cap; + __le64 z_cap; /* The starting sector of the zone */ - __virtio64 z_start; + __le64 z_start; /* Zone write pointer position in sectors */ - __virtio64 z_wp; + __le64 z_wp; /* Zone type */ __u8 z_type; /* Zone state */ @@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor { }; struct virtio_blk_zone_report { - __virtio64 nr_zones; + __le64 nr_zones; __u8 reserved[56]; struct virtio_blk_zone_descriptor zones[]; }; -- 2.53.0