diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 1852beaf0c..587207b66d 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -5973,6 +5973,65 @@ static void stdout_pull_model_ddc_req_log(struct nvme_pull_model_ddc_req_log *lo d((unsigned char *)log->osp, osp_len, 16, 1); } +static void stdout_relatives(nvme_root_t r, const char *name) +{ + struct nvme_resources res; + struct htable_ns_iter it; + bool block = true; + bool first = true; + nvme_ctrl_t c; + nvme_path_t p; + nvme_ns_t n; + int nsid; + int ret; + int id; + + ret = sscanf(name, "nvme%dn%d", &id, &nsid); + + switch (ret) { + case 1: + block = false; + break; + case 2: + break; + default: + return; + } + + nvme_resources_init(r, &res); + + if (block) { + fprintf(stderr, "Namespace %s has parent controller(s):", name); + for (n = htable_ns_getfirst(&res.ht_n, name, &it); n; + n = htable_ns_getnext(&res.ht_n, name, &it)) { + if (nvme_ns_get_ctrl(n)) { + fprintf(stderr, "%s", nvme_ctrl_get_name(nvme_ns_get_ctrl(n))); + break; + } + nvme_namespace_for_each_path(n, p) { + c = nvme_path_get_ctrl(p); + fprintf(stderr, "%s%s", first ? "" : ", ", nvme_ctrl_get_name(c)); + if (first) + first = false; + } + } + fprintf(stderr, "\n\n"); + } else { + c = htable_ctrl_get(&res.ht_c, name); + if (c) { + fprintf(stderr, "Controller %s has child namespace(s):", name); + nvme_ctrl_for_each_ns(c, n) { + fprintf(stderr, "%s%s", first ? "" : ", ", nvme_ns_get_name(n)); + if (first) + first = false; + } + fprintf(stderr, "\n\n"); + } + } + + nvme_resources_free(&res); +} + static struct print_ops stdout_print_ops = { /* libnvme types.h print functions */ .ana_log = stdout_ana_log, @@ -6016,6 +6075,7 @@ static struct print_ops stdout_print_ops = { .predictable_latency_event_agg_log = stdout_predictable_latency_event_agg_log, .predictable_latency_per_nvmset = stdout_predictable_latency_per_nvmset, .primary_ctrl_cap = stdout_primary_ctrl_cap, + .relatives = stdout_relatives, .resv_notification_log = stdout_resv_notif_log, .resv_report = stdout_resv_report, .sanitize_log_page = stdout_sanitize_log, diff --git a/nvme-print.c b/nvme-print.c index 85451fb23e..742999fd69 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -15,6 +15,7 @@ #include "util/suffix.h" #include "util/types.h" #include "common.h" +#include "logging.h" #define nvme_print(name, flags, ...) \ do { \ @@ -490,9 +491,9 @@ void nvme_show_single_property(int offset, uint64_t value64, nvme_print_flags_t nvme_print(single_property, flags, offset, value64); } -void nvme_show_relatives(const char *name) +void nvme_show_relatives(nvme_root_t r, const char *name, nvme_print_flags_t flags) { - /* XXX: TBD */ + nvme_print(relatives, flags, r, name); } void d(unsigned char *buf, int len, int width, int group) diff --git a/nvme-print.h b/nvme-print.h index 2ff562646d..7329f0aec6 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -64,6 +64,7 @@ struct print_ops { void (*predictable_latency_event_agg_log)(struct nvme_aggregate_predictable_lat_event *pea_log, __u64 log_entries, __u32 size, const char *devname); void (*predictable_latency_per_nvmset)(struct nvme_nvmset_predictable_lat_log *plpns_log, __u16 nvmset_id, const char *devname); void (*primary_ctrl_cap)(const struct nvme_primary_ctrl_cap *caps); + void (*relatives)(nvme_root_t r, const char *name); void (*resv_notification_log)(struct nvme_resv_notification_log *resv, const char *devname); void (*resv_report)(struct nvme_resv_status *status, int bytes, bool eds); void (*sanitize_log_page)(struct nvme_sanitize_log_page *sanitize_log, const char *devname); @@ -153,7 +154,7 @@ struct print_ops *nvme_get_binary_print_ops(nvme_print_flags_t flags); void nvme_show_status(int status); void nvme_show_lba_status_info(__u32 result); -void nvme_show_relatives(const char *name); +void nvme_show_relatives(nvme_root_t r, const char *name, nvme_print_flags_t flags); void nvme_show_id_iocs(struct nvme_id_iocs *iocs, nvme_print_flags_t flags); void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, nvme_print_flags_t flags, diff --git a/nvme.c b/nvme.c index 5992335418..c1042066a7 100644 --- a/nvme.c +++ b/nvme.c @@ -6335,6 +6335,26 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi return nvme_set_single_property(dev_fd(dev), cfg.offset, cfg.value); } +static void show_relatives(const char *name, nvme_print_flags_t flags) +{ + int err = 0; + + _cleanup_nvme_root_ nvme_root_t r = nvme_create_root(stderr, log_level); + + if (!r) { + nvme_show_error("Failed to create topology root: %s", nvme_strerror(errno)); + return; + } + + err = nvme_scan_topology(r, NULL, NULL); + if (err < 0) { + nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno)); + return; + } + + nvme_show_relatives(r, name, flags); +} + static int format_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Re-format a specified namespace on the\n" @@ -6356,6 +6376,7 @@ static int format_cmd(int argc, char **argv, struct command *cmd, struct plugin __u8 prev_lbaf = 0; int block_size; int err, i; + nvme_print_flags_t flags = NORMAL; struct config { __u32 namespace_id; @@ -6411,6 +6432,12 @@ static int format_cmd(int argc, char **argv, struct command *cmd, struct plugin return err; } + err = validate_output_format(nvme_cfg.output_format, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + if (cfg.lbaf != 0xff && cfg.bs != 0) { nvme_show_error( "Invalid specification of both LBAF and Block Size, please specify only one"); @@ -6523,7 +6550,7 @@ static int format_cmd(int argc, char **argv, struct command *cmd, struct plugin fprintf(stderr, "You are about to format %s, namespace %#x%s.\n", dev->name, cfg.namespace_id, cfg.namespace_id == NVME_NSID_ALL ? "(ALL namespaces)" : ""); - nvme_show_relatives(dev->name); + show_relatives(dev->name, flags); fprintf(stderr, "WARNING: Format may irrevocably delete this device's data.\n" "You have 10 seconds to press Ctrl-C to cancel this operation.\n\n"