@@ -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();
@@ -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, \
@@ -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 {
@@ -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 ==
@@ -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--;
@@ -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),
@@ -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);
@@ -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 {
@@ -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);
@@ -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',
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 <faithilikerun@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(-)