diff options
author | Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com> | 2024-08-08 13:07:50 +0200 |
---|---|---|
committer | Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com> | 2024-08-30 11:08:42 +0200 |
commit | 6e793aeace463d7687656f7ac6968300ba106228 (patch) | |
tree | 64ce13c3a60e0d7b03427707a81c565c5c011854 | |
parent | imsm: add read OROM form ACPI UEFI tables (diff) | |
download | mdadm-6e793aeace463d7687656f7ac6968300ba106228.tar.xz mdadm-6e793aeace463d7687656f7ac6968300ba106228.zip |
imsm: get bus from VMD driver directory
Enumeration of VMD child devices is started early, kernel is not waiting
for VMD enumeration to finish. It causes that:
/sys/bus/pci/drivers/vmd/{dev}/domain/device link might be not yet ready.
With PCI gen5 devices we can observe that mdadm is failing to start IMSM
raid arrays because of that. In that case, it needs to find bus path
manually.
Look for bus device in VMD driver directory if realpath() failed with
ENOENT.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
-rw-r--r-- | platform-intel.c | 88 |
1 files changed, 77 insertions, 11 deletions
diff --git a/platform-intel.c b/platform-intel.c index 9705c925..d0ef9111 100644 --- a/platform-intel.c +++ b/platform-intel.c @@ -105,12 +105,75 @@ static void free_sys_dev(struct sys_dev **list) } } +/** + * vmd_find_pci_bus() - look for PCI bus created by VMD. + * @vmd_path: path to vmd driver. + * @buf: return buffer, must be PATH_MAX. + * + * Each VMD device represents one domain and each VMD device adds separate PCI bus. + * IMSM must know VMD domains, therefore it needs to determine and follow buses. + * + */ +mdadm_status_t vmd_find_pci_bus(char *vmd_path, char *buf) +{ + char tmp[PATH_MAX]; + struct dirent *ent; + DIR *vmd_dir; + char *rp_ret; + + snprintf(tmp, PATH_MAX, "%s/domain/device", vmd_path); + + rp_ret = realpath(tmp, buf); + + if (rp_ret) + return MDADM_STATUS_SUCCESS; + + if (errno != ENOENT) + return MDADM_STATUS_ERROR; + + /* + * If it is done early, there is a chance that kernel is still enumerating VMD device but + * kernel did enough to start enumerating child devices, {vmd_path}/domain/device link may + * not exist yet. We have to look into @vmd_path directory and find it ourselves. + */ + + vmd_dir = opendir(vmd_path); + + if (!vmd_dir) + return MDADM_STATUS_ERROR; + + for (ent = readdir(vmd_dir); ent; ent = readdir(vmd_dir)) { + static const char pci[] = "pci"; + + /** + * Pci bus must have form pciXXXXX:XX, where X is a digit i.e pci10000:00. + * We do not check digits here, it is sysfs so it should be safe to check + * length and ':' position only. + */ + if (strncmp(ent->d_name, pci, strlen(pci)) != 0) + continue; + + if (ent->d_name[8] != ':' || ent->d_name[11] != 0) + continue; + break; + } + + if (!ent) { + closedir(vmd_dir); + return MDADM_STATUS_ERROR; + } + + snprintf(buf, PATH_MAX, "%s/%s", vmd_path, ent->d_name); + closedir(vmd_dir); + return MDADM_STATUS_SUCCESS; +} + struct sys_dev *find_driver_devices(const char *bus, const char *driver) { /* search sysfs for devices driven by 'driver' */ char path[PATH_MAX]; char link[PATH_MAX]; - char *c, *p; + char *c; DIR *driver_dir; struct dirent *de; struct sys_dev *head = NULL; @@ -142,8 +205,9 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) return NULL; } for (de = readdir(driver_dir); de; de = readdir(driver_dir)) { - int n; int skip = 0; + char *p; + int n; /* is 'de' a device? check that the 'subsystem' link exists and * that its target matches 'bus' @@ -195,18 +259,20 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) if (devpath_to_ll(path, "class", &class) != 0) continue; - /* - * Each VMD device (domain) adds separate PCI bus, it is better - * to store path as a path to that bus (easier further - * determination which NVMe dev is connected to this particular - * VMD domain). - */ if (type == SYS_DEV_VMD) { - sprintf(path, "/sys/bus/%s/drivers/%s/%s/domain/device", - bus, driver, de->d_name); + char vmd_path[PATH_MAX]; + + sprintf(vmd_path, "/sys/bus/%s/drivers/%s/%s", bus, driver, de->d_name); + + if (vmd_find_pci_bus(vmd_path, path)) { + pr_err("Cannot determine VMD bus for %s\n", vmd_path); + continue; + } } + p = realpath(path, NULL); - if (p == NULL) { + + if (!p) { pr_err("Unable to get real path for '%s'\n", path); continue; } |