The zone_append_max_bytes queue attribute is the largest REQ_OP_ZONE_APPEND that the device accepts, and Linux has no interface for issuing one from userspace: include/uapi has no such operation, and every submitter of REQ_OP_ZONE_APPEND is in the kernel. Userspace writes to a sequential zone with an ordinary write at the write pointer.
That is what this driver does. raw_co_zone_append() substitutes the write pointer of the zone for the offset and hands the request to raw_co_prw(), which reaches handle_aiocb_rw_vector() and issues a plain pwritev(). The kernel never sees a zone append, so the attribute describes a limit on an operation that is never issued. Nor is it a limit that this driver runs into. The kernel splits a write that exceeds the transfer limit rather than refusing it, so a larger append succeeds: on a null_blk device whose zone_append_max_bytes is 130560, a 16 MiB append completes and advances the write pointer by 16 MiB. Reporting the attribute only understates what the driver can do, because Linux derives it as a minimum that already includes max_sectors and chunk_sectors. Report max_hw_transfer instead, the limit that governs the write the driver actually issues. There is no use in telling a guest that it may append more than the device carries in one command, and a frontend then does not have to reason about how this driver implements an append in order to bound the value it advertises. On a null_blk device with max_hw_sectors_kb of 127 and zone_append_max_bytes of 130560, virtio-blk reports 255 sectors before and after. Signed-off-by: Niklas Cassel <[email protected]> --- block/file-posix.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index f267513a4e..e019cc3cd8 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1488,10 +1488,15 @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st, } bs->bl.nr_zones = ret; - ret = get_sysfs_long_val(st, "zone_append_max_bytes"); - if (ret > 0) { - bs->bl.max_append_sectors = ret >> BDRV_SECTOR_BITS; - } + /* + * raw_co_zone_append() carries out an append as an ordinary write at the + * write pointer, so the zone_append_max_bytes attribute, which bounds an + * operation that this driver never issues, does not apply. The kernel + * splits a write that is larger than the transfer limit rather than + * refusing it, but there is no use in telling a guest that it may append + * more than the device carries in one command. + */ + bs->bl.max_append_sectors = bs->bl.max_hw_transfer >> BDRV_SECTOR_BITS; ret = get_sysfs_long_val(st, "zone_write_granularity"); if (ret >= 0) { -- 2.55.0
