[--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
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
----
#include "nvme-wrap.h"
#include "util/argconfig.h"
+#include "util/suffix.h"
#include "fabrics.h"
#define CREATE_CMD
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 "\
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;
__u32 timeout;
__u8 csi;
__u64 lbstm;
+ char *nsze_si;
+ char *ncap_si;
};
struct config cfg = {
.timeout = 120000,
.csi = 0,
.lbstm = 0,
+ .nsze_si = NULL,
+ .ncap_si = NULL,
};
OPT_ARGS(opts) = {
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()
};
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),
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')
--- /dev/null
+// 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;
+}
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;
#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);