From a7db1f299a1c25fd4ba6ca4ac66e8b2bf2313367 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Sun, 2 Feb 2025 20:04:46 +0900 Subject: [PATCH 1/3] nvme-print: add show_key_value print_ops This is to output a command result as json key and value. Signed-off-by: Tokunori Ikegami --- nvme-print-binary.c | 1 + nvme-print-json.c | 15 +++++++++++++++ nvme-print-stdout.c | 11 +++++++++++ nvme-print.c | 16 ++++++++++++++++ nvme-print.h | 2 ++ 5 files changed, 45 insertions(+) diff --git a/nvme-print-binary.c b/nvme-print-binary.c index 17dfb8511d..b4c34ad50b 100644 --- a/nvme-print-binary.c +++ b/nvme-print-binary.c @@ -435,6 +435,7 @@ static struct print_ops binary_print_ops = { .show_perror = NULL, .show_status = NULL, .show_error_status = NULL, + .show_key_value = NULL, }; struct print_ops *nvme_get_binary_print_ops(nvme_print_flags_t flags) diff --git a/nvme-print-json.c b/nvme-print-json.c index ae82a80125..e8e516cb3e 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -4900,6 +4900,20 @@ static void json_output_perror(const char *msg, va_list ap) json_output_object(r); } +static void json_output_key_value(const char *key, const char *val, va_list ap) +{ + struct json_object *r = json_r ? json_r : json_create_object(); + + _cleanup_free_ char *value = NULL; + + if (vasprintf(&value, val, ap) < 0) + value = NULL; + + obj_add_str(r, key, value ? value : "Could not allocate string"); + + obj_print(r); +} + void json_show_init(void) { json_r = json_create_object(); @@ -5264,6 +5278,7 @@ static struct print_ops json_print_ops = { .show_perror = json_output_perror, .show_status = json_output_status, .show_error_status = json_output_error_status, + .show_key_value = json_output_key_value, }; struct print_ops *nvme_get_json_print_ops(nvme_print_flags_t flags) diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 396dd2bf10..4ff3408330 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -5705,6 +5705,16 @@ static void stdout_perror(const char *msg, va_list ap) perror(error); } +static void stdout_key_value(const char *key, const char *val, va_list ap) +{ + _cleanup_free_ char *value = NULL; + + if (vasprintf(&value, val, ap) < 0) + value = NULL; + + printf("%s: %s\n", key, value ? value : "Could not allocate string"); +} + static void stdout_discovery_log(struct nvmf_discovery_log *log, int numrec) { int i; @@ -6052,6 +6062,7 @@ static struct print_ops stdout_print_ops = { .show_perror = stdout_perror, .show_status = stdout_status, .show_error_status = stdout_error_status, + .show_key_value = stdout_key_value, }; struct print_ops *nvme_get_stdout_print_ops(nvme_print_flags_t flags) diff --git a/nvme-print.c b/nvme-print.c index 554f6ee8a0..85451fb23e 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -1586,6 +1586,22 @@ void nvme_show_perror(const char *msg, ...) va_end(ap); } +void nvme_show_key_value(const char *key, const char *val, ...) +{ + struct print_ops *ops = nvme_print_ops(NORMAL); + va_list ap; + + va_start(ap, val); + + if (nvme_is_output_format_json()) + ops = nvme_print_ops(JSON); + + if (ops && ops->show_key_value) + ops->show_key_value(key, val, ap); + + va_end(ap); +} + void nvme_show_discovery_log(struct nvmf_discovery_log *log, uint64_t numrec, nvme_print_flags_t flags) { diff --git a/nvme-print.h b/nvme-print.h index 7916b276c5..2ff562646d 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -111,6 +111,7 @@ struct print_ops { void (*show_perror)(const char *msg, va_list ap); void (*show_status)(int status); void (*show_error_status)(int status, const char *msg, va_list ap); + void (*show_key_value)(const char *key, const char *val, va_list ap); nvme_print_flags_t flags; }; @@ -334,6 +335,7 @@ void nvme_show_perror(const char *msg, ...); void nvme_show_error_status(int status, const char *msg, ...); void nvme_show_init(void); void nvme_show_finish(void); +void nvme_show_key_value(const char *key, const char *value, ...); bool nvme_is_fabrics_reg(int offset); bool nvme_is_fabrics_optional_reg(int offset); bool nvme_registers_cmbloc_support(__u32 cmbsz); From 5d1d837ce38fb095753bdaf31a7b627a8d5ffea0 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Sun, 2 Feb 2025 20:09:43 +0900 Subject: [PATCH 2/3] nvme: output NS management command result by json This is to use the command result NSID created by TP. Signed-off-by: Tokunori Ikegami --- nvme.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/nvme.c b/nvme.c index f6b981ab1f..5d2af37b07 100644 --- a/nvme.c +++ b/nvme.c @@ -2829,26 +2829,37 @@ static int id_endurance_grp_list(int argc, char **argv, struct command *cmd, return err; } -static void ns_mgmt_show_error(struct nvme_dev *dev, int err, const char *cmd) +static bool is_ns_mgmt_support(struct nvme_dev *dev) { - _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + int err; + _cleanup_free_ struct nvme_id_ctrl *ctrl = nvme_alloc(sizeof(*ctrl)); + + if (ctrl) + return false; + + err = nvme_cli_identify_ctrl(dev, ctrl); + if (err) + return false; + + return le16_to_cpu(ctrl->oacs) & NVME_CTRL_OACS_NS_MGMT; +} + +static void ns_mgmt_show_status(struct nvme_dev *dev, int err, char *cmd, __u32 nsid) +{ if (err < 0) { - nvme_show_error("%s namespace: %s", cmd, nvme_strerror(errno)); + nvme_show_error("%s: %s", cmd, nvme_strerror(errno)); return; } nvme_show_init(); - nvme_show_status(err); - - ctrl = nvme_alloc(sizeof(*ctrl)); - if (!ctrl) - return; - - err = nvme_cli_identify_ctrl(dev, ctrl); if (!err) { - if (!(le16_to_cpu(ctrl->oacs) & NVME_CTRL_OACS_NS_MGMT)) + nvme_show_key_value(cmd, "success"); + nvme_show_key_value("nsid", "%d", nsid); + } else { + nvme_show_status(err); + if (!is_ns_mgmt_support(dev)) nvme_show_result("NS management and attachment not supported"); } @@ -2901,10 +2912,7 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin * } err = nvme_cli_ns_mgmt_delete(dev, cfg.namespace_id, nvme_cfg.timeout); - if (!err) - printf("%s: Success, deleted nsid:%d\n", cmd->name, cfg.namespace_id); - else - ns_mgmt_show_error(dev, err, "delete"); + ns_mgmt_show_status(dev, err, cmd->name, cfg.namespace_id); return err; } @@ -2986,10 +2994,7 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s err = nvme_cli_ns_detach_ctrls(dev, cfg.namespace_id, cntlist); - if (!err) - printf("%s: Success, nsid:%d\n", cmd->name, cfg.namespace_id); - else - ns_mgmt_show_error(dev, err, attach ? "attach" : "detach"); + ns_mgmt_show_status(dev, err, cmd->name, cfg.namespace_id); return err; } @@ -3369,10 +3374,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * data->phndl[i] = cpu_to_le16(phndl[i]); err = nvme_cli_ns_mgmt_create(dev, data, &nsid, nvme_cfg.timeout, cfg.csi); - if (!err) - printf("%s: Success, created nsid:%d\n", cmd->name, nsid); - else - ns_mgmt_show_error(dev, err, "create"); + ns_mgmt_show_status(dev, err, cmd->name, nsid); return err; } From ffeea8394be795ac2d0d051d506e440ddeaf82b2 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Sun, 2 Mar 2025 23:02:25 +0900 Subject: [PATCH 3/3] tests: validate create-ns command nsid json output Also the command output-format is changed to json. Signed-off-by: Tokunori Ikegami --- tests/nvme_test.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/nvme_test.py b/tests/nvme_test.py index 80750f5772..0c66be88a8 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -354,12 +354,13 @@ def create_ns(self, nsze, ncap, flbas, dps): - flbas : new namespace format. - dps : new namespace data protection information. - Returns: - - return code of the nvme create namespace command. + - Popen object of the nvme create namespace command. """ create_ns_cmd = f"{self.nvme_bin} create-ns {self.ctrl} " + \ f"--nsze={str(nsze)} --ncap={str(ncap)} --flbas={str(flbas)} " + \ - f"--dps={str(dps)} --verbose" - return self.exec_cmd(create_ns_cmd) + f"--dps={str(dps)} --verbose --output-format=json" + return subprocess.Popen(create_ns_cmd, shell=True, + stdout=subprocess.PIPE, encoding='utf-8') def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps): """ Wrapper for creating and validating a namespace. @@ -372,8 +373,12 @@ def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps): - Returns: - return 0 on success, error code on failure. """ - err = self.create_ns(nsze, ncap, flbas, dps) + proc = self.create_ns(nsze, ncap, flbas, dps) + err = proc.wait() if err == 0: + json_output = json.loads(proc.stdout.read()) + self.assertEqual(int(json_output['nsid']), nsid, + "ERROR : create namespace failed") id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ f"--namespace-id={str(nsid)}" err = subprocess.call(id_ns_cmd,