mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00
block/block-backend: add block layer APIs resembling Linux ZonedBlockDevice ioctls
Add zoned device option to host_device BlockDriver. It will be presented only for zoned host block devices. By adding zone management operations to the host_block_device 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=host_device, filename=/dev/nullb0 -c "zrp offset nr_zones" Signed-off-by: Sam Li <faithilikerun@gmail.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 20230508045533.175575-4-faithilikerun@gmail.com Message-id: 20230324090605.28361-4-faithilikerun@gmail.com [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé <philmd@linaro.org> and remove spurious ret = -errno in raw_co_zone_mgmt(). --Stefan] Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
a735b56e49
commit
6d43eaa396
9 changed files with 696 additions and 3 deletions
|
@ -1845,6 +1845,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,
|
||||
(unsigned int*)(uintptr_t)acb->bytes,
|
||||
rwco->iobuf);
|
||||
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,
|
||||
.iobuf = zones,
|
||||
.ret = NOT_DONE,
|
||||
};
|
||||
acb->bytes = (int64_t)(uintptr_t)nr_zones,
|
||||
acb->has_returned = false;
|
||||
|
||||
co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
|
||||
aio_co_enter(blk_get_aio_context(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,
|
||||
(BlockZoneOp)(uintptr_t)rwco->iobuf,
|
||||
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,
|
||||
.iobuf = (void *)(uintptr_t)op,
|
||||
.ret = NOT_DONE,
|
||||
};
|
||||
acb->bytes = len;
|
||||
acb->has_returned = false;
|
||||
|
||||
co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
|
||||
aio_co_enter(blk_get_aio_context(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); /* increase before waiting */
|
||||
blk_wait_while_drained(blk);
|
||||
GRAPH_RDLOCK_GUARD();
|
||||
if (!blk_is_available(blk)) {
|
||||
blk_dec_in_flight(blk);
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
ret = bdrv_co_zone_report(blk_bs(blk), offset, nr_zones, zones);
|
||||
blk_dec_in_flight(blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a zone_management command.
|
||||
* op is the zone operation;
|
||||
* offset is the byte offset from the start of the zoned device;
|
||||
* len is the maximum number of bytes the command should operate on. It
|
||||
* should be aligned with the device zone size.
|
||||
*/
|
||||
int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
|
||||
int64_t offset, int64_t len)
|
||||
{
|
||||
int ret;
|
||||
IO_CODE();
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
blk_wait_while_drained(blk);
|
||||
GRAPH_RDLOCK_GUARD();
|
||||
|
||||
ret = blk_check_byte_request(blk, offset, len);
|
||||
if (ret < 0) {
|
||||
blk_dec_in_flight(blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_co_zone_mgmt(blk_bs(blk), op, offset, len);
|
||||
blk_dec_in_flight(blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void blk_drain(BlockBackend *blk)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue