--- a/src/udev/udev-builtin-path_id.c 2022-11-27 20:07:00.000000000 +0200
+++ b/src/udev/udev-builtin-path_id.c 2022-11-28 08:49:17.518446117 +0200
@@ -614,12 +614,51 @@
return parent;
}
+static int find_real_nvme_parent(struct udev_device *dev, struct udev_device **ret) {
+ _cleanup_free_ struct udev_device *nvme = NULL;
+ const char *sysname, *end;
+ struct udev *udev = udev_device_get_udev(dev);
+
+ /* If the device belongs to "nvme-subsystem" (not to be confused with "nvme"), which happens when
+ * NVMe multipathing is enabled in the kernel (/sys/module/nvme_core/parameters/multipath is Y),
+ * then the syspath is something like the following:
+ * /sys/devices/virtual/nvme-subsystem/nvme-subsys0/nvme0n1
+ * Hence, we need to find the 'real parent' in "nvme" subsystem, e.g,
+ * /sys/devices/pci0000:00/0000:00:1c.4/0000:3c:00.0/nvme/nvme0 */
+
+ assert(dev);
+ assert(ret);
+
+ sysname = udev_device_get_sysname(dev);
+ if (sysname == NULL)
+ return -1;
+
+ /* The sysname format of nvme block device is nvme%d[c%d]n%d[p%d], e.g. nvme0n1p2 or nvme0c1n2.
+ * (Note, nvme device with 'c' can be ignored, as they are hidden. )
+ * The sysname format of nvme subsystem device is nvme%d.
+ * See nvme_alloc_ns() and nvme_init_ctrl() in drivers/nvme/host/core.c for more details. */
+ end = startswith(sysname, "nvme");
+ if (!end)
+ return -ENXIO;
+
+ end += strspn(end, "0123456789");
+ sysname = strndupa(sysname, end - sysname);
+
+ nvme = udev_device_new_from_subsystem_sysname(udev, "nvme", sysname);
+ if (nvme == NULL)
+ return -1;
+
+ *ret = TAKE_PTR(nvme);
+ return 0;
+}
+
static int builtin_path_id(struct udev_device *dev, int argc __attribute__((unused)), char *argv[] __attribute__((unused)), bool test) {
struct udev_device *parent;
char *path = NULL;
bool supported_transport = false;
bool supported_parent = false;
char *compat_path = NULL;
+ _cleanup_free_ struct udev_device *dev_other_branch = NULL;
/* S390 ccw bus */
parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
@@ -685,6 +724,36 @@
parent = skip_subsystem(parent, "scm");
supported_transport = true;
supported_parent = true;
+ } else if (streq(subsys, "nvme") || streq(subsys, "nvme-subsystem")) {
+ const char *nsid;
+ int r;
+
+ nsid = udev_device_get_sysattr_value(dev, "nsid");
+ if (nsid != NULL) {
+ path_prepend(&path, "nvme-%s", nsid);
+ if (compat_path)
+ path_prepend(&compat_path, "nvme-%s", nsid);
+
+ if (streq(subsys, "nvme-subsystem")) {
+ r = find_real_nvme_parent(dev, &dev_other_branch);
+ if (r < 0)
+ return r;
+
+ parent = dev_other_branch;
+ }
+
+ parent = skip_subsystem(parent, "nvme");
+ supported_parent = true;
+ supported_transport = true;
+ }
+ } else if (streq(subsys, "spi")) {
+ const char *sysnum;
+
+ sysnum = udev_device_get_sysname(parent);
+ if (sysnum !=NULL) {
+ path_prepend(&path, "cs-%s", sysnum);
+ parent = skip_subsystem(parent, "spi");
+ }
}
parent = udev_device_get_parent(parent);
--- a/src/udev/udev.h 2022-06-14 02:44:42.000000000 +0300
+++ b/src/udev/udev.h 2022-11-28 11:51:02.744444816 +0200
@@ -212,3 +212,11 @@
extern const struct udevadm_cmd udevadm_hwdb;
extern const struct udevadm_cmd udevadm_test;
extern const struct udevadm_cmd udevadm_test_builtin;
+
+#define TAKE_PTR(ptr) \
+ ({ \
+ typeof(ptr) *_pptr_ = &(ptr); \
+ typeof(ptr) _ptr_ = *_pptr_; \
+ *_pptr_ = NULL; \
+ _ptr_; \
+ })
think that #272 is incomplete because some( i mean a lot) nvme devices can belong to nvme-subsystem! see >>Werkov/systemd@cef7269
the right patch could be, like i said in the past, the following one: