Blame SOURCES/0056-Try-even-harder-to-find-disk-device-symlinks-in-sysf.patch

a43681
From 156d7a1e123f85863db854aae5c10acd3864f9d8 Mon Sep 17 00:00:00 2001
a43681
From: Peter Jones <pjones@redhat.com>
a43681
Date: Fri, 11 Oct 2019 14:20:54 -0400
a43681
Subject: [PATCH 56/63] Try even harder to find disk device symlinks in sysfs.
a43681
a43681
Today's realization is that the thing encoded into the structure of
a43681
sysfs is, in the best case, the dependency graph of the makefile targets
a43681
to build a device driver.
a43681
a43681
In the case of nvme-fabric, or really wherever the kernel has
a43681
class_create() and device_create() in the same function, there's an
a43681
extra level of indirection.
a43681
a43681
Anyway, in this patch we stop pretending sysfs isn't completely absurd,
a43681
and just try adding "/device" in the middle of the driver symlink path,
a43681
until we actually either get ENOENT on the device symlink or find a
a43681
device symlink that actually has a driver symlink under it.
a43681
a43681
Signed-off-by: Peter Jones <pjones@redhat.com>
a43681
---
a43681
 src/linux-nvme.c | 13 +++++----
a43681
 src/linux.c      | 46 ++++++++++++++++++--------------
a43681
 src/linux.h      | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
a43681
 3 files changed, 101 insertions(+), 27 deletions(-)
a43681
a43681
diff --git a/src/linux-nvme.c b/src/linux-nvme.c
a43681
index 7b18d7990ac..455c4c7ba9b 100644
a43681
--- a/src/linux-nvme.c
a43681
+++ b/src/linux-nvme.c
a43681
@@ -87,13 +87,12 @@ parse_nvme(struct device *dev, const char *current, const char *root UNUSED)
a43681
 	/*
a43681
 	 * now fish the eui out of sysfs is there is one...
a43681
 	 */
a43681
-	rc = read_sysfs_file(&filebuf,
a43681
-	                     "class/block/nvme%dn%d/eui",
a43681
-	                     ctrl_id, ns_id);
a43681
-	if ((rc < 0 && errno == ENOENT) || filebuf == NULL) {
a43681
-	        rc = read_sysfs_file(&filebuf,
a43681
-	                     "class/block/nvme%dn%d/device/eui",
a43681
-	                     ctrl_id, ns_id);
a43681
+	char *euipath = NULL;
a43681
+	rc = read_sysfs_file(&filebuf, "class/block/nvme%dn%d/eui", ctrl_id, ns_id);
a43681
+	if (rc < 0 && (errno == ENOENT || errno == ENOTDIR)) {
a43681
+		rc = find_device_file(&euipath, "eui", "class/block/nvme%dn%d", ctrl_id, ns_id);
a43681
+		if (rc >= 0 && euipath != NULL)
a43681
+			rc = read_sysfs_file(&filebuf, "%s", euipath);
a43681
 	}
a43681
 	if (rc >= 0 && filebuf != NULL) {
a43681
 	        uint8_t eui[8];
a43681
diff --git a/src/linux.c b/src/linux.c
a43681
index 73c67cbafd3..30db22d95dd 100644
a43681
--- a/src/linux.c
a43681
+++ b/src/linux.c
a43681
@@ -401,26 +401,32 @@ struct device HIDDEN
a43681
 	        goto err;
a43681
 	}
a43681
 
a43681
-	if (dev->device[0] != 0) {
a43681
-	        rc = sysfs_readlink(&tmpbuf, "block/%s/device/driver", dev->disk_name);
a43681
+	/*
a43681
+	 * So, on a normal disk, you get something like:
a43681
+	 * /sys/block/sda/device -> ../../0:0:0:0
a43681
+	 * /sys/block/sda/device/driver -> ../../../../../../../bus/scsi/drivers/sd
a43681
+	 *
a43681
+	 * On a directly attached nvme device you get:
a43681
+	 * /sys/block/nvme0n1/device -> ../../nvme0
a43681
+	 * /sys/block/nvme0n1/device/device -> ../../../0000:6e:00.0
a43681
+	 * /sys/block/nvme0n1/device/device/driver -> ../../../../bus/pci/drivers/nvme
a43681
+	 *
a43681
+	 * On a fabric-attached nvme device, you get something like:
a43681
+	 * /sys/block/nvme0n1/device -> ../../nvme0
a43681
+	 * /sys/block/nvme0n1/device/device -> ../../ctl
a43681
+	 * /sys/block/nvme0n1/device/device/device -> ../../../../../0000:6e:00.0
a43681
+	 * /sys/block/nvme0n1/device/device/device/driver -> ../../../../../../bus/pci/drivers/nvme-fabrics
a43681
+	 *
a43681
+	 * ... I think?  I don't have one in front of me.
a43681
+	 */
a43681
+
a43681
+	char *filepath = NULL;
a43681
+	rc = find_device_file(&filepath, "driver", "block/%s", dev->disk_name);
a43681
+	if (rc >= 0) {
a43681
+		rc = sysfs_readlink(&tmpbuf, "%s", filepath);
a43681
 	        if (rc < 0 || !tmpbuf) {
a43681
-	                if (errno == ENOENT) {
a43681
-	                        /*
a43681
-	                         * nvme, for example, will have nvme0n1/device point
a43681
-	                         * at nvme0, and we need to look for device/driver
a43681
-	                         * there.
a43681
-	                         */
a43681
-	                        rc = sysfs_readlink(&tmpbuf,
a43681
-	                                            "block/%s/device/device/driver",
a43681
-	                                            dev->disk_name);
a43681
-	                        if (rc >= 0 && tmpbuf)
a43681
-	                                efi_error_pop();
a43681
-	                }
a43681
-	                if (rc < 0 || !tmpbuf) {
a43681
-	                        efi_error("readlink of /sys/block/%s/device/driver failed",
a43681
-	                                  dev->disk_name);
a43681
-	                        goto err;
a43681
-	                }
a43681
+			efi_error("readlink of /sys/%s failed", filepath);
a43681
+	                goto err;
a43681
 	        }
a43681
 
a43681
 	        linkbuf = pathseg(tmpbuf, -1);
a43681
@@ -431,7 +437,7 @@ struct device HIDDEN
a43681
 
a43681
 	        dev->driver = strdup(linkbuf);
a43681
 	} else {
a43681
-	        dev->driver = strdup("");
a43681
+		dev->driver = strdup("");
a43681
 	}
a43681
 
a43681
 	if (!dev->driver) {
a43681
diff --git a/src/linux.h b/src/linux.h
a43681
index 5ae64ffaacf..ae9835ef7ce 100644
a43681
--- a/src/linux.h
a43681
+++ b/src/linux.h
a43681
@@ -218,6 +218,22 @@ extern ssize_t HIDDEN make_mac_path(uint8_t *buf, ssize_t size,
a43681
 		_rc;							\
a43681
 	})
a43681
 
a43681
+#define sysfs_access(mode, fmt, args...)				\
a43681
+	({								\
a43681
+		int rc_;						\
a43681
+		char *pn_;						\
a43681
+									\
a43681
+		rc_ = asprintfa(&pn_, "/sys/" fmt, ## args);		\
a43681
+		if (rc_ >= 0) {						\
a43681
+			rc_ = access(pn_, mode);			\
a43681
+			if (rc_ < 0)					\
a43681
+				efi_error("could not access %s", pn_);  \
a43681
+		} else {						\
a43681
+			efi_error("could not allocate memory");		\
a43681
+		}							\
a43681
+		rc_;							\
a43681
+	})
a43681
+
a43681
 #define sysfs_stat(statbuf, fmt, args...)				\
a43681
 	({								\
a43681
 		int rc_;						\
a43681
@@ -251,6 +267,59 @@ extern ssize_t HIDDEN make_mac_path(uint8_t *buf, ssize_t size,
a43681
 		dir_;							\
a43681
 	})
a43681
 
a43681
+/*
a43681
+ * Iterate a /sys/block directory looking for device/foo, device/device/foo,
a43681
+ * etc.  I'm not proud of this method.
a43681
+ */
a43681
+#define find_device_file(result, name, fmt, args...)				\
a43681
+	({									\
a43681
+		int rc_ = 0;							\
a43681
+		debug("searching for %s from in %s", name, dev->disk_name);	\
a43681
+		for (unsigned int try_ = 0; true; try_++) {			\
a43681
+			char slashdev_[sizeof("device")				\
a43681
+				       + try_ * strlen("/device")];		\
a43681
+										\
a43681
+			char *nul_ = stpcpy(slashdev_, "device");		\
a43681
+			for (unsigned int i_ = 0; i_ < try_; i_++)		\
a43681
+				nul_ = stpcpy(nul_, "/device");			\
a43681
+										\
a43681
+			debug("trying /sys/" fmt "/%s/%s",			\
a43681
+			      ## args, slashdev_, name);			\
a43681
+										\
a43681
+			rc_ = sysfs_access(F_OK, fmt "/%s", ## args, slashdev_);\
a43681
+			if (rc_ < 0) {						\
a43681
+				if (errno == ENOENT) {				\
a43681
+					efi_error_pop();			\
a43681
+					break;					\
a43681
+				}						\
a43681
+				efi_error("cannot access /sys/"fmt"/%s: %m",	\
a43681
+					  ## args, slashdev_);			\
a43681
+				goto find_device_link_err_;			\
a43681
+			}							\
a43681
+										\
a43681
+			rc_ = sysfs_access(F_OK, fmt "/%s/%s",			\
a43681
+					   ## args, slashdev_, name);		\
a43681
+			if (rc_ < 0) {						\
a43681
+				if (errno == ENOENT) {				\
a43681
+					efi_error_pop();			\
a43681
+					break;					\
a43681
+				}						\
a43681
+				efi_error("cannot access /sys/"fmt"/%s/%s: %m",	\
a43681
+					  ## args, slashdev_, name);		\
a43681
+				goto find_device_link_err_;			\
a43681
+			}							\
a43681
+										\
a43681
+			rc_ = asprintfa(result, fmt "/%s/%s",			\
a43681
+					## args, slashdev_, name);		\
a43681
+			if (rc_ < 0) {						\
a43681
+				efi_error("cannot allocate memory: %m");	\
a43681
+				goto find_device_link_err_;			\
a43681
+			}							\
a43681
+		}								\
a43681
+find_device_link_err_:								\
a43681
+		rc_;								\
a43681
+	})
a43681
+
a43681
 #define DEV_PROVIDES_ROOT       1
a43681
 #define DEV_PROVIDES_HD	 2
a43681
 #define DEV_ABBREV_ONLY	 4
a43681
-- 
a43681
2.26.2
a43681