diff --git a/Documentation/nvme-create-ns.txt b/Documentation/nvme-create-ns.txt index 740d05b922..eae7a004d7 100644 --- a/Documentation/nvme-create-ns.txt +++ b/Documentation/nvme-create-ns.txt @@ -98,13 +98,13 @@ OPTIONS -S:: --nsze-si:: - The namespace size (NSZE) in standard SI units. + The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries). 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 namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries). 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. diff --git a/nvme.c b/nvme.c index 14a5411774..efa0fadc74 100644 --- a/nvme.c +++ b/nvme.c @@ -2833,12 +2833,13 @@ static int detach_ns(int argc, char **argv, struct command *cmd, struct plugin * } static int parse_lba_num_si(struct nvme_dev *dev, const char *opt, - const char *val, __u8 flbas, __u64 *num) + const char *val, __u8 flbas, __u64 *num, __u32 align) { _cleanup_free_ struct nvme_ns_list *ns_list = NULL; _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; _cleanup_free_ struct nvme_id_ns *ns = NULL; __u32 nsid = 1; + unsigned int remainder; char *endptr; int err = -EINVAL; int i; @@ -2916,6 +2917,12 @@ static int parse_lba_num_si(struct nvme_dev *dev, const char *opt, return -errno; } + if (endptr[0]) { + remainder = *num % align; + if (remainder) + *num += align - remainder; + } + if (endptr[0] != '\0') *num /= lbas; @@ -2955,9 +2962,11 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * _cleanup_free_ struct nvme_id_ns *ns = NULL; _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err = 0, i; - __u32 nsid; + __u32 nsid, align_nsze, align_ncap; uint16_t num_phandle; uint16_t phndl[128] = { 0, }; + _cleanup_free_ struct nvme_id_ctrl *id = NULL; + _cleanup_free_ struct nvme_id_ns_granularity_list *gr_list = NULL; struct config { __u64 nsze; @@ -3075,11 +3084,43 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * return -EINVAL; } - err = parse_lba_num_si(dev, "nsze", cfg.nsze_si, cfg.flbas, &cfg.nsze); + id = nvme_alloc(sizeof(*id)); + if (!id) + return -ENOMEM; + + err = nvme_identify_ctrl(dev_fd(dev), id); + if (err) { + if (err < 0) { + nvme_show_error("identify-controller: %s", nvme_strerror(errno)); + } else { + fprintf(stderr, "identify controller failed\n"); + nvme_show_status(err); + } + return err; + } + + align_nsze = align_ncap = 1 << 20; /* Default 1 Mb */ + if (id->ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) { + gr_list = nvme_alloc(sizeof(*gr_list)); + if (!gr_list) + return -ENOMEM; + + if (!nvme_identify_ns_granularity(dev_fd(dev), gr_list)) { + struct nvme_id_ns_granularity_desc *desc; + desc = &gr_list->entry[cfg.flbas]; + + if (desc->nszegran) + align_nsze = desc->nszegran; + if (desc->ncapgran) + align_ncap = desc->ncapgran; + } + } + + err = parse_lba_num_si(dev, "nsze", cfg.nsze_si, cfg.flbas, &cfg.nsze, align_nsze); if (err) return err; - err = parse_lba_num_si(dev, "ncap", cfg.ncap_si, cfg.flbas, &cfg.ncap); + err = parse_lba_num_si(dev, "ncap", cfg.ncap_si, cfg.flbas, &cfg.ncap, align_ncap); if (err) return err;