On Mon, Sep 07, 2026 at 01:07:45PM +0200, Niklas Cassel wrote:
> The max_append_sectors field of virtio_blk_zoned_characteristics must be
> set by the device to the largest zone append request that can be issued
> to it, and a value of zero tells the guest driver that zone append is not
> supported at all (virtio 1.4, 5.2.5.2). Linux refuses to attach a zoned
> device that reports zero.
> 
> We pass BlockLimits.max_append_sectors straight through, which makes that
> field mean "zone append unsupported" when it is unset, rather than "this
> backend imposes no limit of its own". Only a backend that has a limit of
> its own has anything to put there.
> 
> Derive the value instead. A backend limit is honoured when there is one,
> and otherwise the request is bounded by the zone size, since an append
> cannot cross a zone boundary, and by the largest request the block layer
> can carry. The result cannot be zero.
> 
> A backend that carries out an append itself, rather than passing it to a
> device that has a limit of its own, is the one that knows how large a
> request its implementation can take, so it reports that in
> BlockLimits.max_append_sectors and this does not have to guess at it.
> 
> Reviewed-by: Damien Le Moal <[email protected]>
> Signed-off-by: Niklas Cassel <[email protected]>
> ---
>  hw/block/virtio-blk.c | 31 ++++++++++++++++++++++++-------
>  1 file changed, 24 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index c2acf59c6d..131516a167 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -525,6 +525,27 @@ typedef struct ZoneCmdData {
>      };
>  } ZoneCmdData;
>  
> +/*
> + * The maximum zone append data size that the device reports to the driver in
> + * virtio_blk_zoned_characteristics, in 512 byte sectors.
> + *
> + * A backend that has no limit of its own leaves 
> BlockLimits.max_append_sectors
> + * at zero, in which case the limit is whatever else bounds the request: an
> + * append cannot cross a zone boundary, and the block layer cannot carry a
> + * larger one. The result is never zero, which the driver would read as zone
> + * append not being supported at all.
> + */
> +static uint32_t virtio_blk_max_append_sectors(VirtIOBlock *s)
> +{
> +    BlockDriverState *bs = blk_bs(s->blk);
> +    uint64_t sectors;
> +
> +    sectors = MIN_NON_ZERO(bs->bl.zone_size >> BDRV_SECTOR_BITS,
> +                           bs->bl.max_append_sectors);
> +
> +    return MIN_NON_ZERO(sectors, BDRV_REQUEST_MAX_SECTORS);
> +}
> +
>  /*
>   * check zoned_request: error checking before issuing requests. If all checks
>   * passed, return true.
> @@ -560,12 +581,8 @@ static bool check_zoned_request(VirtIOBlock *s, int64_t 
> offset, int64_t len,
>              return false;
>          }
>  
> -        if (len / 512 > bs->bl.max_append_sectors) {
> -            if (bs->bl.max_append_sectors == 0) {
> -                *status = VIRTIO_BLK_S_UNSUPP;
> -            } else {
> -                *status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> -            }
> +        if ((len >> BDRV_SECTOR_BITS) > virtio_blk_max_append_sectors(s)) {
> +            *status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
>              return false;
>          }
>      }
> @@ -1313,7 +1330,7 @@ static void virtio_blk_update_config(VirtIODevice 
> *vdev, uint8_t *config)
>          virtio_stl_p(vdev, &blkcfg.zoned.write_granularity,
>                       blkconf_zone_write_granularity(conf));
>          virtio_stl_p(vdev, &blkcfg.zoned.max_append_sectors,
> -                     bs->bl.max_append_sectors);
> +                     virtio_blk_max_append_sectors(s));

This has the same issue as the write_granularity patch earlier in this
patch series, except that max_append_sectors was already exposing the
BlockBackends BlockLimits, which we shouldn't do.

>      } else {
>          blkcfg.zoned.model = VIRTIO_BLK_Z_NONE;
>      }
> -- 
> 2.55.0
> 

Attachment: signature.asc
Description: PGP signature

Reply via email to