From 2100609ddefbe5f2c93a6ba8fcf82e9adc3abcb9 Mon Sep 17 00:00:00 2001 From: Olaf Schmerse Date: Tue, 19 Oct 2021 12:05:59 +0200 Subject: [PATCH] nvme: open namespace exclusive by default All data modifying functions open the namespace exclusive. With the --force option this can be bypassed. Signed-off-by: Olaf Schmerse --- nvme-print.c | 7 +++++ nvme-print.h | 1 + nvme.c | 86 +++++++++++++++++++++++++++------------------------- 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/nvme-print.c b/nvme-print.c index 894d2571..433723e1 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -6909,3 +6909,10 @@ void nvme_show_list_items(nvme_root_t r, enum nvme_print_flags flags) else nvme_show_simple_list(r); } + +void nvme_show_busy_namespace(char *namespace) { + fprintf(stderr, "Failed to open %s.\n"\ + "Namespace is currently busy.\n"\ + "Use the force [--force] option to ignore that.\n", + namespace); +} diff --git a/nvme-print.h b/nvme-print.h index 92cb7f20..6bf37d92 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -120,6 +120,7 @@ void nvme_show_zns_report_zones(void *report, __u32 descs, void json_nvme_finish_zone_list(__u64 nr_zones, struct json_object *zone_list); void nvme_show_list_item(nvme_ns_t n); +void nvme_show_busy_namespace(char *namespace); const char *nvme_cmd_to_string(int admin, __u8 opcode); const char *nvme_select_to_string(int sel); diff --git a/nvme.c b/nvme.c index dd4ba433..c6233025 100644 --- a/nvme.c +++ b/nvme.c @@ -242,29 +242,32 @@ static int get_dev(int argc, char **argv, int flags) int parse_and_open(int argc, char **argv, const char *desc, const struct argconfig_commandline_options *opts) { + const struct argconfig_commandline_options *s; + int flags = O_RDONLY; int ret; ret = argconfig_parse(argc, argv, desc, opts); if (ret) return ret; - ret = get_dev(argc, argv, O_RDONLY); - if (ret < 0) - argconfig_print_help(desc, opts); + for (s = opts; (s->option != NULL) && (s != NULL); s++) { + if (!strcmp(s->option, "force")) { + if (! *(int *) s->default_value) + flags |= O_EXCL; + break; + } + } + ret = get_dev(argc, argv, flags); + if (ret < 0) { + if (errno == EBUSY) + nvme_show_busy_namespace(basename(argv[optind])); + else + argconfig_print_help(desc, opts); + } return ret; } -int open_exclusive(int argc, char **argv, int force) -{ - int flags = O_RDONLY; - - if (!force) - flags |= O_EXCL; - - return get_dev(argc, argv, flags); -} - enum nvme_print_flags validate_output_format(const char *format) { if (!format) @@ -3716,6 +3719,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p const char *ause_desc = "Allow unrestricted sanitize exit."; const char *sanact_desc = "Sanitize action."; const char *ovrpat_desc = "Overwrite pattern."; + const char *force_desc = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; int fd, ret; @@ -3726,6 +3730,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p int ause; __u8 sanact; __u32 ovrpat; + int force; }; struct config cfg = { @@ -3735,6 +3740,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p .ause = 0, .sanact = 0, .ovrpat = 0, + .force = 0, }; OPT_ARGS(opts) = { @@ -3744,6 +3750,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p OPT_FLAG("ause", 'u', &cfg.ause, ause_desc), OPT_BYTE("sanact", 'a', &cfg.sanact, sanact_desc), OPT_UINT("ovrpat", 'p', &cfg.ovrpat, ovrpat_desc), + OPT_FLAG("force", 'f', &cfg.force, force_desc), OPT_END() }; @@ -4107,24 +4114,6 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu OPT_END() }; - err = argconfig_parse(argc, argv, desc, opts); - if (err) - goto ret; - - err = fd = open_exclusive(argc, argv, cfg.force); - if (fd < 0) { - if (errno == EBUSY) { - fprintf(stderr, "Failed to open %s.\n", - basename(argv[optind])); - fprintf(stderr, - "Namespace is currently busy.\n" - "Use the force [--force|-f] option to ignore that.\n"); - } else { - argconfig_print_help(desc, opts); - } - goto ret; - } - err = fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) goto ret; @@ -4738,23 +4727,27 @@ static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin const char *namespace_id = "desired namespace"; const char *start_block = "64-bit LBA of first block to access"; const char *block_count = "number of blocks (zeroes based) on device to access"; + const char *force_desc = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; struct config { __u64 start_block; __u32 namespace_id; __u16 block_count; + int force; }; struct config cfg = { .start_block = 0, .namespace_id = 0, .block_count = 0, + .force = 0, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), + OPT_FLAG("force", 'f', &cfg.force, force_desc), OPT_END() }; @@ -4795,7 +4788,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi const char *start_block = "64-bit LBA of first block to access"; const char *block_count = "number of blocks (zeroes based) on device to access"; const char *limited_retry = "limit media access attempts"; - const char *force = "force device to commit data before command completes"; + const char *force_unit_access = "force device to commit data before command completes"; const char *prinfo = "PI and check field"; const char *ref_tag = "reference tag (for end to end PI)"; const char *app_tag_mask = "app tag mask (for end to end PI)"; @@ -4805,6 +4798,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi const char *deac = "Set DEAC bit, requesting controller to deallocate specified logical blocks"; const char *storage_tag_check = "This bit specifies the Storage Tag field shall be checked as "\ "part of end-to-end data protection processing"; + const char *force = "The \"I know what I'm doing\" flag, open device even it is already used"; struct config { __u64 start_block; @@ -4819,6 +4813,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi int limited_retry; int force_unit_access; int storage_tag_check; + int force; }; struct config cfg = { @@ -4830,6 +4825,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi .app_tag = 0, .storage_tag = 0, .storage_tag_check = 0, + .force = 0, }; OPT_ARGS(opts) = { @@ -4838,13 +4834,14 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_FLAG("deac", 'd', &cfg.deac, deac), OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), - OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force), + OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), + OPT_FLAG("force", 0, &cfg.force, force), OPT_END() }; @@ -5520,7 +5517,7 @@ static int submit_io(int opcode, char *command, const char *desc, const char *app_tag = "app tag (for end to end PI)"; const char *limited_retry = "limit num. media access attempts"; const char *latency = "output latency statistics"; - const char *force = "force device to commit data before command completes"; + const char *force_unit_access = "force device to commit data before command completes"; const char *show = "show command before sending"; const char *dry = "show command instead of sending"; const char *dtype = "directive type (for write-only)"; @@ -5530,6 +5527,7 @@ static int submit_io(int opcode, char *command, const char *desc, "checked as part of end-to-end data protection processing"; const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ "(for end to end PI)"; + const char *force = "The \"I know what I'm doing\" flag, open device even it is already in use"; struct config { __u32 namespace_id; @@ -5553,22 +5551,24 @@ static int submit_io(int opcode, char *command, const char *desc, int show; int dry_run; int latency; + int force; }; struct config cfg = { .namespace_id = 0, .start_block = 0, .block_count = 0, - .data_size = 0, + .data_size = 0, .metadata_size = 0, - .ref_tag = 0, - .data = "", - .metadata = "", - .prinfo = 0, + .ref_tag = 0, + .data = "", + .metadata = "", + .prinfo = 0, .app_tag_mask = 0, - .app_tag = 0, + .app_tag = 0, .storage_tag_check = 0, .storage_tag = 0, + .force = 0, }; OPT_ARGS(opts) = { @@ -5585,7 +5585,7 @@ static int submit_io(int opcode, char *command, const char *desc, OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), OPT_SUFFIX("storage-tag", 'g', &cfg.storage_tag, storage_tag), OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), - OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force), + OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype), OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), @@ -5593,9 +5593,13 @@ static int submit_io(int opcode, char *command, const char *desc, OPT_FLAG("show-command", 'v', &cfg.show, show), OPT_FLAG("dry-run", 'w', &cfg.dry_run, dry), OPT_FLAG("latency", 't', &cfg.latency, latency), + OPT_FLAG("force", 0, &cfg.force, force), OPT_END() }; + if (opcode != nvme_cmd_write) + cfg.force = 1; + err = fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) goto ret; -- 2.50.1