diff --git a/nvme.c b/nvme.c index 8a5756777f..aeca6aafbb 100644 --- a/nvme.c +++ b/nvme.c @@ -299,7 +299,48 @@ static bool is_blkdev(struct nvme_dev *dev) return S_ISBLK(dev->direct.stat.st_mode); } -static int open_dev_direct(struct nvme_dev **devp, char *devstr, int flags) +static bool is_nvme_dev(char *dev) +{ + int instance; + int head_instance; + + return sscanf(basename(dev), "nvme%dn%d", &instance, &head_instance) == 1; +} + +static __u32 get_nsid(struct argconfig_commandline_options *opts) +{ + __u32 *nsid = argconfig_get_value(opts, "namespace-id"); + + if (nsid && *nsid != NVME_NSID_ALL) + return *nsid; + + return NVME_NSID_NONE; +} + +static int open_blkdev_direct(char *dev, int flags, __u32 nsid) +{ + _cleanup_free_ char *blkdev = NULL; + int fd = -1; + + if (is_nvme_dev(dev) && nsid) { + if (asprintf(&blkdev, "%sn%d", dev, nsid) < 0) + blkdev = NULL; + } + + if (blkdev) { + fd = open(blkdev, flags); + print_info("blkdev: %s, fd: %d\n", blkdev, fd); + } + + if (fd < 0) { + fd = open(dev, flags); + print_info("dev: %s, fd: %d\n", dev, fd); + } + + return fd; +} + +static int open_dev_direct(struct nvme_dev **devp, char *devstr, int flags, __u32 nsid) { struct nvme_dev *dev; int err; @@ -310,7 +351,7 @@ static int open_dev_direct(struct nvme_dev **devp, char *devstr, int flags) dev->type = NVME_DEV_DIRECT; dev->name = basename(devstr); - err = open(devstr, flags); + err = open_blkdev_direct(devstr, flags, nsid); if (err < 0) { nvme_show_perror(devstr); goto err_free; @@ -412,10 +453,12 @@ static int check_arg_dev(int argc, char **argv) return 0; } -static int get_dev(struct nvme_dev **dev, int argc, char **argv, int flags) +static int get_dev(struct nvme_dev **dev, int argc, char **argv, int flags, + struct argconfig_commandline_options *opts) { char *devname; int ret; + __u32 nsid = get_nsid(opts); ret = check_arg_dev(argc, argv); if (ret) @@ -427,7 +470,7 @@ static int get_dev(struct nvme_dev **dev, int argc, char **argv, int flags) if (!strncmp(devname, "mctp:", strlen("mctp:"))) ret = open_dev_mi_mctp(dev, devname); else - ret = open_dev_direct(dev, devname, flags); + ret = open_dev_direct(dev, devname, flags, nsid); return ret ? -errno : 0; } @@ -457,7 +500,7 @@ int parse_and_open(struct nvme_dev **dev, int argc, char **argv, if (ret) return ret; - ret = get_dev(dev, argc, argv, O_RDONLY); + ret = get_dev(dev, argc, argv, O_RDONLY, opts); if (ret < 0) argconfig_print_help(desc, opts); @@ -465,14 +508,14 @@ int parse_and_open(struct nvme_dev **dev, int argc, char **argv, } int open_exclusive(struct nvme_dev **dev, int argc, char **argv, - int ignore_exclusive) + int ignore_exclusive, struct argconfig_commandline_options *opts) { int flags = O_RDONLY; if (!ignore_exclusive) flags |= O_EXCL; - return get_dev(dev, argc, argv, flags); + return get_dev(dev, argc, argv, flags, opts); } int validate_output_format(const char *format, nvme_print_flags_t *flags) @@ -6182,7 +6225,7 @@ static int format_cmd(int argc, char **argv, struct command *cmd, struct plugin if (err) return err; - err = open_exclusive(&dev, argc, argv, cfg.force); + err = open_exclusive(&dev, argc, argv, cfg.force, opts); if (err) { if (errno == EBUSY) { fprintf(stderr, "Failed to open %s.\n", basename(argv[optind])); @@ -7372,6 +7415,23 @@ static int copy_cmd(int argc, char **argv, struct command *cmd, struct plugin *p return err; } +static void io_cmd_show_error(struct nvme_dev *dev, int err, const char *cmd) +{ + if (err > 0) { + nvme_show_status(err); + return; + } + + nvme_show_init(); + + nvme_show_error("%s: %s", cmd, nvme_strerror(errno)); + + if (is_chardev(dev)) + nvme_show_result("char device provided but blkdev is needed, e.g. /dev/nvme0n1"); + + nvme_show_finish(); +} + static int flush_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Commit data and metadata associated with\n" @@ -7407,10 +7467,8 @@ static int flush_cmd(int argc, char **argv, struct command *cmd, struct plugin * } err = nvme_flush(dev_fd(dev), cfg.namespace_id); - if (err < 0) - nvme_show_error("flush: %s", nvme_strerror(errno)); - else if (err != 0) - nvme_show_status(err); + if (err) + io_cmd_show_error(dev, err, "flush"); else printf("NVMe Flush: success\n"); @@ -7863,7 +7921,7 @@ static int submit_io(int opcode, char *command, const char *desc, int argc, char err = parse_args(argc, argv, desc, opts); if (err) return err; - err = open_exclusive(&dev, argc, argv, cfg.force); + err = open_exclusive(&dev, argc, argv, cfg.force, opts); if (err) { if (errno == EBUSY) { fprintf(stderr, "Failed to open %s.\n", basename(argv[optind])); diff --git a/util/argconfig.c b/util/argconfig.c index 34607202ae..9a3faf0ed6 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -429,3 +429,16 @@ bool argconfig_parse_seen(struct argconfig_commandline_options *s, return false; } + +void *argconfig_get_value(struct argconfig_commandline_options *s, const char *option) +{ + for (; s && s->option; s++) { + if (!strcmp(s->option, option)) { + if (s->seen) + return s->default_value; + break; + } + } + + return NULL; +} diff --git a/util/argconfig.h b/util/argconfig.h index 44d2e4e6ab..f0d2c36b2d 100644 --- a/util/argconfig.h +++ b/util/argconfig.h @@ -190,4 +190,5 @@ int argconfig_parse_comma_sep_array_u64(char *string, __u64 *val, void print_word_wrapped(const char *s, int indent, int start, FILE *stream); bool argconfig_parse_seen(struct argconfig_commandline_options *options, const char *option); +void *argconfig_get_value(struct argconfig_commandline_options *s, const char *option); #endif