]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
nvme: create-ns: Add nsze-si and ncap-si arguments to set in standard SI units
authorTokunori Ikegami <ikegami.t@gmail.com>
Wed, 28 Dec 2022 10:18:30 +0000 (19:18 +0900)
committerTokunori Ikegami <ikegami.t@gmail.com>
Tue, 3 Jan 2023 13:57:09 +0000 (22:57 +0900)
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 <ikegami.t@gmail.com>
Documentation/nvme-create-ns.txt
nvme.c
tests/meson.build
tests/test-suffix-si-parse.c [new file with mode: 0644]
util/suffix.c
util/suffix.h

index a17c70db703c7cfa19a075a701335dbb66559bb9..dfa56565850e9e0a06e610fb9862285403bce3a8 100644 (file)
@@ -19,6 +19,9 @@ SYNOPSIS
                        [--lbstm=<lbstm> | -l <lbstm>]
                        [--block-size=<block-size> | -b <block-size>]
                        [--timeout=<timeout> | -t <timeout>]
+                       [--nsze-si=<nsze-si> | -S <nsze-si>]
+                       [--ncap-si=<ncap-si> | -C <ncap-si>]
+
 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 821237dd5cf9a1ecb983f65ab1f6a1891fdb823c..10cfd7ef66347ece2dc9be412a44f8b8d9d057ae 100644 (file)
--- 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),
index 6f171373d4286f12304754f842e11822a13a48ec..4095fba561170148676586970dbabec7ffb8de60 100644 (file)
@@ -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 (file)
index 0000000..879518b
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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;
+}
index 6cd4f0b5d3b091b1995c8b4f4ce73c2c40dbf3d4..3b80fceadbc2f0d8f0d9db859e44f08c97ebaf41 100644 (file)
@@ -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;
index 4f8e041bfde447a2587ebe390dd8a08789dc0ecb..7cf2237c393b07398e7bf7a3e633f90db9e602c0 100644 (file)
 #ifndef __ARGCONFIG_SUFFIX_H__
 
 #include <inttypes.h>
+#include <stdbool.h>
 
 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);