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
>
signature.asc
Description: PGP signature
