From: Tokunori Ikegami Date: Wed, 28 Dec 2022 10:18:30 +0000 (+0900) Subject: nvme: create-ns: Add nsze-si and ncap-si arguments to set in standard SI units X-Git-Tag: v2.3~24^2 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=de1170dd71d1fa7d2648be92d5cfb514dcbbda3a;p=users%2Fsagi%2Fnvme-cli.git nvme: create-ns: Add nsze-si and ncap-si arguments to set in standard SI units This is proposed by the issue #1747. The value suffixed SI is divided by the namespace LBA size to set as NSZE and NCAP. If the value not suffixed it is set as same with the nsze and ncap options. Note: The existing nsze/ncap arguments follow the specification defined units. Signed-off-by: Tokunori Ikegami --- diff --git a/Documentation/nvme-create-ns.txt b/Documentation/nvme-create-ns.txt index a17c70db..dfa56565 100644 --- a/Documentation/nvme-create-ns.txt +++ b/Documentation/nvme-create-ns.txt @@ -19,6 +19,9 @@ SYNOPSIS [--lbstm= | -l ] [--block-size= | -b ] [--timeout= | -t ] + [--nsze-si= | -S ] + [--ncap-si= | -C ] + DESCRIPTION ----------- For the NVMe device given, sends a namespace management command to create @@ -75,10 +78,26 @@ OPTIONS values will be values will be scanned and the lowest numbered will be selected for the create-ns operation. Conflicts with --flbas argument. +-S:: +--nsze-si:: + The namespace size (NSZE) in standard SI units. + The value SI suffixed is divided by the namespace LBA size to set as NSZE. + If the value not suffixed it is set as same with the nsze option. + +-C:: +--ncap-si:: + The namespace capacity (NCAP) in standard SI units. + The value SI suffixed is divided by the namespace LBA size to set as NCAP. + If the value not suffixed it is set as same with the ncap option. EXAMPLES -------- -No examples provided yet. +* Create a namespace: ++ +------------ +# nvme create-ns /dev/nvme0 --nsze 11995709440 --ncap 1199570940 --flbas 0 --dps 0 --nmic 0 +# nvme create-ns /dev/nvme0 --nsze-si 6.14T --ncap 1199570940 --flbas 0 --dps 0 --nmic 0 +------------ NVME ---- diff --git a/nvme.c b/nvme.c index 821237dd..10cfd7ef 100644 --- a/nvme.c +++ b/nvme.c @@ -64,6 +64,7 @@ #include "nvme-wrap.h" #include "util/argconfig.h" +#include "util/suffix.h" #include "fabrics.h" #define CREATE_CMD @@ -2597,6 +2598,86 @@ static int detach_ns(int argc, char **argv, struct command *cmd, struct plugin * return nvme_attach_ns(argc, argv, 0, desc, cmd); } +static int parse_lba_num_si(struct nvme_dev *dev, const char *opt, + const char *val, __u8 flbas, __u64 *num) +{ + bool suffixed = false; + struct nvme_id_ctrl ctrl; + __u32 nsid = 1; + struct nvme_id_ns ns; + int err = -EINVAL; + int i; + int lbas; + struct nvme_ns_list ns_list; + struct nvme_identify_args args = { + .args_size = sizeof(args), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .data = &ns_list, + .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, + .nsid = nsid - 1. + }; + + if (!val) + return 0; + + if (*num) { + fprintf(stderr, + "Invalid specification of both %s and its SI argument, please specify only one\n", + opt); + return err; + } + + err = nvme_cli_identify_ctrl(dev, &ctrl); + if (err) { + if (err < 0) + fprintf(stderr, "identify controller: %s\n", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + + if ((ctrl.oacs & 0x8) >> 3) + nsid = NVME_NSID_ALL; + else { + err = nvme_cli_identify(dev, &args); + if (err) { + if (err < 0) + fprintf(stderr, "identify namespace list: %s", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + nsid = le32_to_cpu(ns_list.ns[0]); + } + + err = nvme_cli_identify_ns(dev, nsid, &ns); + if (err) { + if (err < 0) + fprintf(stderr, "identify namespace: %s", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + + i = flbas & NVME_NS_FLBAS_LOWER_MASK; + lbas = (1 << ns.lbaf[i].ds) + ns.lbaf[i].ms; + + *num = suffix_si_parse(val, &suffixed); + + if (errno) + fprintf(stderr, + "Expected long suffixed integer argument for '%s-si' but got '%s'!\n", + opt, val); + + if (suffixed) + *num /= lbas; + + return errno; +} + static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Send a namespace management command "\ @@ -2616,6 +2697,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * const char *lbstm = "logical block storage tag mask (LBSTM)"; const char *bs = "target block size, specify only if \'FLBAS\' "\ "value not entered"; + const char *nsze_si = "size of ns (NSZE) in standard SI units"; + const char *ncap_si = "capacity of ns (NCAP) in standard SI units"; struct nvme_id_ns ns; struct nvme_dev *dev; @@ -2634,6 +2717,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * __u32 timeout; __u8 csi; __u64 lbstm; + char *nsze_si; + char *ncap_si; }; struct config cfg = { @@ -2648,6 +2733,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * .timeout = 120000, .csi = 0, .lbstm = 0, + .nsze_si = NULL, + .ncap_si = NULL, }; OPT_ARGS(opts) = { @@ -2662,6 +2749,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_BYTE("csi", 'y', &cfg.csi, csi), OPT_SUFFIX("lbstm", 'l', &cfg.lbstm, lbstm), + OPT_STR("nsze-si", 'S', &cfg.nsze_si, nsze_si), + OPT_STR("ncap-si", 'C', &cfg.ncap_si, ncap_si), OPT_END() }; @@ -2713,6 +2802,14 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * goto close_dev; } + err = parse_lba_num_si(dev, "nsze", cfg.nsze_si, cfg.flbas, &cfg.nsze); + if (err) + goto close_dev; + + err = parse_lba_num_si(dev, "ncap", cfg.ncap_si, cfg.flbas, &cfg.ncap); + if (err) + goto close_dev; + struct nvme_id_ns ns2 = { .nsze = cpu_to_le64(cfg.nsze), .ncap = cpu_to_le64(cfg.ncap), diff --git a/tests/meson.build b/tests/meson.build index 6f171373..4095fba5 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -64,6 +64,15 @@ test_uint128 = executable( test('uint128', test_uint128) +test_suffix_si_parse = executable( + 'test-suffix-si-parse', + ['test-suffix-si-parse.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('suffix_si_parse', test_suffix_si_parse) + python_module = import('python') python = python_module.find_installation('python3') diff --git a/tests/test-suffix-si-parse.c b/tests/test-suffix-si-parse.c new file mode 100644 index 00000000..879518bb --- /dev/null +++ b/tests/test-suffix-si-parse.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "../util/suffix.h" +#include "../util/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static int test_rc; + +static void check_num(const char *val, int lbas, __u64 exp, __u64 num) +{ + if (exp == num) + return; + + printf("ERROR: printing {%s} (lbas %d), got '%llu', expected '%llu'\n", + val, lbas, (unsigned long long)num, (unsigned long long)exp); + + test_rc = 1; +} + +struct tonum_test { + const char *val; + int lbas; + const __u64 exp; +}; + +static struct tonum_test tonum_tests[] = { + { "11995709440", 512, 11995709440 }, + { "1199570940", 512, 1199570940 }, + { "6.14T", 512, 11992187500 }, + { "6.14T", 520, 11807692307 }, + { "6.14T", 4096, 1499023437 }, + { "6.14", 512, 0 }, + { "6.14#", 512, 0 }, +}; + +void tonum_test(struct tonum_test *test) +{ + __u64 num; + bool suffixed; + + num = suffix_si_parse(test->val, &suffixed); + + if (suffixed) + num /= test->lbas; + + check_num(test->val, test->lbas, test->exp, num); +} + +int main(void) +{ + unsigned int i; + + test_rc = 0; + + for (i = 0; i < ARRAY_SIZE(tonum_tests); i++) + tonum_test(&tonum_tests[i]); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/util/suffix.c b/util/suffix.c index 6cd4f0b5..3b80fcea 100644 --- a/util/suffix.c +++ b/util/suffix.c @@ -69,6 +69,31 @@ const char *suffix_si_get(double *value) return ""; } +uint64_t suffix_si_parse(const char *value, bool *suffixed) +{ + char *suffix; + double ret; + struct si_suffix *s; + + errno = 0; + ret = strtod(value, &suffix); + if (errno) + return 0; + + for (s = si_suffixes; s->magnitude != 0; s++) { + if (suffix[0] == s->suffix[0]) { + if (suffixed && suffix[0] != '\0') + *suffixed = true; + return ret *= s->magnitude; + } + } + + if (suffix[0] != '\0') + errno = EINVAL; + + return (uint64_t)ret; +} + static struct binary_suffix { int shift; const char *suffix; diff --git a/util/suffix.h b/util/suffix.h index 4f8e041b..7cf2237c 100644 --- a/util/suffix.h +++ b/util/suffix.h @@ -33,8 +33,10 @@ #ifndef __ARGCONFIG_SUFFIX_H__ #include +#include const char *suffix_si_get(double *value); +uint64_t suffix_si_parse(const char *value, bool *suffixed); const char *suffix_binary_get(long long *value); const char *suffix_dbinary_get(double *value); uint64_t suffix_binary_parse(const char *value);