Re: [RFC v3 2/2] virtio-blk: add zoned storage emulation for zoned devices

2022-10-24 Thread Dmitry Fomichev
On Tue, 2022-10-18 at 16:56 +0800, Sam Li wrote:
> Dmitry Fomichev  于2022年10月17日周一 09:01写道:
> > 
> > On Sun, 2022-10-16 at 23:05 +0800, Sam Li wrote:
> > > This patch extends virtio-blk emulation to handle zoned device commands
> > > by calling the new block layer APIs to perform zoned device I/O on
> > > behalf of the guest. It supports Report Zone, four zone oparations (open,
> > > close, finish, reset), and Append Zone.
> > > 
> > > The VIRTIO_BLK_F_ZONED feature bit will only be set if the host does
> > > support zoned block devices. Regular block devices(conventional zones)
> > > will not be set.
> > > 
> > > Then the guest os can use blkzone(8) to test those commands on zoned
> > > devices.
> > > Furthermore, using zonefs to test zone append write is also supported.
> > > 
> > > Signed-off-by: Sam Li 
> > > ---
> > >  hw/block/virtio-blk-common.c   |   2 +
> > >  hw/block/virtio-blk.c  | 412 -
> > >  include/hw/virtio/virtio-blk.h |  11 +-
> > >  3 files changed, 422 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c
> > > index ac52d7c176..e2f8e2f6da 100644
> > > --- a/hw/block/virtio-blk-common.c
> > > +++ b/hw/block/virtio-blk-common.c
> > > @@ -29,6 +29,8 @@ static const VirtIOFeature feature_sizes[] = {
> > >   .end = endof(struct virtio_blk_config, discard_sector_alignment)},
> > >  {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
> > >   .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
> > > +    {.flags = 1ULL << VIRTIO_BLK_F_ZONED,
> > > + .end = endof(struct virtio_blk_config, zoned)},
> > >  {}
> > >  };
> > > 
> > > diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> > > index 8131ec2dbc..58891aea31 100644
> > > --- a/hw/block/virtio-blk.c
> > > +++ b/hw/block/virtio-blk.c
> > > @@ -26,6 +26,9 @@
> > >  #include "hw/virtio/virtio-blk.h"
> > >  #include "dataplane/virtio-blk.h"
> > >  #include "scsi/constants.h"
> > > +#if defined(CONFIG_BLKZONED)
> > > +#include 
> > > +#endif
> > >  #ifdef __linux__
> > >  # include 
> > >  #endif
> > > @@ -55,10 +58,29 @@ static void virtio_blk_req_complete(VirtIOBlockReq
> > > *req,
> > > unsigned char status)
> > >  {
> > >  VirtIOBlock *s = req->dev;
> > >  VirtIODevice *vdev = VIRTIO_DEVICE(s);
> > > +    int64_t inhdr_len, n;
> > > +    void *buf;
> > > 
> > >  trace_virtio_blk_req_complete(vdev, req, status);
> > > 
> > > -    stb_p(>in->status, status);
> > > +    iov_discard_undo(>inhdr_undo);
> > > +    if (virtio_ldl_p(vdev, >out.type) == VIRTIO_BLK_T_ZONE_APPEND) {
> > > +    inhdr_len = sizeof(struct virtio_blk_zone_append_inhdr);
> > > +    req->in.in_hdr->status = status;
> > > +    buf = req->in.in_hdr;
> > > +    } else {
> > > +    inhdr_len = sizeof(struct virtio_blk_inhdr);
> > > +    req->in.zone_append_inhdr->status = status;
> > > +    buf = req->in.zone_append_inhdr;
> > > +    }
> > > +
> > > +    n = iov_from_buf(req->elem.in_sg, req->elem.in_num,
> > > + req->in_len - inhdr_len, buf, inhdr_len);
> > > +    if (n != inhdr_len) {
> > > +    virtio_error(vdev, "Driver provided input buffer less than size 
> > > of
> > > "
> > > + "in header");
> > > +    }
> > > +
> > >  iov_discard_undo(>inhdr_undo);
> > >  iov_discard_undo(>outhdr_undo);
> > >  virtqueue_push(req->vq, >elem, req->in_len);
> > > @@ -592,6 +614,334 @@ err:
> > >  return err_status;
> > >  }
> > > 
> > > +typedef struct ZoneCmdData {
> > > +    VirtIOBlockReq *req;
> > > +    union {
> > > +    struct {
> > > +    unsigned int nr_zones;
> > > +    BlockZoneDescriptor *zones;
> > > +    } zone_report_data;
> > > +    struct {
> > > +    int64_t offset;
> > > +    } zone_append_data;
> > > +    };
> > > +} ZoneCmdData;
> > > +
> > > +/*
> > > + * check zoned_request: error checking before issuing requests. If all
> > > checks
> > > + * passed, return true.
> > > + * append: true if only zone append requests issued.
> > > + */
> > > +static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t
> > > len,
> > > + bool append, uint8_t *status) {
> > > +    BlockDriverState *bs = blk_bs(s->blk);
> > > +    int index = offset / bs->bl.zone_size;
> > > +
> > > +    if (offset < 0 || len < 0 || offset > bs->bl.capacity - len) {
> > > +    *status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> > > +    return false;
> > > +    }
> > > +
> > > +    if (!virtio_has_feature(s->host_features, VIRTIO_BLK_F_ZONED)) {
> > > +    *status = VIRTIO_BLK_S_UNSUPP;
> > > +    return false;
> > > +    }
> > > +
> > > +    if (append) {
> > > +    if ((offset % bs->bl.write_granularity) != 0) {
> > > +    *status = VIRTIO_BLK_S_ZONE_UNALIGNED_WP;
> > > +    return false;
> > > +    }
> > > +
> > > +    if 

Re: [RFC v3 2/2] virtio-blk: add zoned storage emulation for zoned devices

2022-10-23 Thread Sam Li
Dmitry Fomichev  于2022年10月23日周日 10:08写道:
>
> On Tue, 2022-10-18 at 16:56 +0800, Sam Li wrote:
> > Dmitry Fomichev  于2022年10月17日周一 09:01写道:
> > >
> > > On Sun, 2022-10-16 at 23:05 +0800, Sam Li wrote:
> > > > This patch extends virtio-blk emulation to handle zoned device commands
> > > > by calling the new block layer APIs to perform zoned device I/O on
> > > > behalf of the guest. It supports Report Zone, four zone oparations 
> > > > (open,
> > > > close, finish, reset), and Append Zone.
> > > >
> > > > The VIRTIO_BLK_F_ZONED feature bit will only be set if the host does
> > > > support zoned block devices. Regular block devices(conventional zones)
> > > > will not be set.
> > > >
> > > > Then the guest os can use blkzone(8) to test those commands on zoned
> > > > devices.
> > > > Furthermore, using zonefs to test zone append write is also supported.
> > > >
> > > > Signed-off-by: Sam Li 
> > > > ---
> > > >  hw/block/virtio-blk-common.c   |   2 +
> > > >  hw/block/virtio-blk.c  | 412 -
> > > >  include/hw/virtio/virtio-blk.h |  11 +-
> > > >  3 files changed, 422 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c
> > > > index ac52d7c176..e2f8e2f6da 100644
> > > > --- a/hw/block/virtio-blk-common.c
> > > > +++ b/hw/block/virtio-blk-common.c
> > > > @@ -29,6 +29,8 @@ static const VirtIOFeature feature_sizes[] = {
> > > >   .end = endof(struct virtio_blk_config, discard_sector_alignment)},
> > > >  {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
> > > >   .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
> > > > +{.flags = 1ULL << VIRTIO_BLK_F_ZONED,
> > > > + .end = endof(struct virtio_blk_config, zoned)},
> > > >  {}
> > > >  };
> > > >
> > > > diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> > > > index 8131ec2dbc..58891aea31 100644
> > > > --- a/hw/block/virtio-blk.c
> > > > +++ b/hw/block/virtio-blk.c
> > > > @@ -26,6 +26,9 @@
> > > >  #include "hw/virtio/virtio-blk.h"
> > > >  #include "dataplane/virtio-blk.h"
> > > >  #include "scsi/constants.h"
> > > > +#if defined(CONFIG_BLKZONED)
> > > > +#include 
> > > > +#endif
> > > >  #ifdef __linux__
> > > >  # include 
> > > >  #endif
> > > > @@ -55,10 +58,29 @@ static void virtio_blk_req_complete(VirtIOBlockReq
> > > > *req,
> > > > unsigned char status)
> > > >  {
> > > >  VirtIOBlock *s = req->dev;
> > > >  VirtIODevice *vdev = VIRTIO_DEVICE(s);
> > > > +int64_t inhdr_len, n;
> > > > +void *buf;
> > > >
> > > >  trace_virtio_blk_req_complete(vdev, req, status);
> > > >
> > > > -stb_p(>in->status, status);
> > > > +iov_discard_undo(>inhdr_undo);
> > > > +if (virtio_ldl_p(vdev, >out.type) == 
> > > > VIRTIO_BLK_T_ZONE_APPEND) {
> > > > +inhdr_len = sizeof(struct virtio_blk_zone_append_inhdr);
> > > > +req->in.in_hdr->status = status;
> > > > +buf = req->in.in_hdr;
> > > > +} else {
> > > > +inhdr_len = sizeof(struct virtio_blk_inhdr);
> > > > +req->in.zone_append_inhdr->status = status;
> > > > +buf = req->in.zone_append_inhdr;
> > > > +}
> > > > +
> > > > +n = iov_from_buf(req->elem.in_sg, req->elem.in_num,
> > > > + req->in_len - inhdr_len, buf, inhdr_len);
> > > > +if (n != inhdr_len) {
> > > > +virtio_error(vdev, "Driver provided input buffer less than 
> > > > size of
> > > > "
> > > > + "in header");
> > > > +}
> > > > +
> > > >  iov_discard_undo(>inhdr_undo);
> > > >  iov_discard_undo(>outhdr_undo);
> > > >  virtqueue_push(req->vq, >elem, req->in_len);
> > > > @@ -592,6 +614,334 @@ err:
> > > >  return err_status;
> > > >  }
> > > >
> > > > +typedef struct ZoneCmdData {
> > > > +VirtIOBlockReq *req;
> > > > +union {
> > > > +struct {
> > > > +unsigned int nr_zones;
> > > > +BlockZoneDescriptor *zones;
> > > > +} zone_report_data;
> > > > +struct {
> > > > +int64_t offset;
> > > > +} zone_append_data;
> > > > +};
> > > > +} ZoneCmdData;
> > > > +
> > > > +/*
> > > > + * check zoned_request: error checking before issuing requests. If all
> > > > checks
> > > > + * passed, return true.
> > > > + * append: true if only zone append requests issued.
> > > > + */
> > > > +static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t
> > > > len,
> > > > + bool append, uint8_t *status) {
> > > > +BlockDriverState *bs = blk_bs(s->blk);
> > > > +int index = offset / bs->bl.zone_size;
> > > > +
> > > > +if (offset < 0 || len < 0 || offset > bs->bl.capacity - len) {
> > > > +*status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> > > > +return false;
> > > > +}
> > > > +
> > > > +if (!virtio_has_feature(s->host_features, VIRTIO_BLK_F_ZONED)) {
> > > > +*status = VIRTIO_BLK_S_UNSUPP;
> > > > +

Re: [RFC v3 2/2] virtio-blk: add zoned storage emulation for zoned devices

2022-10-18 Thread Sam Li
Dmitry Fomichev  于2022年10月17日周一 09:01写道:
>
> On Sun, 2022-10-16 at 23:05 +0800, Sam Li wrote:
> > This patch extends virtio-blk emulation to handle zoned device commands
> > by calling the new block layer APIs to perform zoned device I/O on
> > behalf of the guest. It supports Report Zone, four zone oparations (open,
> > close, finish, reset), and Append Zone.
> >
> > The VIRTIO_BLK_F_ZONED feature bit will only be set if the host does
> > support zoned block devices. Regular block devices(conventional zones)
> > will not be set.
> >
> > Then the guest os can use blkzone(8) to test those commands on zoned 
> > devices.
> > Furthermore, using zonefs to test zone append write is also supported.
> >
> > Signed-off-by: Sam Li 
> > ---
> >  hw/block/virtio-blk-common.c   |   2 +
> >  hw/block/virtio-blk.c  | 412 -
> >  include/hw/virtio/virtio-blk.h |  11 +-
> >  3 files changed, 422 insertions(+), 3 deletions(-)
> >
> > diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c
> > index ac52d7c176..e2f8e2f6da 100644
> > --- a/hw/block/virtio-blk-common.c
> > +++ b/hw/block/virtio-blk-common.c
> > @@ -29,6 +29,8 @@ static const VirtIOFeature feature_sizes[] = {
> >   .end = endof(struct virtio_blk_config, discard_sector_alignment)},
> >  {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
> >   .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
> > +{.flags = 1ULL << VIRTIO_BLK_F_ZONED,
> > + .end = endof(struct virtio_blk_config, zoned)},
> >  {}
> >  };
> >
> > diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> > index 8131ec2dbc..58891aea31 100644
> > --- a/hw/block/virtio-blk.c
> > +++ b/hw/block/virtio-blk.c
> > @@ -26,6 +26,9 @@
> >  #include "hw/virtio/virtio-blk.h"
> >  #include "dataplane/virtio-blk.h"
> >  #include "scsi/constants.h"
> > +#if defined(CONFIG_BLKZONED)
> > +#include 
> > +#endif
> >  #ifdef __linux__
> >  # include 
> >  #endif
> > @@ -55,10 +58,29 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req,
> > unsigned char status)
> >  {
> >  VirtIOBlock *s = req->dev;
> >  VirtIODevice *vdev = VIRTIO_DEVICE(s);
> > +int64_t inhdr_len, n;
> > +void *buf;
> >
> >  trace_virtio_blk_req_complete(vdev, req, status);
> >
> > -stb_p(>in->status, status);
> > +iov_discard_undo(>inhdr_undo);
> > +if (virtio_ldl_p(vdev, >out.type) == VIRTIO_BLK_T_ZONE_APPEND) {
> > +inhdr_len = sizeof(struct virtio_blk_zone_append_inhdr);
> > +req->in.in_hdr->status = status;
> > +buf = req->in.in_hdr;
> > +} else {
> > +inhdr_len = sizeof(struct virtio_blk_inhdr);
> > +req->in.zone_append_inhdr->status = status;
> > +buf = req->in.zone_append_inhdr;
> > +}
> > +
> > +n = iov_from_buf(req->elem.in_sg, req->elem.in_num,
> > + req->in_len - inhdr_len, buf, inhdr_len);
> > +if (n != inhdr_len) {
> > +virtio_error(vdev, "Driver provided input buffer less than size of 
> > "
> > + "in header");
> > +}
> > +
> >  iov_discard_undo(>inhdr_undo);
> >  iov_discard_undo(>outhdr_undo);
> >  virtqueue_push(req->vq, >elem, req->in_len);
> > @@ -592,6 +614,334 @@ err:
> >  return err_status;
> >  }
> >
> > +typedef struct ZoneCmdData {
> > +VirtIOBlockReq *req;
> > +union {
> > +struct {
> > +unsigned int nr_zones;
> > +BlockZoneDescriptor *zones;
> > +} zone_report_data;
> > +struct {
> > +int64_t offset;
> > +} zone_append_data;
> > +};
> > +} ZoneCmdData;
> > +
> > +/*
> > + * check zoned_request: error checking before issuing requests. If all 
> > checks
> > + * passed, return true.
> > + * append: true if only zone append requests issued.
> > + */
> > +static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t 
> > len,
> > + bool append, uint8_t *status) {
> > +BlockDriverState *bs = blk_bs(s->blk);
> > +int index = offset / bs->bl.zone_size;
> > +
> > +if (offset < 0 || len < 0 || offset > bs->bl.capacity - len) {
> > +*status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> > +return false;
> > +}
> > +
> > +if (!virtio_has_feature(s->host_features, VIRTIO_BLK_F_ZONED)) {
> > +*status = VIRTIO_BLK_S_UNSUPP;
> > +return false;
> > +}
> > +
> > +if (append) {
> > +if ((offset % bs->bl.write_granularity) != 0) {
> > +*status = VIRTIO_BLK_S_ZONE_UNALIGNED_WP;
> > +return false;
> > +}
> > +
> > +if (BDRV_ZT_IS_CONV(bs->bl.wps->wp[index])) {
> > +*status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> > +return false;
> > +}
> > +
> > +if (len / 512 > bs->bl.max_append_sectors) {
> > +if (bs->bl.max_append_sectors == 0) {
> > +*status = VIRTIO_BLK_S_UNSUPP;
> > +} else {
> > +  

Re: [RFC v3 2/2] virtio-blk: add zoned storage emulation for zoned devices

2022-10-16 Thread Dmitry Fomichev
On Sun, 2022-10-16 at 23:05 +0800, Sam Li wrote:
> This patch extends virtio-blk emulation to handle zoned device commands
> by calling the new block layer APIs to perform zoned device I/O on
> behalf of the guest. It supports Report Zone, four zone oparations (open,
> close, finish, reset), and Append Zone.
> 
> The VIRTIO_BLK_F_ZONED feature bit will only be set if the host does
> support zoned block devices. Regular block devices(conventional zones)
> will not be set.
> 
> Then the guest os can use blkzone(8) to test those commands on zoned devices.
> Furthermore, using zonefs to test zone append write is also supported.
> 
> Signed-off-by: Sam Li 
> ---
>  hw/block/virtio-blk-common.c   |   2 +
>  hw/block/virtio-blk.c  | 412 -
>  include/hw/virtio/virtio-blk.h |  11 +-
>  3 files changed, 422 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c
> index ac52d7c176..e2f8e2f6da 100644
> --- a/hw/block/virtio-blk-common.c
> +++ b/hw/block/virtio-blk-common.c
> @@ -29,6 +29,8 @@ static const VirtIOFeature feature_sizes[] = {
>   .end = endof(struct virtio_blk_config, discard_sector_alignment)},
>  {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
>   .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
> +    {.flags = 1ULL << VIRTIO_BLK_F_ZONED,
> + .end = endof(struct virtio_blk_config, zoned)},
>  {}
>  };
>  
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index 8131ec2dbc..58891aea31 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -26,6 +26,9 @@
>  #include "hw/virtio/virtio-blk.h"
>  #include "dataplane/virtio-blk.h"
>  #include "scsi/constants.h"
> +#if defined(CONFIG_BLKZONED)
> +#include 
> +#endif
>  #ifdef __linux__
>  # include 
>  #endif
> @@ -55,10 +58,29 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req,
> unsigned char status)
>  {
>  VirtIOBlock *s = req->dev;
>  VirtIODevice *vdev = VIRTIO_DEVICE(s);
> +    int64_t inhdr_len, n;
> +    void *buf;
>  
>  trace_virtio_blk_req_complete(vdev, req, status);
>  
> -    stb_p(>in->status, status);
> +    iov_discard_undo(>inhdr_undo);
> +    if (virtio_ldl_p(vdev, >out.type) == VIRTIO_BLK_T_ZONE_APPEND) {
> +    inhdr_len = sizeof(struct virtio_blk_zone_append_inhdr);
> +    req->in.in_hdr->status = status;
> +    buf = req->in.in_hdr;
> +    } else {
> +    inhdr_len = sizeof(struct virtio_blk_inhdr);
> +    req->in.zone_append_inhdr->status = status;
> +    buf = req->in.zone_append_inhdr;
> +    }
> +
> +    n = iov_from_buf(req->elem.in_sg, req->elem.in_num,
> + req->in_len - inhdr_len, buf, inhdr_len);
> +    if (n != inhdr_len) {
> +    virtio_error(vdev, "Driver provided input buffer less than size of "
> + "in header");
> +    }
> +
>  iov_discard_undo(>inhdr_undo);
>  iov_discard_undo(>outhdr_undo);
>  virtqueue_push(req->vq, >elem, req->in_len);
> @@ -592,6 +614,334 @@ err:
>  return err_status;
>  }
>  
> +typedef struct ZoneCmdData {
> +    VirtIOBlockReq *req;
> +    union {
> +    struct {
> +    unsigned int nr_zones;
> +    BlockZoneDescriptor *zones;
> +    } zone_report_data;
> +    struct {
> +    int64_t offset;
> +    } zone_append_data;
> +    };
> +} ZoneCmdData;
> +
> +/*
> + * check zoned_request: error checking before issuing requests. If all checks
> + * passed, return true.
> + * append: true if only zone append requests issued.
> + */
> +static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t len,
> + bool append, uint8_t *status) {
> +    BlockDriverState *bs = blk_bs(s->blk);
> +    int index = offset / bs->bl.zone_size;
> +
> +    if (offset < 0 || len < 0 || offset > bs->bl.capacity - len) {
> +    *status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> +    return false;
> +    }
> +
> +    if (!virtio_has_feature(s->host_features, VIRTIO_BLK_F_ZONED)) {
> +    *status = VIRTIO_BLK_S_UNSUPP;
> +    return false;
> +    }
> +
> +    if (append) {
> +    if ((offset % bs->bl.write_granularity) != 0) {
> +    *status = VIRTIO_BLK_S_ZONE_UNALIGNED_WP;
> +    return false;
> +    }
> +
> +    if (BDRV_ZT_IS_CONV(bs->bl.wps->wp[index])) {
> +    *status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> +    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;
> +    }
> +    return false;
> +    }
> +    }
> +    return true;
> +}
> +
> +static void virtio_blk_zone_report_complete(void *opaque, int ret)
> +{
> +    ZoneCmdData *data = opaque;
> +    VirtIOBlockReq *req = data->req;
> +    VirtIOBlock *s = 

[RFC v3 2/2] virtio-blk: add zoned storage emulation for zoned devices

2022-10-16 Thread Sam Li
This patch extends virtio-blk emulation to handle zoned device commands
by calling the new block layer APIs to perform zoned device I/O on
behalf of the guest. It supports Report Zone, four zone oparations (open,
close, finish, reset), and Append Zone.

The VIRTIO_BLK_F_ZONED feature bit will only be set if the host does
support zoned block devices. Regular block devices(conventional zones)
will not be set.

Then the guest os can use blkzone(8) to test those commands on zoned devices.
Furthermore, using zonefs to test zone append write is also supported.

Signed-off-by: Sam Li 
---
 hw/block/virtio-blk-common.c   |   2 +
 hw/block/virtio-blk.c  | 412 -
 include/hw/virtio/virtio-blk.h |  11 +-
 3 files changed, 422 insertions(+), 3 deletions(-)

diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c
index ac52d7c176..e2f8e2f6da 100644
--- a/hw/block/virtio-blk-common.c
+++ b/hw/block/virtio-blk-common.c
@@ -29,6 +29,8 @@ static const VirtIOFeature feature_sizes[] = {
  .end = endof(struct virtio_blk_config, discard_sector_alignment)},
 {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
  .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
+{.flags = 1ULL << VIRTIO_BLK_F_ZONED,
+ .end = endof(struct virtio_blk_config, zoned)},
 {}
 };
 
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 8131ec2dbc..58891aea31 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -26,6 +26,9 @@
 #include "hw/virtio/virtio-blk.h"
 #include "dataplane/virtio-blk.h"
 #include "scsi/constants.h"
+#if defined(CONFIG_BLKZONED)
+#include 
+#endif
 #ifdef __linux__
 # include 
 #endif
@@ -55,10 +58,29 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, 
unsigned char status)
 {
 VirtIOBlock *s = req->dev;
 VirtIODevice *vdev = VIRTIO_DEVICE(s);
+int64_t inhdr_len, n;
+void *buf;
 
 trace_virtio_blk_req_complete(vdev, req, status);
 
-stb_p(>in->status, status);
+iov_discard_undo(>inhdr_undo);
+if (virtio_ldl_p(vdev, >out.type) == VIRTIO_BLK_T_ZONE_APPEND) {
+inhdr_len = sizeof(struct virtio_blk_zone_append_inhdr);
+req->in.in_hdr->status = status;
+buf = req->in.in_hdr;
+} else {
+inhdr_len = sizeof(struct virtio_blk_inhdr);
+req->in.zone_append_inhdr->status = status;
+buf = req->in.zone_append_inhdr;
+}
+
+n = iov_from_buf(req->elem.in_sg, req->elem.in_num,
+ req->in_len - inhdr_len, buf, inhdr_len);
+if (n != inhdr_len) {
+virtio_error(vdev, "Driver provided input buffer less than size of "
+ "in header");
+}
+
 iov_discard_undo(>inhdr_undo);
 iov_discard_undo(>outhdr_undo);
 virtqueue_push(req->vq, >elem, req->in_len);
@@ -592,6 +614,334 @@ err:
 return err_status;
 }
 
+typedef struct ZoneCmdData {
+VirtIOBlockReq *req;
+union {
+struct {
+unsigned int nr_zones;
+BlockZoneDescriptor *zones;
+} zone_report_data;
+struct {
+int64_t offset;
+} zone_append_data;
+};
+} ZoneCmdData;
+
+/*
+ * check zoned_request: error checking before issuing requests. If all checks
+ * passed, return true.
+ * append: true if only zone append requests issued.
+ */
+static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t len,
+ bool append, uint8_t *status) {
+BlockDriverState *bs = blk_bs(s->blk);
+int index = offset / bs->bl.zone_size;
+
+if (offset < 0 || len < 0 || offset > bs->bl.capacity - len) {
+*status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
+return false;
+}
+
+if (!virtio_has_feature(s->host_features, VIRTIO_BLK_F_ZONED)) {
+*status = VIRTIO_BLK_S_UNSUPP;
+return false;
+}
+
+if (append) {
+if ((offset % bs->bl.write_granularity) != 0) {
+*status = VIRTIO_BLK_S_ZONE_UNALIGNED_WP;
+return false;
+}
+
+if (BDRV_ZT_IS_CONV(bs->bl.wps->wp[index])) {
+*status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
+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;
+}
+return false;
+}
+}
+return true;
+}
+
+static void virtio_blk_zone_report_complete(void *opaque, int ret)
+{
+ZoneCmdData *data = opaque;
+VirtIOBlockReq *req = data->req;
+VirtIOBlock *s = req->dev;
+VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
+struct iovec *in_iov = req->elem.in_sg;
+unsigned in_num = req->elem.in_num;
+int64_t zrp_size, nz, n, j = 0;
+int8_t err_status = VIRTIO_BLK_S_OK;
+
+if (ret) {
+err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
+goto out;
+}
+
+nz =