imsm: Limit support to the lowest namespace

First namespace existence is not quaranted by NVMe specification.
Instead first the smallest one shall be chosen.

Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
This commit is contained in:
Mariusz Tkaczyk 2021-05-17 16:39:02 +02:00 committed by Jes Sorensen
parent fcebeb77b1
commit 8662f92d71
3 changed files with 125 additions and 86 deletions

View File

@ -879,36 +879,75 @@ char *vmd_domain_to_controller(struct sys_dev *hba, char *buf)
closedir(dir); closedir(dir);
return NULL; return NULL;
} }
/* Verify that NVMe drive is supported by IMSM
/* Scan over all controller's namespaces and compare nsid value to verify if
* current one is supported. The routine doesn't check IMSM capabilities for
* namespace. Only one nvme namespace is supported by IMSM.
* Paramteres:
* fd - open descriptor to the nvme namespace
* verbose - error logging level
* Returns: * Returns:
* 0 - not supported * 1 - if namespace is supported
* 1 - supported * 0 - otherwise
*/ */
int imsm_is_nvme_supported(int disk_fd, int verbose) int imsm_is_nvme_namespace_supported(int fd, int verbose)
{ {
char nsid_path[PATH_MAX]; DIR *dir = NULL;
char buf[PATH_MAX]; struct dirent *ent;
struct stat stb; char cntrl_path[PATH_MAX];
char ns_path[PATH_MAX];
unsigned long long lowest_nsid = ULLONG_MAX;
unsigned long long this_nsid;
int rv = 0;
if (disk_fd < 0)
return 0;
if (fstat(disk_fd, &stb)) if (!diskfd_to_devpath(fd, 1, cntrl_path) ||
return 0; !diskfd_to_devpath(fd, 0, ns_path)) {
snprintf(nsid_path, PATH_MAX-1, "/sys/dev/block/%d:%d/nsid",
major(stb.st_rdev), minor(stb.st_rdev));
if (load_sys(nsid_path, buf, sizeof(buf))) {
pr_err("Cannot read %s, rejecting drive\n", nsid_path);
return 0;
}
if (strtoll(buf, NULL, 10) != 1) {
if (verbose) if (verbose)
pr_err("Only first namespace is supported by IMSM, aborting\n"); pr_err("Cannot get device paths\n");
return 0; goto abort;
} }
return 1;
if (devpath_to_ll(ns_path, "nsid", &this_nsid)) {
if (verbose)
pr_err("Cannot read nsid value for %s",
basename(ns_path));
goto abort;
}
dir = opendir(cntrl_path);
if (!dir)
goto abort;
/* The lowest nvme namespace is supported */
for (ent = readdir(dir); ent; ent = readdir(dir)) {
unsigned long long curr_nsid;
char curr_ns_path[PATH_MAX + 256];
if (!strstr(ent->d_name, "nvme"))
continue;
snprintf(curr_ns_path, sizeof(curr_ns_path), "%s/%s",
cntrl_path, ent->d_name);
if (devpath_to_ll(curr_ns_path, "nsid", &curr_nsid))
goto abort;
if (lowest_nsid > curr_nsid)
lowest_nsid = curr_nsid;
}
if (this_nsid == lowest_nsid)
rv = 1;
else if (verbose)
pr_err("IMSM is supported on the lowest NVMe namespace\n");
abort:
if (dir)
closedir(dir);
return rv;
} }
/* Verify if multipath is supported by NVMe controller /* Verify if multipath is supported by NVMe controller

View File

@ -254,6 +254,6 @@ const struct orom_entry *get_orom_entry_by_device_id(__u16 dev_id);
const struct imsm_orom *get_orom_by_device_id(__u16 device_id); const struct imsm_orom *get_orom_by_device_id(__u16 device_id);
struct sys_dev *device_by_id(__u16 device_id); struct sys_dev *device_by_id(__u16 device_id);
struct sys_dev *device_by_id_and_path(__u16 device_id, const char *path); struct sys_dev *device_by_id_and_path(__u16 device_id, const char *path);
int imsm_is_nvme_supported(int disk_fd, int verbose);
int is_multipath_nvme(int disk_fd); int is_multipath_nvme(int disk_fd);
int imsm_is_nvme_namespace_supported(int disk_fd, int verbose);
char *vmd_domain_to_controller(struct sys_dev *hba, char *buf); char *vmd_domain_to_controller(struct sys_dev *hba, char *buf);

View File

@ -2381,49 +2381,51 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
static int print_nvme_info(struct sys_dev *hba) static int print_nvme_info(struct sys_dev *hba)
{ {
char buf[1024];
char *device_path;
struct dirent *ent; struct dirent *ent;
DIR *dir; DIR *dir;
int fd;
dir = opendir("/sys/block/"); dir = opendir("/sys/block/");
if (!dir) if (!dir)
return 1; return 1;
for (ent = readdir(dir); ent; ent = readdir(dir)) { for (ent = readdir(dir); ent; ent = readdir(dir)) {
if (strstr(ent->d_name, "nvme")) { char ns_path[PATH_MAX];
fd = open_dev(ent->d_name); char cntrl_path[PATH_MAX];
if (fd < 0) char buf[PATH_MAX];
continue; int fd = -1;
if (!imsm_is_nvme_supported(fd, 0)) { if (!strstr(ent->d_name, "nvme"))
if (fd >= 0) goto skip;
close(fd);
continue;
}
device_path = diskfd_to_devpath(fd, 1, NULL); fd = open_dev(ent->d_name);
if (!device_path) { if (fd < 0)
close(fd); goto skip;
continue;
}
if (path_attached_to_hba(device_path, hba->path)) { if (!diskfd_to_devpath(fd, 0, ns_path) ||
fd2devname(fd, buf); !diskfd_to_devpath(fd, 1, cntrl_path))
if (hba->type == SYS_DEV_VMD) goto skip;
printf(" NVMe under VMD : %s", buf);
else if (hba->type == SYS_DEV_NVME) if (!path_attached_to_hba(cntrl_path, hba->path))
printf(" NVMe Device : %s", buf); goto skip;
if (!imsm_read_serial(fd, NULL, (__u8 *)buf,
sizeof(buf))) if (!imsm_is_nvme_namespace_supported(fd, 0))
printf(" (%s)\n", buf); goto skip;
else
printf("()\n"); fd2devname(fd, buf);
} if (hba->type == SYS_DEV_VMD)
free(device_path); printf(" NVMe under VMD : %s", buf);
else if (hba->type == SYS_DEV_NVME)
printf(" NVMe Device : %s", buf);
if (!imsm_read_serial(fd, NULL, (__u8 *)buf,
sizeof(buf)))
printf(" (%s)\n", buf);
else
printf("()\n");
skip:
if (fd > -1)
close(fd); close(fd);
}
} }
closedir(dir); closedir(dir);
@ -5933,14 +5935,8 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
if (!diskfd_to_devpath(fd, 2, pci_dev_path) || if (!diskfd_to_devpath(fd, 2, pci_dev_path) ||
!diskfd_to_devpath(fd, 1, cntrl_path)) { !diskfd_to_devpath(fd, 1, cntrl_path)) {
pr_err("failed to get dev_path, aborting\n"); pr_err("failed to get dev paths, aborting\n");
if (dd->devname)
free(dd->devname);
free(dd);
return 1;
}
if (!imsm_is_nvme_supported(dd->fd, 1)) {
if (dd->devname) if (dd->devname)
free(dd->devname); free(dd->devname);
free(dd); free(dd);
@ -6665,7 +6661,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
{ {
int fd; int fd;
unsigned long long ldsize; unsigned long long ldsize;
struct intel_super *super; struct intel_super *super = NULL;
int rv = 0; int rv = 0;
if (level != LEVEL_CONTAINER) if (level != LEVEL_CONTAINER)
@ -6680,24 +6676,18 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
dev, strerror(errno)); dev, strerror(errno));
return 0; return 0;
} }
if (!get_dev_size(fd, dev, &ldsize)) { if (!get_dev_size(fd, dev, &ldsize))
close(fd); goto exit;
return 0;
}
/* capabilities retrieve could be possible /* capabilities retrieve could be possible
* note that there is no fd for the disks in array. * note that there is no fd for the disks in array.
*/ */
super = alloc_super(); super = alloc_super();
if (!super) { if (!super)
close(fd); goto exit;
return 0;
} if (!get_dev_sector_size(fd, NULL, &super->sector_size))
if (!get_dev_sector_size(fd, NULL, &super->sector_size)) { goto exit;
close(fd);
free_imsm(super);
return 0;
}
rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL); rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
if (rv != 0) { if (rv != 0) {
@ -6708,32 +6698,42 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
fd, str, super->orom, rv, raiddisks); fd, str, super->orom, rv, raiddisks);
#endif #endif
/* no orom/efi or non-intel hba of the disk */ /* no orom/efi or non-intel hba of the disk */
close(fd); rv = 0;
free_imsm(super); goto exit;
return 0;
} }
close(fd);
if (super->orom) { if (super->orom) {
if (raiddisks > super->orom->tds) { if (raiddisks > super->orom->tds) {
if (verbose) if (verbose)
pr_err("%d exceeds maximum number of platform supported disks: %d\n", pr_err("%d exceeds maximum number of platform supported disks: %d\n",
raiddisks, super->orom->tds); raiddisks, super->orom->tds);
free_imsm(super); goto exit;
return 0;
} }
if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 && if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 &&
(ldsize >> 9) >> 32 > 0) { (ldsize >> 9) >> 32 > 0) {
if (verbose) if (verbose)
pr_err("%s exceeds maximum platform supported size\n", dev); pr_err("%s exceeds maximum platform supported size\n", dev);
free_imsm(super); goto exit;
return 0; }
if (super->hba->type == SYS_DEV_VMD ||
super->hba->type == SYS_DEV_NVME) {
if (!imsm_is_nvme_namespace_supported(fd, 1)) {
if (verbose)
pr_err("NVMe namespace %s is not supported by IMSM\n",
basename(dev));
goto exit;
}
} }
} }
*freesize = avail_size_imsm(st, ldsize >> 9, data_offset); *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
free_imsm(super); rv = 1;
exit:
if (super)
free_imsm(super);
close(fd);
return 1; return rv;
} }
static unsigned long long find_size(struct extent *e, int *idx, int num_extents) static unsigned long long find_size(struct extent *e, int *idx, int num_extents)