Zone write pointers are tracked and reported in units of BDRV_SECTOR_SIZE, so an append whose data size is not a multiple of it would leave a write pointer that cannot be represented, neither in a BlockZoneDescriptor nor in the virtio and NVMe zone reports derived from one.
Nothing states that invariant. file-posix, the only driver that carries out an append itself, does enforce it, but only as a side effect of checking each iovec against BlockLimits.write_granularity, which is never smaller than the sector size. That conflates two constraints: the sector granularity holds for every driver, whereas write_granularity describes a coarser requirement of the medium below a driver, and only a driver that has such a medium should express it. Check the invariant once in bdrv_co_zone_append(), so that it no longer rests on a driver that happens to have a granularity of its own to report. This is a lower bound, not the alignment that a guest has to observe. The block layer cannot know that one, because it also depends on the logical block size the device is configured with, which is a property of the frontend. The alignment that applies to a guest is the larger of the two, and it is the frontend that reports it, that validates requests against it, and that has to refuse a device whose write pointers do not satisfy it. Signed-off-by: Niklas Cassel <[email protected]> --- block/io.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/block/io.c b/block/io.c index a916b236c3..705dc73d76 100644 --- a/block/io.c +++ b/block/io.c @@ -3350,6 +3350,16 @@ int coroutine_fn bdrv_co_zone_append(BlockDriverState *bs, int64_t *offset, return ret; } + /* + * Zone write pointers are kept and reported in units of BDRV_SECTOR_SIZE, + * so an append that would leave a write pointer at a finer granularity + * cannot be represented. Drivers may impose a coarser granularity of their + * own, see BlockLimits.write_granularity. + */ + if (!QEMU_IS_ALIGNED(qiov->size, BDRV_SECTOR_SIZE)) { + return -EINVAL; + } + bdrv_inc_in_flight(bs); if (!drv || !drv->bdrv_co_zone_append || bs->bl.zoned == BLK_Z_NONE) { co.ret = -ENOTSUP; -- 2.55.0
