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

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