Zone descriptor data is host definied data that is associated with each zone. Add zone descriptor extensions to zonedmeta and blk_get_zone_extension to access zd_extensions.
Signed-off-by: Sam Li <faithilike...@gmail.com> --- block/block-backend.c | 15 ++++++ block/qcow2.c | 86 ++++++++++++++++++++++++++----- block/qcow2.h | 3 ++ docs/interop/qcow2.txt | 2 + hw/nvme/ctrl.c | 19 ++++--- hw/nvme/ns.c | 24 ++------- hw/nvme/nvme.h | 7 --- include/block/block_int-common.h | 6 +++ include/sysemu/block-backend-io.h | 2 + qapi/block-core.json | 3 ++ 10 files changed, 121 insertions(+), 46 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index ad410286a0..f68c5263f3 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2418,6 +2418,21 @@ uint32_t blk_get_max_append_sectors(BlockBackend *blk) return bs ? bs->bl.max_append_sectors : 0; } +uint8_t *blk_get_zone_extension(BlockBackend *blk) { + BlockDriverState * bs = blk_bs(blk); + IO_CODE(); + + return bs ? bs->zd_extensions : NULL; +} + +uint32_t blk_get_zd_ext_size(BlockBackend *blk) +{ + BlockDriverState *bs = blk_bs(blk); + IO_CODE(); + + return bs ? bs->bl.zd_extension_size : 0; +} + void *blk_try_blockalign(BlockBackend *blk, size_t size) { IO_CODE(); diff --git a/block/qcow2.c b/block/qcow2.c index 9de90ccc9f..fce1fe83a7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -340,15 +340,28 @@ static inline int qcow2_refresh_zonedmeta(BlockDriverState *bs) { int ret; BDRVQcow2State *s = bs->opaque; - uint64_t *temp = g_malloc(s->zoned_header.zonedmeta_size); + uint64_t wps_size = s->zoned_header.zonedmeta_size - + s->zded_size; + g_autofree uint64_t *temp = NULL; + temp = g_new(uint64_t, wps_size); ret = bdrv_pread(bs->file, s->zoned_header.zonedmeta_offset, - s->zoned_header.zonedmeta_size, temp, 0); + wps_size, temp, 0); if (ret < 0) { - error_report("Can not read metadata\n"); + error_report("Can not read metadata"); return ret; } - memcpy(s->wps->wp, temp, s->zoned_header.zonedmeta_size); + g_autofree uint8_t *zded = NULL; + zded = g_try_malloc0(s->zded_size); + ret = bdrv_pread(bs->file, s->zoned_header.zonedmeta_offset + wps_size, + s->zded_size, zded, 0); + if (ret < 0) { + error_report("Can not read zded"); + return ret; + } + + memcpy(s->wps->wp, temp, wps_size); + memcpy(bs->zd_extensions, zded, s->zded_size); return 0; } @@ -607,6 +620,8 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, zoned_ext.zone_size = be32_to_cpu(zoned_ext.zone_size); zoned_ext.zone_capacity = be32_to_cpu(zoned_ext.zone_capacity); + zoned_ext.zd_extension_size = + be32_to_cpu(zoned_ext.zd_extension_size); zoned_ext.nr_zones = be32_to_cpu(zoned_ext.nr_zones); zoned_ext.zone_nr_conv = be32_to_cpu(zoned_ext.zone_nr_conv); zoned_ext.max_open_zones = be32_to_cpu(zoned_ext.max_open_zones); @@ -618,8 +633,10 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, be64_to_cpu(zoned_ext.zonedmeta_offset); zoned_ext.zonedmeta_size = be64_to_cpu(zoned_ext.zonedmeta_size); s->zoned_header = zoned_ext; + s->wps = g_malloc(sizeof(BlockZoneWps) - + s->zoned_header.zonedmeta_size); + + zoned_ext.zonedmeta_size - s->zded_size); + bs->zd_extensions = g_malloc0(s->zded_size); ret = qcow2_refresh_zonedmeta(bs); if (ret < 0) { error_setg_errno(errp, -ret, "zonedmeta: " @@ -2174,6 +2191,7 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.zoned = s->zoned_header.zoned; bs->bl.zoned_profile = s->zoned_header.zoned_profile; bs->bl.zone_capacity = s->zoned_header.zone_capacity; + bs->bl.zd_extension_size = s->zoned_header.zd_extension_size; bs->bl.nr_zones = s->zoned_header.nr_zones; bs->wps = s->wps; bs->bl.max_append_sectors = s->zoned_header.max_append_sectors; @@ -3369,6 +3387,8 @@ int qcow2_update_header(BlockDriverState *bs) .nr_zones = cpu_to_be32(s->zoned_header.nr_zones), .zone_size = cpu_to_be32(s->zoned_header.zone_size), .zone_capacity = cpu_to_be32(s->zoned_header.zone_capacity), + .zd_extension_size = + cpu_to_be32(s->zoned_header.zd_extension_size), .zone_nr_conv = cpu_to_be32(s->zoned_header.zone_nr_conv), .max_open_zones = cpu_to_be32(s->zoned_header.max_open_zones), .max_active_zones = @@ -4075,13 +4095,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) if (qcow2_opts->zoned_profile) { BDRVQcow2State *s = blk_bs(blk)->opaque; - if (!strcmp(qcow2_opts->zoned_profile, "zbc")) { - s->zoned_header.zoned_profile = BLK_ZP_ZBC; - s->zoned_header.zone_capacity = qcow2_opts->zone_size; - } else if (!strcmp(qcow2_opts->zoned_profile, "zns")) { - s->zoned_header.zoned_profile = BLK_ZP_ZNS; - s->zoned_header.zone_capacity = qcow2_opts->zone_capacity; - } + uint64_t zded_size = 0; + s->zoned_header.zoned = BLK_Z_HM; s->zoned_header.zone_size = qcow2_opts->zone_size; s->zoned_header.zone_nr_conv = qcow2_opts->zone_nr_conv; @@ -4119,6 +4134,33 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) meta[i] |= ((uint64_t)BLK_ZS_EMPTY << 60); } + if (!g_strcmp0(qcow2_opts->zoned_profile, "zbc")) { + s->zoned_header.zoned_profile = BLK_ZP_ZBC; + s->zoned_header.zone_capacity = qcow2_opts->zone_size; + } else if (!g_strcmp0(qcow2_opts->zoned_profile, "zns")) { + s->zoned_header.zoned_profile = BLK_ZP_ZNS; + s->zoned_header.zone_capacity = qcow2_opts->zone_capacity; + + if (qcow2_opts->zd_extension_size) { + if (qcow2_opts->zd_extension_size & 0x3f) { + error_setg(errp, "zone descriptor extension size must be a " + "multiple of 64B"); + return -1; + } + if ((qcow2_opts->zd_extension_size >> 6) > 0xff) { + error_setg(errp, + "zone descriptor extension size is too large"); + return -1; + } + } + s->zoned_header.zd_extension_size = qcow2_opts->zd_extension_size; + + zded_size = s->zoned_header.zd_extension_size * + s->zoned_header.nr_zones; + } + s->zded_size = zded_size; + zoned_meta_size += zded_size; + offset = qcow2_alloc_clusters(blk_bs(blk), zoned_meta_size); if (offset < 0) { error_setg_errno(errp, -offset, "Could not allocate clusters " @@ -4138,12 +4180,23 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) error_setg_errno(errp, -ret, "Could not zero fill zoned metadata"); goto out; } - ret = bdrv_pwrite(blk_bs(blk)->file, offset, zoned_meta_size, meta, 0); + ret = bdrv_pwrite(blk_bs(blk)->file, offset, + zoned_meta_size - zded_size, meta, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write zoned metadata " "to disk"); goto out; } + if (s->zoned_header.zoned_profile == BLK_ZP_ZNS) { + /* Initialize zone descriptor extensions */ + ret = bdrv_co_pwrite_zeroes(blk_bs(blk)->file, offset + zded_size, + zded_size, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not write zone descriptor" + "extensions to disk"); + goto out; + } + } } /* Create a full header (including things like feature table) */ @@ -4290,6 +4343,7 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts, { BLOCK_OPT_Z_MAS, "max-append-sectors"}, { BLOCK_OPT_Z_SIZE, "zone-size"}, { BLOCK_OPT_Z_CAP, "zone-capacity"}, + { BLOCK_OPT_Z_DEXTSIZE, "zd-extension-size"}, { NULL, NULL }, }; @@ -6856,6 +6910,12 @@ static QemuOptsList qcow2_create_opts = { .type = QEMU_OPT_SIZE, \ .help = "zone capacity", \ }, \ + { \ + .name = BLOCK_OPT_Z_DEXTSIZE, \ + .type = QEMU_OPT_SIZE, \ + .help = "zone descriptor extension size (defaults " \ + "to 0, must be a multiple of 64 bytes)", \ + }, \ { \ .name = BLOCK_OPT_Z_NR_COV, \ .type = QEMU_OPT_NUMBER, \ diff --git a/block/qcow2.h b/block/qcow2.h index 38b779ae32..254295cfce 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -250,6 +250,8 @@ typedef struct Qcow2ZonedHeaderExtension { uint32_t max_append_sectors; uint64_t zonedmeta_offset; uint64_t zonedmeta_size; + uint32_t zd_extension_size; /* must be multiple of 64 B */ + uint32_t reserved32; } QEMU_PACKED Qcow2ZonedHeaderExtension; typedef struct Qcow2UnknownHeaderExtension { @@ -445,6 +447,7 @@ typedef struct BDRVQcow2State { uint32_t nr_zones_imp_open; uint32_t nr_zones_closed; BlockZoneWps *wps; + uint64_t zded_size; } BDRVQcow2State; typedef struct Qcow2COWRegion { diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 739e2c62c6..beb4ead094 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -356,6 +356,8 @@ The fields of the zoned extension are: 28 - 31: max_append_sectors 32 - 39: zonedmeta_offset 40 - 47: zonedmeta_size + 48 - 51: zd_extension_size + 52 - 55: Reserved, must be zero. == Full disk encryption header pointer == diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 4e1608f0c1..4320f3a15c 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -4010,6 +4010,12 @@ static uint16_t nvme_zone_mgmt_send_zrwa_flush(NvmeCtrl *n, NvmeZone *zone, return NVME_SUCCESS; } +static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns, + uint32_t zone_idx) +{ + return &ns->zd_extensions[zone_idx * blk_get_zd_ext_size(ns->blkconf.blk)]; +} + static uint16_t nvme_zone_mgmt_send(NvmeCtrl *n, NvmeRequest *req) { NvmeZoneSendCmd *cmd = (NvmeZoneSendCmd *)&req->cmd; @@ -4094,11 +4100,11 @@ static uint16_t nvme_zone_mgmt_send(NvmeCtrl *n, NvmeRequest *req) case NVME_ZONE_ACTION_SET_ZD_EXT: trace_pci_nvme_set_descriptor_extension(slba, zone_idx); - if (all || !ns->params.zd_extension_size) { + if (all || !blk_get_zd_ext_size(ns->blkconf.blk)) { return NVME_INVALID_FIELD | NVME_DNR; } zd_ext = nvme_get_zd_extension(ns, zone_idx); - status = nvme_h2c(n, zd_ext, ns->params.zd_extension_size, req); + status = nvme_h2c(n, zd_ext, blk_get_zd_ext_size(ns->blkconf.blk), req); if (status) { trace_pci_nvme_err_zd_extension_map_error(zone_idx); return status; @@ -4189,7 +4195,7 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) if (zra != NVME_ZONE_REPORT && zra != NVME_ZONE_REPORT_EXTENDED) { return NVME_INVALID_FIELD | NVME_DNR; } - if (zra == NVME_ZONE_REPORT_EXTENDED && !ns->params.zd_extension_size) { + if (zra == NVME_ZONE_REPORT_EXTENDED && !blk_get_zd_ext_size(ns->blkconf.blk)){ return NVME_INVALID_FIELD | NVME_DNR; } @@ -4211,7 +4217,7 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) zone_entry_sz = sizeof(NvmeZoneDescr); if (zra == NVME_ZONE_REPORT_EXTENDED) { - zone_entry_sz += ns->params.zd_extension_size; + zone_entry_sz += blk_get_zd_ext_size(ns->blkconf.blk) ; } max_zones = (data_size - sizeof(NvmeZoneReportHeader)) / zone_entry_sz; @@ -4249,11 +4255,12 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) } if (zra == NVME_ZONE_REPORT_EXTENDED) { + int zd_ext_size = blk_get_zd_ext_size(ns->blkconf.blk); if (zone->d.za & NVME_ZA_ZD_EXT_VALID) { memcpy(buf_p, nvme_get_zd_extension(ns, zone_idx), - ns->params.zd_extension_size); + zd_ext_size); } - buf_p += ns->params.zd_extension_size; + buf_p += zd_ext_size; } max_zones--; diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index f076593ada..c9c3a54d36 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -218,15 +218,15 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) static void nvme_ns_zoned_init_state(NvmeNamespace *ns) { + BlockBackend *blk = ns->blkconf.blk; uint64_t start = 0, zone_size = ns->zone_size; uint64_t capacity = ns->num_zones * zone_size; NvmeZone *zone; int i; ns->zone_array = g_new0(NvmeZone, ns->num_zones); - if (ns->params.zd_extension_size) { - ns->zd_extensions = g_malloc0(ns->params.zd_extension_size * - ns->num_zones); + if (blk_get_zone_extension(blk)) { + ns->zd_extensions = blk_get_zone_extension(blk); } QTAILQ_INIT(&ns->exp_open_zones); @@ -275,7 +275,7 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) for (i = 0; i <= ns->id_ns.nlbaf; i++) { id_ns_z->lbafe[i].zsze = cpu_to_le64(ns->zone_size); id_ns_z->lbafe[i].zdes = - ns->params.zd_extension_size >> 6; /* Units of 64B */ + blk_get_zd_ext_size(blk) >> 6; /* Units of 64B */ } if (ns->params.zrwas) { @@ -577,19 +577,6 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) } if (blk_get_zone_model(blk)) { - if (ns->params.zd_extension_size) { - if (ns->params.zd_extension_size & 0x3f) { - error_setg(errp, "zone descriptor extension size must be a " - "multiple of 64B"); - return -1; - } - if ((ns->params.zd_extension_size >> 6) > 0xff) { - error_setg(errp, - "zone descriptor extension size is too large"); - return -1; - } - } - if (ns->params.zrwas) { if (ns->params.zrwas % ns->blkconf.logical_block_size) { error_setg(errp, "zone random write area size (zoned.zrwas " @@ -677,7 +664,6 @@ void nvme_ns_cleanup(NvmeNamespace *ns) if (blk_get_zone_model(ns->blkconf.blk)) { g_free(ns->id_ns_zoned); g_free(ns->zone_array); - g_free(ns->zd_extensions); } if (ns->endgrp && ns->endgrp->fdp.enabled) { @@ -795,8 +781,6 @@ static Property nvme_ns_props[] = { params.max_active_zones, 0), DEFINE_PROP_UINT32("zoned.max_open", NvmeNamespace, params.max_open_zones, 0), - DEFINE_PROP_UINT32("zoned.descr_ext_size", NvmeNamespace, - params.zd_extension_size, 0), DEFINE_PROP_UINT32("zoned.numzrwa", NvmeNamespace, params.numzrwa, 0), DEFINE_PROP_SIZE("zoned.zrwas", NvmeNamespace, params.zrwas, 0), DEFINE_PROP_SIZE("zoned.zrwafg", NvmeNamespace, params.zrwafg, -1), diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 76677a86e9..37007952fc 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -192,7 +192,6 @@ typedef struct NvmeNamespaceParams { bool cross_zone_read; uint32_t max_active_zones; uint32_t max_open_zones; - uint32_t zd_extension_size; uint32_t numzrwa; uint64_t zrwas; @@ -315,12 +314,6 @@ static inline bool nvme_wp_is_valid(NvmeZone *zone) st != NVME_ZONE_STATE_OFFLINE; } -static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns, - uint32_t zone_idx) -{ - return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size]; -} - static inline void nvme_aor_inc_open(NvmeNamespace *ns) { assert(ns->nr_open_zones >= 0); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 1dbe820a9b..e16dfe8581 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -61,6 +61,7 @@ #define BLOCK_OPT_Z_MODEL "zoned" #define BLOCK_OPT_Z_SIZE "zone_size" #define BLOCK_OPT_Z_CAP "zone_capacity" +#define BLOCK_OPT_Z_DEXTSIZE "zd_extension_size" #define BLOCK_OPT_Z_NR_COV "zone_nr_conv" #define BLOCK_OPT_Z_MAS "max_append_sectors" #define BLOCK_OPT_Z_MAZ "max_active_zones" @@ -907,6 +908,9 @@ typedef struct BlockLimits { uint32_t max_active_zones; uint32_t write_granularity; + + /* size of data that is associated with a zone in bytes */ + uint32_t zd_extension_size; } BlockLimits; typedef struct BdrvOpBlocker BdrvOpBlocker; @@ -1265,6 +1269,8 @@ struct BlockDriverState { /* array of write pointers' location of each zone in the zoned device. */ BlockZoneWps *wps; + + uint8_t *zd_extensions; }; struct BlockBackendRootState { diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 3be221e752..c56ed29c8f 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -106,6 +106,8 @@ uint32_t blk_get_zone_capacity(BlockBackend *blk); uint32_t blk_get_max_open_zones(BlockBackend *blk); uint32_t blk_get_max_active_zones(BlockBackend *blk); uint32_t blk_get_max_append_sectors(BlockBackend *blk); +uint8_t *blk_get_zone_extension(BlockBackend *blk); +uint32_t blk_get_zd_ext_size(BlockBackend *blk); void blk_io_plug(void); void blk_io_unplug(void); diff --git a/qapi/block-core.json b/qapi/block-core.json index 0c97ae678b..f71dd18fc3 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -5024,6 +5024,8 @@ # (default: off, since 8.0) # @zone-size: The size of a zone of the zoned device (since 8.0) # @zone-capacity: The capacity of a zone of the zoned device (since 8.0) +# @zd-extension-size: Zone descriptor extension size. Must be a multiple of +# 64 bytes (since 8.0) # @zone-nr-conv: The number of conventional zones of the zoned device # (since 8.0) # @max-open-zones: The maximal allowed open zones (since 8.0) @@ -5052,6 +5054,7 @@ '*zoned-profile': 'str', '*zone-size': 'size', '*zone-capacity': 'size', + '*zd-extension-size': 'size', '*zone-nr-conv': 'uint32', '*max-open-zones': 'uint32', '*max-active-zones': 'uint32', -- 2.40.1