You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mdadm/SOURCES/0162-imsm-get-bus-from-VMD-...

147 lines
4.1 KiB

From 6e793aeace463d7687656f7ac6968300ba106228 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 8 Aug 2024 13:07:50 +0200
Subject: [PATCH 162/201] 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>
---
platform-intel.c | 88 ++++++++++++++++++++++++++++++++++++++++++------
1 file 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;
}
--
2.41.0