Blob Blame History Raw
From 7c798f870900f6f4d4647dd3c88318524d7ccee4 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 17 May 2021 16:39:00 +0200
Subject: [PATCH 04/15] imsm: add generic method to resolve "device" links

Each virtual device is linked with parent by "device". This patch adds
possibility to get previous device in sysfs tree.

Depending on device type, there is a different amount of virutal
layers. The best we can do is allow to directly specify how many
"device" links need to be resolved. This approach also allows to get
previous virtual device, which may contain some attributes.

Simplify fd2devname, this function doesn't require new functionality and
shall use generic fd2kname.

For nvme drives represented via nvme-subystem when path to block
device if requested, then return it without translation.

Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 platform-intel.c | 75 ++++++++++++++++++++++++++++++++++++++------------------
 platform-intel.h |  4 +--
 super-intel.c    | 63 ++++++++++++++++++-----------------------------
 3 files changed, 77 insertions(+), 65 deletions(-)

diff --git a/platform-intel.c b/platform-intel.c
index 2da152f..2ed63ed 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -712,28 +712,61 @@ char *get_nvme_multipath_dev_hw_path(const char *dev_path)
 	return rp;
 }
 
-char *devt_to_devpath(dev_t dev)
+/* Description: Return part or whole realpath for the dev
+ * Parameters:
+ *	dev - the device to be quered
+ *	dev_level - level of "/device" entries. It allows to caller to access
+ *		    virtual or physical devices which are on "path" to quered
+ *		    one.
+ *	buf - optional, must be PATH_MAX size. If set, then will be used.
+ */
+char *devt_to_devpath(dev_t dev, int dev_level, char *buf)
 {
-	char device[46];
-	char *rp;
-	char *buf;
+	char device[PATH_MAX];
+	char *hw_path;
+	int i;
+	unsigned long device_free_len = sizeof(device) - 1;
+	char dev_str[] = "/device";
+	unsigned long dev_str_len = strlen(dev_str);
+
+	snprintf(device, sizeof(device), "/sys/dev/block/%d:%d", major(dev),
+		 minor(dev));
+
+	/* If caller wants block device, return path to it even if it is exposed
+	 * via virtual layer.
+	 */
+	if (dev_level == 0)
+		return realpath(device, buf);
 
-	sprintf(device, "/sys/dev/block/%d:%d/device", major(dev), minor(dev));
+	device_free_len -= strlen(device);
+	for (i = 0; i < dev_level; i++) {
+		if (device_free_len < dev_str_len)
+			return NULL;
 
-	rp = realpath(device, NULL);
-	if (!rp)
-		return NULL;
+		strncat(device, dev_str, device_free_len);
 
-	buf = get_nvme_multipath_dev_hw_path(rp);
-	if (buf) {
-		free(rp);
-		return buf;
+		/* Resolve nvme-subsystem abstraction if needed
+		 */
+		device_free_len -= dev_str_len;
+		if (i == 0) {
+			char rp[PATH_MAX];
+
+			if (!realpath(device, rp))
+				return NULL;
+			hw_path = get_nvme_multipath_dev_hw_path(rp);
+			if (hw_path) {
+				strcpy(device, hw_path);
+				device_free_len = sizeof(device) -
+						  strlen(device) - 1;
+				free(hw_path);
+			}
+		}
 	}
 
-	return rp;
+	return realpath(device, buf);
 }
 
-char *diskfd_to_devpath(int fd)
+char *diskfd_to_devpath(int fd, int dev_level, char *buf)
 {
 	/* return the device path for a disk, return NULL on error or fd
 	 * refers to a partition
@@ -745,7 +778,7 @@ char *diskfd_to_devpath(int fd)
 	if (!S_ISBLK(st.st_mode))
 		return NULL;
 
-	return devt_to_devpath(st.st_rdev);
+	return devt_to_devpath(st.st_rdev, dev_level, buf);
 }
 
 int path_attached_to_hba(const char *disk_path, const char *hba_path)
@@ -770,7 +803,7 @@ int path_attached_to_hba(const char *disk_path, const char *hba_path)
 
 int devt_attached_to_hba(dev_t dev, const char *hba_path)
 {
-	char *disk_path = devt_to_devpath(dev);
+	char *disk_path = devt_to_devpath(dev, 1, NULL);
 	int rc = path_attached_to_hba(disk_path, hba_path);
 
 	if (disk_path)
@@ -781,7 +814,7 @@ int devt_attached_to_hba(dev_t dev, const char *hba_path)
 
 int disk_attached_to_hba(int fd, const char *hba_path)
 {
-	char *disk_path = diskfd_to_devpath(fd);
+	char *disk_path = diskfd_to_devpath(fd, 1, NULL);
 	int rc = path_attached_to_hba(disk_path, hba_path);
 
 	if (disk_path)
@@ -862,15 +895,9 @@ int imsm_is_nvme_supported(int disk_fd, int verbose)
  */
 int is_multipath_nvme(int disk_fd)
 {
-	char path_buf[PATH_MAX];
 	char ns_path[PATH_MAX];
-	char *kname = fd2kname(disk_fd);
-
-	if (!kname)
-		return 0;
-	sprintf(path_buf, "/sys/block/%s", kname);
 
-	if (!realpath(path_buf, ns_path))
+	if (!diskfd_to_devpath(disk_fd, 0, ns_path))
 		return 0;
 
 	if (strncmp(ns_path, NVME_SUBSYS_PATH, strlen(NVME_SUBSYS_PATH)) == 0)
diff --git a/platform-intel.h b/platform-intel.h
index 8396a0f..f93add5 100644
--- a/platform-intel.h
+++ b/platform-intel.h
@@ -237,7 +237,7 @@ static inline char *guid_str(char *buf, struct efi_guid guid)
 }
 
 char *get_nvme_multipath_dev_hw_path(const char *dev_path);
-char *diskfd_to_devpath(int fd);
+char *diskfd_to_devpath(int fd, int dev_level, char *buf);
 __u16 devpath_to_vendor(const char *dev_path);
 struct sys_dev *find_driver_devices(const char *bus, const char *driver);
 struct sys_dev *find_intel_devices(void);
@@ -245,7 +245,7 @@ const struct imsm_orom *find_imsm_capability(struct sys_dev *hba);
 const struct imsm_orom *find_imsm_orom(void);
 int disk_attached_to_hba(int fd, const char *hba_path);
 int devt_attached_to_hba(dev_t dev, const char *hba_path);
-char *devt_to_devpath(dev_t dev);
+char *devt_to_devpath(dev_t dev, int dev_level, char *buf);
 int path_attached_to_hba(const char *disk_path, const char *hba_path);
 const char *get_sys_dev_type(enum sys_dev_type);
 const struct orom_entry *get_orom_entry_by_device_id(__u16 dev_id);
diff --git a/super-intel.c b/super-intel.c
index 5469912..cff8550 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -694,7 +694,7 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
 	if (fd < 0)
 		disk_path  = (char *) devname;
 	else
-		disk_path = diskfd_to_devpath(fd);
+		disk_path = diskfd_to_devpath(fd, 1, NULL);
 
 	if (!disk_path)
 		return 0;
@@ -2253,7 +2253,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 
 		if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
 			continue;
-		path = devt_to_devpath(makedev(major, minor));
+		path = devt_to_devpath(makedev(major, minor), 1, NULL);
 		if (!path)
 			continue;
 		if (!path_attached_to_hba(path, hba_path)) {
@@ -2407,7 +2407,7 @@ static int print_nvme_info(struct sys_dev *hba)
 				continue;
 			}
 
-			device_path = diskfd_to_devpath(fd);
+			device_path = diskfd_to_devpath(fd, 1, NULL);
 			if (!device_path) {
 				close(fd);
 				continue;
@@ -4015,28 +4015,13 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst,
 
 static void fd2devname(int fd, char *name)
 {
-	struct stat st;
-	char path[256];
-	char dname[PATH_MAX];
 	char *nm;
-	int rv;
-
-	name[0] = '\0';
-	if (fstat(fd, &st) != 0)
-		return;
-	sprintf(path, "/sys/dev/block/%d:%d",
-		major(st.st_rdev), minor(st.st_rdev));
 
-	rv = readlink(path, dname, sizeof(dname)-1);
-	if (rv <= 0)
+	nm = fd2kname(fd);
+	if (!nm)
 		return;
 
-	dname[rv] = '\0';
-	nm = strrchr(dname, '/');
-	if (nm) {
-		nm++;
-		snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
-	}
+	snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
 }
 
 static int nvme_get_serial(int fd, void *buf, size_t buf_len)
@@ -5941,29 +5926,23 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
 		free(dd);
 		abort();
 	}
+
 	if (super->hba && ((super->hba->type == SYS_DEV_NVME) ||
 	   (super->hba->type == SYS_DEV_VMD))) {
 		int i;
-		char *devpath = diskfd_to_devpath(fd);
-		char controller_path[PATH_MAX];
-		char *controller_name;
+		char cntrl_path[PATH_MAX];
+		char *cntrl_name;
+		char pci_dev_path[PATH_MAX];
 
-		if (!devpath) {
-			pr_err("failed to get devpath, aborting\n");
+		if (!diskfd_to_devpath(fd, 2, pci_dev_path) ||
+		    !diskfd_to_devpath(fd, 1, cntrl_path)) {
+			pr_err("failed to get dev_path, aborting\n");
 			if (dd->devname)
 				free(dd->devname);
 			free(dd);
 			return 1;
 		}
 
-		snprintf(controller_path, PATH_MAX-1, "%s/device", devpath);
-
-		controller_name = basename(devpath);
-		if (is_multipath_nvme(fd))
-			pr_err("%s controller supports Multi-Path I/O, Intel (R) VROC does not support multipathing\n", controller_name);
-
-		free(devpath);
-
 		if (!imsm_is_nvme_supported(dd->fd, 1)) {
 			if (dd->devname)
 				free(dd->devname);
@@ -5971,7 +5950,12 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
 			return 1;
 		}
 
-		if (devpath_to_vendor(controller_path) == 0x8086) {
+		cntrl_name = basename(cntrl_path);
+		if (is_multipath_nvme(fd))
+			pr_err("%s controller supports Multi-Path I/O, Intel (R) VROC does not support multipathing\n",
+			       cntrl_name);
+
+		if (devpath_to_vendor(pci_dev_path) == 0x8086) {
 			/*
 			 * If Intel's NVMe drive has serial ended with
 			 * "-A","-B","-1" or "-2" it means that this is "x8"
@@ -6985,7 +6969,7 @@ get_devices(const char *hba_path)
 		char *path = NULL;
 		if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
 			continue;
-		path = devt_to_devpath(makedev(major, minor));
+		path = devt_to_devpath(makedev(major, minor), 1, NULL);
 		if (!path)
 			continue;
 		if (!path_attached_to_hba(path, hba_path)) {
@@ -10648,7 +10632,7 @@ int validate_container_imsm(struct mdinfo *info)
 	struct sys_dev *hba = NULL;
 	struct sys_dev *intel_devices = find_intel_devices();
 	char *dev_path = devt_to_devpath(makedev(info->disk.major,
-									info->disk.minor));
+						 info->disk.minor), 1, NULL);
 
 	for (idev = intel_devices; idev; idev = idev->next) {
 		if (dev_path && strstr(dev_path, idev->path)) {
@@ -10669,7 +10653,8 @@ int validate_container_imsm(struct mdinfo *info)
 	struct mdinfo *dev;
 
 	for (dev = info->next; dev; dev = dev->next) {
-		dev_path = devt_to_devpath(makedev(dev->disk.major, dev->disk.minor));
+		dev_path = devt_to_devpath(makedev(dev->disk.major,
+						   dev->disk.minor), 1, NULL);
 
 		struct sys_dev *hba2 = NULL;
 		for (idev = intel_devices; idev; idev = idev->next) {
@@ -11181,7 +11166,7 @@ static const char *imsm_get_disk_controller_domain(const char *path)
 		struct sys_dev* hba;
 		char *path;
 
-		path = devt_to_devpath(st.st_rdev);
+		path = devt_to_devpath(st.st_rdev, 1, NULL);
 		if (path == NULL)
 			return "unknown";
 		hba = find_disk_attached_hba(-1, path);
-- 
2.7.5