From 6f3eca8d70babf777d244319ca137333c0a673ca Mon Sep 17 00:00:00 2001 From: Tom Nabarro Date: Fri, 17 Nov 2023 16:47:44 +0000 Subject: [PATCH] improve json parsing of bdev params with spdk api Required-githooks: true Signed-off-by: Tom Nabarro --- src/bio/bio_config.c | 134 +++++++++++++++++++++++++++++++++++++++++ src/bio/bio_device.c | 100 +++++++++++++++++------------- src/bio/bio_internal.h | 2 + 3 files changed, 194 insertions(+), 42 deletions(-) diff --git a/src/bio/bio_config.c b/src/bio/bio_config.c index 0b369e02780..1a1c9837574 100644 --- a/src/bio/bio_config.c +++ b/src/bio/bio_config.c @@ -935,3 +935,137 @@ bio_read_rpc_srv_settings(const char *nvme_conf, bool *enable, const char **sock rc = 0; return rc; } + +static int +json_decode_bdev_str(struct spdk_json_val *obj, const char *key, char **dst) +{ + struct spdk_json_val *val = NULL; + int rc; + + rc = spdk_json_find_string(obj, key, NULL, &val); + if (rc < 0) { + D_ERROR("Failed to find string value '%s': %s\n", key, strerror(-rc)); + return -DER_INVAL; + } + + rc = spdk_json_decode_string(val, dst); + if (rc < 0) { + D_ERROR("Failed to decode string value for '%s': %s\n", key, strerror(-rc)); + return -DER_INVAL; + } + + return 0; +} + +static struct spdk_json_object_decoder nvme_ns_decoders[] = { + {"id", offsetof(struct ns_t, id), spdk_json_decode_uint32}, +}; + +/** + * Fetch bdev controller parameters from spdk_bdev_dump_info_json output. + * + * \param[out] *b_info Device info struct to populate + * \param[in] json Raw JSON to parse + * \param[in] json_size Number of JSON chars + * + * \returns Zero on success, negative on failure (DER) + */ +int +bio_decode_bdev_params(struct bio_dev_info *b_info, const void *json, int json_size) +{ + struct spdk_json_val *values = NULL; + struct spdk_json_val *ctrlr_data = NULL; + struct spdk_json_val *ns_data = NULL; + void *end; + ssize_t values_cnt; + char *tmp = NULL; + ssize_t rc; + char *end1 = NULL; + + /* Trim chars to get single valid "nvme" object from array. */ + tmp = strstr(json, "{"); + if (tmp == NULL) + return -DER_INVAL; + end1 = strchr(tmp, ']'); + if (end1 == NULL) + return -DER_INVAL; + *end1 = '\0'; + + D_INFO("input JSON: %s\n", tmp); + rc = spdk_json_parse((void *)tmp, end1 - tmp, NULL, 0, &end, + SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS); + if (rc < 0) { + D_ERROR("Parsing config failed: %s\n", strerror(-rc)); + return -DER_INVAL; + } + D_INFO("input JSON Count: %ld\n", rc); + + values_cnt = rc; + D_ALLOC_ARRAY(values, values_cnt); + if (values == NULL) + return -DER_NOMEM; + + rc = spdk_json_parse((void *)tmp, end1 - tmp, values, values_cnt, &end, + SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS); + if (rc != values_cnt) { + D_ERROR("Parsing config failed, want %zd values got %zd\n", values_cnt, rc); + D_GOTO(out, rc = -DER_INVAL); + } + + D_INFO("JSON type: %d\n", values->type); + + rc = json_decode_bdev_str(values, "pci_address", &b_info->bdi_traddr); + if (rc < 0) { + D_ERROR("Failed to decode JSON string value for pci_address: %s\n", strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = spdk_json_find(values, "ctrlr_data", NULL, &ctrlr_data, SPDK_JSON_VAL_OBJECT_BEGIN); + if ((rc < 0) && (ctrlr_data == NULL)) { + D_ERROR("Failed to find ctrlr_data JSON object: %s\n", strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = json_decode_bdev_str(ctrlr_data, "model_number", &b_info->bdi_ctrlr->model); + if (rc < 0) { + D_ERROR("Failed to decode JSON string value for model_number: %s\n", strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = json_decode_bdev_str(ctrlr_data, "serial_number", &b_info->bdi_ctrlr->serial); + if (rc < 0) { + D_ERROR("Failed to decode JSON string value for serial_number: %s\n", + strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = json_decode_bdev_str(ctrlr_data, "firmware_revision", &b_info->bdi_ctrlr->fw_rev); + if (rc < 0) { + D_ERROR("Failed to decode JSON string value for firmware_revision: %s\n", + strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = json_decode_bdev_str(ctrlr_data, "vendor_id", &b_info->bdi_ctrlr->vendor_id); + if (rc < 0) { + D_ERROR("Failed to decode JSON string value for vendor_id: %s\n", strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = spdk_json_find(values, "ns_data", NULL, &ns_data, SPDK_JSON_VAL_OBJECT_BEGIN); + if ((rc < 0) && (ns_data == NULL)) { + D_ERROR("Failed to find ns_data JSON object: %s\n", strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } + + rc = spdk_json_decode_object(ns_data, nvme_ns_decoders, SPDK_COUNTOF(nvme_ns_decoders), + &b_info->bdi_ctrlr->nss); + if (rc < 0) { + D_ERROR("Failed to decode 'id' entry (%s)\n", strerror(-rc)); + D_GOTO(out, rc = -DER_INVAL); + } +out: + D_FREE(values); + + return rc; +} diff --git a/src/bio/bio_device.c b/src/bio/bio_device.c index f46fe7db6b4..c356e49e754 100644 --- a/src/bio/bio_device.c +++ b/src/bio/bio_device.c @@ -463,7 +463,7 @@ bio_replace_dev(struct bio_xs_context *xs_ctxt, uuid_t old_dev_id, static char *json_prefix = NULL; static int -json_write_cb(void *cb_ctx, const void *data, size_t size) +json_write_str_cb(void *cb_ctx, const void *data, size_t size) { char *tmp, *end, **buf_ptr = cb_ctx; @@ -474,9 +474,10 @@ json_write_cb(void *cb_ctx, const void *data, size_t size) if (size <= strlen(json_prefix)) return 0; + D_DEBUG(DB_MGMT, "%s json: %s\n", json_prefix, (char *)data); + tmp = strstr(data, json_prefix); if (tmp) { - tmp += strlen(json_prefix); end = strchr(tmp, '"'); if (end == NULL) @@ -493,7 +494,7 @@ json_write_cb(void *cb_ctx, const void *data, size_t size) } static int -find_in_bdev_json(struct spdk_bdev *bdev, char **buf_ptr, char *prefix) +find_bdev_json_str(struct spdk_bdev *bdev, char **buf_ptr, char *prefix) { struct spdk_json_write_ctx *json; int rc; @@ -503,7 +504,7 @@ find_in_bdev_json(struct spdk_bdev *bdev, char **buf_ptr, char *prefix) json_prefix = prefix; - json = spdk_json_write_begin(json_write_cb, buf_ptr, SPDK_JSON_WRITE_FLAG_FORMATTED); + json = spdk_json_write_begin(json_write_str_cb, buf_ptr, SPDK_JSON_WRITE_FLAG_FORMATTED); if (json == NULL) { D_ERROR("Failed to alloc SPDK json context\n"); D_GOTO(out, rc = -DER_NOMEM); @@ -531,6 +532,40 @@ find_in_bdev_json(struct spdk_bdev *bdev, char **buf_ptr, char *prefix) return rc; } +static int +json_write_cb(void *cb_ctx, const void *json, size_t json_size) +{ + struct bio_dev_info *b_info = cb_ctx; + + return bio_decode_bdev_params(b_info, json, (int)json_size); +} + +static int +json_find_bdev_params(struct spdk_bdev *bdev, struct bio_dev_info *b_info) +{ + struct spdk_json_write_ctx *json; + int rc; + + json = spdk_json_write_begin(json_write_cb, b_info, SPDK_JSON_WRITE_FLAG_FORMATTED); + if (json == NULL) { + D_ERROR("Failed to alloc SPDK json context\n"); + return -DER_NOMEM; + } + + rc = spdk_bdev_dump_info_json(bdev, json); + if (rc != 0) { + D_ERROR("Failed to dump config from SPDK bdev (%s)\n", spdk_strerror(-rc)); + return daos_errno2der(-rc); + } + + rc = spdk_json_write_end(json); + if (rc != 0) { + D_ERROR("Failed to write JSON (%s)\n", spdk_strerror(-rc)); + return daos_errno2der(-rc); + } + + return rc; +} int fill_in_traddr(struct bio_dev_info *b_info, char *dev_name) @@ -551,7 +586,7 @@ fill_in_traddr(struct bio_dev_info *b_info, char *dev_name) if (get_bdev_type(bdev) != BDEV_CLASS_NVME) return 0; - rc = find_in_bdev_json(bdev, &b_info->bdi_traddr, "traddr\": \""); + rc = find_bdev_json_str(bdev, &b_info->bdi_traddr, "traddr\": \""); if (rc != 0) { D_ERROR("Failed to get traddr for %s\n", dev_name); return rc; @@ -564,7 +599,7 @@ static struct bio_dev_info * alloc_dev_info(uuid_t dev_id, char *dev_name, struct smd_dev_info *s_info) { struct bio_dev_info *info; - int tgt_cnt = 0, i, rc; + int tgt_cnt = 0, i; D_ALLOC_PTR(info); if (info == NULL) @@ -577,14 +612,6 @@ alloc_dev_info(uuid_t dev_id, char *dev_name, struct smd_dev_info *s_info) info->bdi_flags |= NVME_DEV_FL_FAULTY; } - if (dev_name != NULL) { - rc = fill_in_traddr(info, dev_name); - if (rc != 0) { - bio_free_dev_info(info); - return NULL; - } - } - if (tgt_cnt != 0) { D_ALLOC_ARRAY(info->bdi_tgts, tgt_cnt); if (info->bdi_tgts == NULL) { @@ -691,8 +718,9 @@ static int alloc_ctrlr_info(uuid_t dev_id, char *dev_name, struct bio_dev_info *b_info) { struct spdk_bdev *bdev; - struct ctrlr_t *w_ctrlr; - int rc; + uint32_t blk_sz; + uint64_t nr_blks; + int rc; D_ASSERT(b_info != NULL); D_ASSERT(b_info->bdi_ctrlr == NULL); @@ -711,44 +739,32 @@ alloc_ctrlr_info(uuid_t dev_id, char *dev_name, struct bio_dev_info *b_info) if (get_bdev_type(bdev) != BDEV_CLASS_NVME) return 0; - D_DEBUG(DB_MGMT, "fetching %s controller details\n", b_info->bdi_traddr); - D_ALLOC_PTR(b_info->bdi_ctrlr); if (b_info->bdi_ctrlr == NULL) return -DER_NOMEM; - w_ctrlr = b_info->bdi_ctrlr; - rc = find_in_bdev_json(bdev, &w_ctrlr->model, "model_number\": \""); - if (rc != 0) { - D_ERROR("Failed to get model_number for %s\n", dev_name); - return rc; - } + D_ALLOC_PTR(b_info->bdi_ctrlr->nss); + if (b_info->bdi_ctrlr->nss == NULL) + return -DER_NOMEM; - rc = find_in_bdev_json(bdev, &w_ctrlr->serial, "serial_number\": \""); - if (rc != 0) { - D_ERROR("Failed to get serial_number for %s\n", dev_name); - return rc; - } + /* Namespace capacity by direct query of SPDK bdev object */ + blk_sz = spdk_bdev_get_block_size(bdev); + nr_blks = spdk_bdev_get_num_blocks(bdev); + b_info->bdi_ctrlr->nss->size = nr_blks * (uint64_t)blk_sz; - rc = find_in_bdev_json(bdev, &w_ctrlr->fw_rev, "firmware_revision\": \""); + /* Controller details and namespace ID by parsing SPDK bdev JSON info */ + rc = json_find_bdev_params(bdev, b_info); if (rc != 0) { - D_ERROR("Failed to get firmware_revision for %s\n", dev_name); + D_ERROR("Failed to get bdev json params for %s\n", dev_name); return rc; } - rc = find_in_bdev_json(bdev, &w_ctrlr->vendor_id, "vendor_id\": \""); - if (rc != 0) { - D_ERROR("Failed to get vendor_id for %s\n", dev_name); - return rc; - } - if (w_ctrlr->vendor_id == NULL) { - D_ERROR("Nil value returned for vendor_id on %s\n", dev_name); - return -DER_INVAL; - } + D_DEBUG(DB_MGMT, "fetched %s controller details\n", b_info->bdi_traddr); + D_DEBUG(DB_MGMT, "namespace %d of size %lu\n", b_info->bdi_ctrlr->nss->id, + b_info->bdi_ctrlr->nss->size); /* Fetch socket ID and PCI device type by enumerating spdk_pci_device list */ - - rc = fetch_pci_dev_info(w_ctrlr, b_info->bdi_traddr); + rc = fetch_pci_dev_info(b_info->bdi_ctrlr, b_info->bdi_traddr); if (rc != 0) { return rc; } diff --git a/src/bio/bio_internal.h b/src/bio/bio_internal.h index 6361768b9fd..dd669a1cd35 100644 --- a/src/bio/bio_internal.h +++ b/src/bio/bio_internal.h @@ -667,4 +667,6 @@ int bio_add_allowed_alloc(const char *nvme_conf, struct spdk_env_opts *opts, int int bio_set_hotplug_filter(const char *nvme_conf); int bio_read_accel_props(const char *nvme_conf); int bio_read_rpc_srv_settings(const char *nvme_conf, bool *enable, const char **sock_addr); +int +bio_decode_bdev_params(struct bio_dev_info *b_info, const void *json, int json_size); #endif /* __BIO_INTERNAL_H__ */