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:
Sam Li 2023-05-08 12:55:28 +08:00 committed by Stefan Hajnoczi
parent a735b56e49
commit 6d43eaa396
9 changed files with 696 additions and 3 deletions

View file

@ -1730,6 +1730,150 @@ static const cmdinfo_t flush_cmd = {
.oneline = "flush all in-core file state to disk",
};
static inline int64_t tosector(int64_t bytes)
{
return bytes >> BDRV_SECTOR_BITS;
}
static int zone_report_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset;
unsigned int nr_zones;
++optind;
offset = cvtnum(argv[optind]);
++optind;
nr_zones = cvtnum(argv[optind]);
g_autofree BlockZoneDescriptor *zones = NULL;
zones = g_new(BlockZoneDescriptor, nr_zones);
ret = blk_zone_report(blk, offset, &nr_zones, zones);
if (ret < 0) {
printf("zone report failed: %s\n", strerror(-ret));
} else {
for (int i = 0; i < nr_zones; ++i) {
printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", "
"cap"" 0x%" PRIx64 ", wptr 0x%" PRIx64 ", "
"zcond:%u, [type: %u]\n",
tosector(zones[i].start), tosector(zones[i].length),
tosector(zones[i].cap), tosector(zones[i].wp),
zones[i].state, zones[i].type);
}
}
return ret;
}
static const cmdinfo_t zone_report_cmd = {
.name = "zone_report",
.altname = "zrp",
.cfunc = zone_report_f,
.argmin = 2,
.argmax = 2,
.args = "offset number",
.oneline = "report zone information",
};
static int zone_open_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len);
if (ret < 0) {
printf("zone open failed: %s\n", strerror(-ret));
}
return ret;
}
static const cmdinfo_t zone_open_cmd = {
.name = "zone_open",
.altname = "zo",
.cfunc = zone_open_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "explicit open a range of zones in zone block device",
};
static int zone_close_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len);
if (ret < 0) {
printf("zone close failed: %s\n", strerror(-ret));
}
return ret;
}
static const cmdinfo_t zone_close_cmd = {
.name = "zone_close",
.altname = "zc",
.cfunc = zone_close_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "close a range of zones in zone block device",
};
static int zone_finish_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len);
if (ret < 0) {
printf("zone finish failed: %s\n", strerror(-ret));
}
return ret;
}
static const cmdinfo_t zone_finish_cmd = {
.name = "zone_finish",
.altname = "zf",
.cfunc = zone_finish_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "finish a range of zones in zone block device",
};
static int zone_reset_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len);
if (ret < 0) {
printf("zone reset failed: %s\n", strerror(-ret));
}
return ret;
}
static const cmdinfo_t zone_reset_cmd = {
.name = "zone_reset",
.altname = "zrs",
.cfunc = zone_reset_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "reset a zone write pointer in zone block device",
};
static int truncate_f(BlockBackend *blk, int argc, char **argv);
static const cmdinfo_t truncate_cmd = {
.name = "truncate",
@ -2523,6 +2667,11 @@ static void __attribute((constructor)) init_qemuio_commands(void)
qemuio_add_command(&aio_write_cmd);
qemuio_add_command(&aio_flush_cmd);
qemuio_add_command(&flush_cmd);
qemuio_add_command(&zone_report_cmd);
qemuio_add_command(&zone_open_cmd);
qemuio_add_command(&zone_close_cmd);
qemuio_add_command(&zone_finish_cmd);
qemuio_add_command(&zone_reset_cmd);
qemuio_add_command(&truncate_cmd);
qemuio_add_command(&length_cmd);
qemuio_add_command(&info_cmd);