Re: [PATCH v11 3/7] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-10-12 Thread Damien Le Moal
On 10/13/22 14:33, Sam Li wrote:
> Damien Le Moal  于2022年10月13日周四 12:41写道:
>>
>> On 10/10/22 11:21, Sam Li wrote:
>>> Add a new zoned_host_device BlockDriver. The zoned_host_device option
>>> accepts only zoned host block devices. By adding zone management
>>> operations in this new BlockDriver, users can use the new block
>>> layer APIs including Report Zone and four zone management operations
>>> (open, close, finish, reset, reset_all).
>>>
>>> Qemu-io uses the new APIs to perform zoned storage commands of the device:
>>> zone_report(zrp), zone_open(zo), zone_close(zc), zone_reset(zrs),
>>> zone_finish(zf).
>>>
>>> For example, to test zone_report, use following command:
>>> $ ./build/qemu-io --image-opts -n driver=zoned_host_device, 
>>> filename=/dev/nullb0
>>> -c "zrp offset nr_zones"
>>>
>>> Signed-off-by: Sam Li 
>>> Reviewed-by: Hannes Reinecke 
>>> ---
>>>  block/block-backend.c | 146 +
>>>  block/file-posix.c| 329 ++
>>>  block/io.c|  41 
>>>  include/block/block-common.h  |   1 +
>>>  include/block/block-io.h  |   7 +
>>>  include/block/block_int-common.h  |  24 +++
>>>  include/block/raw-aio.h   |   6 +-
>>>  include/sysemu/block-backend-io.h |  17 ++
>>>  meson.build   |   4 +
>>>  qapi/block-core.json  |   8 +-
>>>  qemu-io-cmds.c| 148 ++
>>>  11 files changed, 728 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/block/block-backend.c b/block/block-backend.c
>>> index d4a5df2ac2..ddc569e3ac 100644
>>> --- a/block/block-backend.c
>>> +++ b/block/block-backend.c
>>> @@ -1431,6 +1431,15 @@ typedef struct BlkRwCo {
>>>  void *iobuf;
>>>  int ret;
>>>  BdrvRequestFlags flags;
>>> +union {
>>> +struct {
>>> +unsigned int *nr_zones;
>>> +BlockZoneDescriptor *zones;
>>> +} zone_report;
>>> +struct {
>>> +BlockZoneOp op;
>>> +} zone_mgmt;
>>> +};
>>>  } BlkRwCo;
>>>
>>>  int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
>>> @@ -1775,6 +1784,143 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
>>>  return ret;
>>>  }
>>>
>>> +static void coroutine_fn blk_aio_zone_report_entry(void *opaque) {
>>> +BlkAioEmAIOCB *acb = opaque;
>>> +BlkRwCo *rwco = &acb->rwco;
>>> +
>>> +rwco->ret = blk_co_zone_report(rwco->blk, rwco->offset,
>>> +   rwco->zone_report.nr_zones,
>>> +   rwco->zone_report.zones);
>>> +blk_aio_complete(acb);
>>> +}
>>> +
>>> +BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
>>> +unsigned int *nr_zones,
>>> +BlockZoneDescriptor  *zones,
>>> +BlockCompletionFunc *cb, void *opaque)
>>> +{
>>> +BlkAioEmAIOCB *acb;
>>> +Coroutine *co;
>>> +IO_CODE();
>>> +
>>> +blk_inc_in_flight(blk);
>>> +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
>>> +acb->rwco = (BlkRwCo) {
>>> +.blk= blk,
>>> +.offset = offset,
>>> +.ret= NOT_DONE,
>>> +.zone_report = {
>>> +.zones = zones,
>>> +.nr_zones = nr_zones,
>>> +},
>>> +};
>>> +acb->has_returned = false;
>>> +
>>> +co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
>>> +bdrv_coroutine_enter(blk_bs(blk), co);
>>> +
>>> +acb->has_returned = true;
>>> +if (acb->rwco.ret != NOT_DONE) {
>>> +replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
>>> + blk_aio_complete_bh, acb);
>>> +}
>>> +
>>> +return &acb->common;
>>> +}
>>> +
>>> +static void coroutine_fn blk_aio_zone_mgmt_entry(void *opaque) {
>>> +BlkAioEmAIOCB *acb = opaque;
>>> +BlkRwCo *rwco = &acb->rwco;
>>> +
>>> +rwco->ret = blk_co_zone_mgmt(rwco->blk, rwco->zone_mgmt.op,
>>> + rwco->offset, acb->bytes);
>>> +blk_aio_complete(acb);
>>> +}
>>> +
>>> +BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
>>> +  int64_t offset, int64_t len,
>>> +  BlockCompletionFunc *cb, void *opaque) {
>>> +BlkAioEmAIOCB *acb;
>>> +Coroutine *co;
>>> +IO_CODE();
>>> +
>>> +blk_inc_in_flight(blk);
>>> +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
>>> +acb->rwco = (BlkRwCo) {
>>> +.blk= blk,
>>> +.offset = offset,
>>> +.ret= NOT_DONE,
>>> +.zone_mgmt = {
>>> +.op = op,
>>> +},
>>> +};
>>> +acb->bytes = len;
>>> +acb->has_returned = false;
>>> +
>>> +co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
>>> +bdrv_coroutine_enter(blk_bs(blk), co);
>>> +
>>> +acb->has_returned = true;
>>> +if (acb->rwco.ret != NOT_DO

Re: [PATCH v11 3/7] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-10-12 Thread Sam Li
Damien Le Moal  于2022年10月13日周四 13:45写道:
>
> On 10/13/22 14:33, Sam Li wrote:
> > Damien Le Moal  于2022年10月13日周四 12:41写道:
> >>
> >> On 10/10/22 11:21, Sam Li wrote:
> >>> Add a new zoned_host_device BlockDriver. The zoned_host_device option
> >>> accepts only zoned host block devices. By adding zone management
> >>> operations in this new BlockDriver, users can use the new block
> >>> layer APIs including Report Zone and four zone management operations
> >>> (open, close, finish, reset, reset_all).
> >>>
> >>> Qemu-io uses the new APIs to perform zoned storage commands of the device:
> >>> zone_report(zrp), zone_open(zo), zone_close(zc), zone_reset(zrs),
> >>> zone_finish(zf).
> >>>
> >>> For example, to test zone_report, use following command:
> >>> $ ./build/qemu-io --image-opts -n driver=zoned_host_device, 
> >>> filename=/dev/nullb0
> >>> -c "zrp offset nr_zones"
> >>>
> >>> Signed-off-by: Sam Li 
> >>> Reviewed-by: Hannes Reinecke 
> >>> ---
> >>>  block/block-backend.c | 146 +
> >>>  block/file-posix.c| 329 ++
> >>>  block/io.c|  41 
> >>>  include/block/block-common.h  |   1 +
> >>>  include/block/block-io.h  |   7 +
> >>>  include/block/block_int-common.h  |  24 +++
> >>>  include/block/raw-aio.h   |   6 +-
> >>>  include/sysemu/block-backend-io.h |  17 ++
> >>>  meson.build   |   4 +
> >>>  qapi/block-core.json  |   8 +-
> >>>  qemu-io-cmds.c| 148 ++
> >>>  11 files changed, 728 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/block/block-backend.c b/block/block-backend.c
> >>> index d4a5df2ac2..ddc569e3ac 100644
> >>> --- a/block/block-backend.c
> >>> +++ b/block/block-backend.c
> >>> @@ -1431,6 +1431,15 @@ typedef struct BlkRwCo {
> >>>  void *iobuf;
> >>>  int ret;
> >>>  BdrvRequestFlags flags;
> >>> +union {
> >>> +struct {
> >>> +unsigned int *nr_zones;
> >>> +BlockZoneDescriptor *zones;
> >>> +} zone_report;
> >>> +struct {
> >>> +BlockZoneOp op;
> >>> +} zone_mgmt;
> >>> +};
> >>>  } BlkRwCo;
> >>>
> >>>  int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
> >>> @@ -1775,6 +1784,143 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
> >>>  return ret;
> >>>  }
> >>>
> >>> +static void coroutine_fn blk_aio_zone_report_entry(void *opaque) {
> >>> +BlkAioEmAIOCB *acb = opaque;
> >>> +BlkRwCo *rwco = &acb->rwco;
> >>> +
> >>> +rwco->ret = blk_co_zone_report(rwco->blk, rwco->offset,
> >>> +   rwco->zone_report.nr_zones,
> >>> +   rwco->zone_report.zones);
> >>> +blk_aio_complete(acb);
> >>> +}
> >>> +
> >>> +BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
> >>> +unsigned int *nr_zones,
> >>> +BlockZoneDescriptor  *zones,
> >>> +BlockCompletionFunc *cb, void *opaque)
> >>> +{
> >>> +BlkAioEmAIOCB *acb;
> >>> +Coroutine *co;
> >>> +IO_CODE();
> >>> +
> >>> +blk_inc_in_flight(blk);
> >>> +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
> >>> +acb->rwco = (BlkRwCo) {
> >>> +.blk= blk,
> >>> +.offset = offset,
> >>> +.ret= NOT_DONE,
> >>> +.zone_report = {
> >>> +.zones = zones,
> >>> +.nr_zones = nr_zones,
> >>> +},
> >>> +};
> >>> +acb->has_returned = false;
> >>> +
> >>> +co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
> >>> +bdrv_coroutine_enter(blk_bs(blk), co);
> >>> +
> >>> +acb->has_returned = true;
> >>> +if (acb->rwco.ret != NOT_DONE) {
> >>> +replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
> >>> + blk_aio_complete_bh, acb);
> >>> +}
> >>> +
> >>> +return &acb->common;
> >>> +}
> >>> +
> >>> +static void coroutine_fn blk_aio_zone_mgmt_entry(void *opaque) {
> >>> +BlkAioEmAIOCB *acb = opaque;
> >>> +BlkRwCo *rwco = &acb->rwco;
> >>> +
> >>> +rwco->ret = blk_co_zone_mgmt(rwco->blk, rwco->zone_mgmt.op,
> >>> + rwco->offset, acb->bytes);
> >>> +blk_aio_complete(acb);
> >>> +}
> >>> +
> >>> +BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
> >>> +  int64_t offset, int64_t len,
> >>> +  BlockCompletionFunc *cb, void *opaque) {
> >>> +BlkAioEmAIOCB *acb;
> >>> +Coroutine *co;
> >>> +IO_CODE();
> >>> +
> >>> +blk_inc_in_flight(blk);
> >>> +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
> >>> +acb->rwco = (BlkRwCo) {
> >>> +.blk= blk,
> >>> +.offset = offset,
> >>> +.ret= NOT_DONE,
> >>> +.zone_mgmt = {
> >>> +.op

Re: [PATCH v11 3/7] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-10-12 Thread Sam Li
Damien Le Moal  于2022年10月13日周四 12:41写道:
>
> On 10/10/22 11:21, Sam Li wrote:
> > Add a new zoned_host_device BlockDriver. The zoned_host_device option
> > accepts only zoned host block devices. By adding zone management
> > operations in this new BlockDriver, users can use the new block
> > layer APIs including Report Zone and four zone management operations
> > (open, close, finish, reset, reset_all).
> >
> > Qemu-io uses the new APIs to perform zoned storage commands of the device:
> > zone_report(zrp), zone_open(zo), zone_close(zc), zone_reset(zrs),
> > zone_finish(zf).
> >
> > For example, to test zone_report, use following command:
> > $ ./build/qemu-io --image-opts -n driver=zoned_host_device, 
> > filename=/dev/nullb0
> > -c "zrp offset nr_zones"
> >
> > Signed-off-by: Sam Li 
> > Reviewed-by: Hannes Reinecke 
> > ---
> >  block/block-backend.c | 146 +
> >  block/file-posix.c| 329 ++
> >  block/io.c|  41 
> >  include/block/block-common.h  |   1 +
> >  include/block/block-io.h  |   7 +
> >  include/block/block_int-common.h  |  24 +++
> >  include/block/raw-aio.h   |   6 +-
> >  include/sysemu/block-backend-io.h |  17 ++
> >  meson.build   |   4 +
> >  qapi/block-core.json  |   8 +-
> >  qemu-io-cmds.c| 148 ++
> >  11 files changed, 728 insertions(+), 3 deletions(-)
> >
> > diff --git a/block/block-backend.c b/block/block-backend.c
> > index d4a5df2ac2..ddc569e3ac 100644
> > --- a/block/block-backend.c
> > +++ b/block/block-backend.c
> > @@ -1431,6 +1431,15 @@ typedef struct BlkRwCo {
> >  void *iobuf;
> >  int ret;
> >  BdrvRequestFlags flags;
> > +union {
> > +struct {
> > +unsigned int *nr_zones;
> > +BlockZoneDescriptor *zones;
> > +} zone_report;
> > +struct {
> > +BlockZoneOp op;
> > +} zone_mgmt;
> > +};
> >  } BlkRwCo;
> >
> >  int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
> > @@ -1775,6 +1784,143 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
> >  return ret;
> >  }
> >
> > +static void coroutine_fn blk_aio_zone_report_entry(void *opaque) {
> > +BlkAioEmAIOCB *acb = opaque;
> > +BlkRwCo *rwco = &acb->rwco;
> > +
> > +rwco->ret = blk_co_zone_report(rwco->blk, rwco->offset,
> > +   rwco->zone_report.nr_zones,
> > +   rwco->zone_report.zones);
> > +blk_aio_complete(acb);
> > +}
> > +
> > +BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
> > +unsigned int *nr_zones,
> > +BlockZoneDescriptor  *zones,
> > +BlockCompletionFunc *cb, void *opaque)
> > +{
> > +BlkAioEmAIOCB *acb;
> > +Coroutine *co;
> > +IO_CODE();
> > +
> > +blk_inc_in_flight(blk);
> > +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
> > +acb->rwco = (BlkRwCo) {
> > +.blk= blk,
> > +.offset = offset,
> > +.ret= NOT_DONE,
> > +.zone_report = {
> > +.zones = zones,
> > +.nr_zones = nr_zones,
> > +},
> > +};
> > +acb->has_returned = false;
> > +
> > +co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
> > +bdrv_coroutine_enter(blk_bs(blk), co);
> > +
> > +acb->has_returned = true;
> > +if (acb->rwco.ret != NOT_DONE) {
> > +replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
> > + blk_aio_complete_bh, acb);
> > +}
> > +
> > +return &acb->common;
> > +}
> > +
> > +static void coroutine_fn blk_aio_zone_mgmt_entry(void *opaque) {
> > +BlkAioEmAIOCB *acb = opaque;
> > +BlkRwCo *rwco = &acb->rwco;
> > +
> > +rwco->ret = blk_co_zone_mgmt(rwco->blk, rwco->zone_mgmt.op,
> > + rwco->offset, acb->bytes);
> > +blk_aio_complete(acb);
> > +}
> > +
> > +BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
> > +  int64_t offset, int64_t len,
> > +  BlockCompletionFunc *cb, void *opaque) {
> > +BlkAioEmAIOCB *acb;
> > +Coroutine *co;
> > +IO_CODE();
> > +
> > +blk_inc_in_flight(blk);
> > +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
> > +acb->rwco = (BlkRwCo) {
> > +.blk= blk,
> > +.offset = offset,
> > +.ret= NOT_DONE,
> > +.zone_mgmt = {
> > +.op = op,
> > +},
> > +};
> > +acb->bytes = len;
> > +acb->has_returned = false;
> > +
> > +co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
> > +bdrv_coroutine_enter(blk_bs(blk), co);
> > +
> > +acb->has_returned = true;
> > +if (acb->rwco.ret != NOT_DONE) {
> > +replay_bh_schedule

Re: [PATCH v11 3/7] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-10-12 Thread Damien Le Moal
On 10/10/22 11:21, Sam Li wrote:
> Add a new zoned_host_device BlockDriver. The zoned_host_device option
> accepts only zoned host block devices. By adding zone management
> operations in this new BlockDriver, users can use the new block
> layer APIs including Report Zone and four zone management operations
> (open, close, finish, reset, reset_all).
> 
> Qemu-io uses the new APIs to perform zoned storage commands of the device:
> zone_report(zrp), zone_open(zo), zone_close(zc), zone_reset(zrs),
> zone_finish(zf).
> 
> For example, to test zone_report, use following command:
> $ ./build/qemu-io --image-opts -n driver=zoned_host_device, 
> filename=/dev/nullb0
> -c "zrp offset nr_zones"
> 
> Signed-off-by: Sam Li 
> Reviewed-by: Hannes Reinecke 
> ---
>  block/block-backend.c | 146 +
>  block/file-posix.c| 329 ++
>  block/io.c|  41 
>  include/block/block-common.h  |   1 +
>  include/block/block-io.h  |   7 +
>  include/block/block_int-common.h  |  24 +++
>  include/block/raw-aio.h   |   6 +-
>  include/sysemu/block-backend-io.h |  17 ++
>  meson.build   |   4 +
>  qapi/block-core.json  |   8 +-
>  qemu-io-cmds.c| 148 ++
>  11 files changed, 728 insertions(+), 3 deletions(-)
> 
> diff --git a/block/block-backend.c b/block/block-backend.c
> index d4a5df2ac2..ddc569e3ac 100644
> --- a/block/block-backend.c
> +++ b/block/block-backend.c
> @@ -1431,6 +1431,15 @@ typedef struct BlkRwCo {
>  void *iobuf;
>  int ret;
>  BdrvRequestFlags flags;
> +union {
> +struct {
> +unsigned int *nr_zones;
> +BlockZoneDescriptor *zones;
> +} zone_report;
> +struct {
> +BlockZoneOp op;
> +} zone_mgmt;
> +};
>  } BlkRwCo;
>  
>  int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
> @@ -1775,6 +1784,143 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
>  return ret;
>  }
>  
> +static void coroutine_fn blk_aio_zone_report_entry(void *opaque) {
> +BlkAioEmAIOCB *acb = opaque;
> +BlkRwCo *rwco = &acb->rwco;
> +
> +rwco->ret = blk_co_zone_report(rwco->blk, rwco->offset,
> +   rwco->zone_report.nr_zones,
> +   rwco->zone_report.zones);
> +blk_aio_complete(acb);
> +}
> +
> +BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
> +unsigned int *nr_zones,
> +BlockZoneDescriptor  *zones,
> +BlockCompletionFunc *cb, void *opaque)
> +{
> +BlkAioEmAIOCB *acb;
> +Coroutine *co;
> +IO_CODE();
> +
> +blk_inc_in_flight(blk);
> +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
> +acb->rwco = (BlkRwCo) {
> +.blk= blk,
> +.offset = offset,
> +.ret= NOT_DONE,
> +.zone_report = {
> +.zones = zones,
> +.nr_zones = nr_zones,
> +},
> +};
> +acb->has_returned = false;
> +
> +co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
> +bdrv_coroutine_enter(blk_bs(blk), co);
> +
> +acb->has_returned = true;
> +if (acb->rwco.ret != NOT_DONE) {
> +replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
> + blk_aio_complete_bh, acb);
> +}
> +
> +return &acb->common;
> +}
> +
> +static void coroutine_fn blk_aio_zone_mgmt_entry(void *opaque) {
> +BlkAioEmAIOCB *acb = opaque;
> +BlkRwCo *rwco = &acb->rwco;
> +
> +rwco->ret = blk_co_zone_mgmt(rwco->blk, rwco->zone_mgmt.op,
> + rwco->offset, acb->bytes);
> +blk_aio_complete(acb);
> +}
> +
> +BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
> +  int64_t offset, int64_t len,
> +  BlockCompletionFunc *cb, void *opaque) {
> +BlkAioEmAIOCB *acb;
> +Coroutine *co;
> +IO_CODE();
> +
> +blk_inc_in_flight(blk);
> +acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
> +acb->rwco = (BlkRwCo) {
> +.blk= blk,
> +.offset = offset,
> +.ret= NOT_DONE,
> +.zone_mgmt = {
> +.op = op,
> +},
> +};
> +acb->bytes = len;
> +acb->has_returned = false;
> +
> +co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
> +bdrv_coroutine_enter(blk_bs(blk), co);
> +
> +acb->has_returned = true;
> +if (acb->rwco.ret != NOT_DONE) {
> +replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
> + blk_aio_complete_bh, acb);
> +}
> +
> +return &acb->common;
> +}
> +
> +/*
> + * Send a zone_report command.
> + * offset is a byte offset from the start of the device. No alignment
> + * required for offset.
> 

[PATCH v11 3/7] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-10-09 Thread Sam Li
Add a new zoned_host_device BlockDriver. The zoned_host_device option
accepts only zoned host block devices. By adding zone management
operations in this new BlockDriver, users can use the new block
layer APIs including Report Zone and four zone management operations
(open, close, finish, reset, reset_all).

Qemu-io uses the new APIs to perform zoned storage commands of the device:
zone_report(zrp), zone_open(zo), zone_close(zc), zone_reset(zrs),
zone_finish(zf).

For example, to test zone_report, use following command:
$ ./build/qemu-io --image-opts -n driver=zoned_host_device, filename=/dev/nullb0
-c "zrp offset nr_zones"

Signed-off-by: Sam Li 
Reviewed-by: Hannes Reinecke 
---
 block/block-backend.c | 146 +
 block/file-posix.c| 329 ++
 block/io.c|  41 
 include/block/block-common.h  |   1 +
 include/block/block-io.h  |   7 +
 include/block/block_int-common.h  |  24 +++
 include/block/raw-aio.h   |   6 +-
 include/sysemu/block-backend-io.h |  17 ++
 meson.build   |   4 +
 qapi/block-core.json  |   8 +-
 qemu-io-cmds.c| 148 ++
 11 files changed, 728 insertions(+), 3 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index d4a5df2ac2..ddc569e3ac 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1431,6 +1431,15 @@ typedef struct BlkRwCo {
 void *iobuf;
 int ret;
 BdrvRequestFlags flags;
+union {
+struct {
+unsigned int *nr_zones;
+BlockZoneDescriptor *zones;
+} zone_report;
+struct {
+BlockZoneOp op;
+} zone_mgmt;
+};
 } BlkRwCo;
 
 int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
@@ -1775,6 +1784,143 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
 return ret;
 }
 
+static void coroutine_fn blk_aio_zone_report_entry(void *opaque) {
+BlkAioEmAIOCB *acb = opaque;
+BlkRwCo *rwco = &acb->rwco;
+
+rwco->ret = blk_co_zone_report(rwco->blk, rwco->offset,
+   rwco->zone_report.nr_zones,
+   rwco->zone_report.zones);
+blk_aio_complete(acb);
+}
+
+BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
+unsigned int *nr_zones,
+BlockZoneDescriptor  *zones,
+BlockCompletionFunc *cb, void *opaque)
+{
+BlkAioEmAIOCB *acb;
+Coroutine *co;
+IO_CODE();
+
+blk_inc_in_flight(blk);
+acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
+acb->rwco = (BlkRwCo) {
+.blk= blk,
+.offset = offset,
+.ret= NOT_DONE,
+.zone_report = {
+.zones = zones,
+.nr_zones = nr_zones,
+},
+};
+acb->has_returned = false;
+
+co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
+bdrv_coroutine_enter(blk_bs(blk), co);
+
+acb->has_returned = true;
+if (acb->rwco.ret != NOT_DONE) {
+replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
+ blk_aio_complete_bh, acb);
+}
+
+return &acb->common;
+}
+
+static void coroutine_fn blk_aio_zone_mgmt_entry(void *opaque) {
+BlkAioEmAIOCB *acb = opaque;
+BlkRwCo *rwco = &acb->rwco;
+
+rwco->ret = blk_co_zone_mgmt(rwco->blk, rwco->zone_mgmt.op,
+ rwco->offset, acb->bytes);
+blk_aio_complete(acb);
+}
+
+BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
+  int64_t offset, int64_t len,
+  BlockCompletionFunc *cb, void *opaque) {
+BlkAioEmAIOCB *acb;
+Coroutine *co;
+IO_CODE();
+
+blk_inc_in_flight(blk);
+acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
+acb->rwco = (BlkRwCo) {
+.blk= blk,
+.offset = offset,
+.ret= NOT_DONE,
+.zone_mgmt = {
+.op = op,
+},
+};
+acb->bytes = len;
+acb->has_returned = false;
+
+co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
+bdrv_coroutine_enter(blk_bs(blk), co);
+
+acb->has_returned = true;
+if (acb->rwco.ret != NOT_DONE) {
+replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
+ blk_aio_complete_bh, acb);
+}
+
+return &acb->common;
+}
+
+/*
+ * Send a zone_report command.
+ * offset is a byte offset from the start of the device. No alignment
+ * required for offset.
+ * nr_zones represents IN maximum and OUT actual.
+ */
+int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset,
+unsigned int *nr_zones,
+BlockZoneDescriptor *zones)
+{
+int ret;
+IO_CODE();
+
+blk_inc_in_flight(blk); /* inc