Patchwork [Open-FCoE,libhbalinux,6/6] use libudev for finding parents

login
register
mail settings
Submitter Chris Leech
Date Oct. 13, 2014, 11:13 p.m.
Message ID <1413242005-17786-7-git-send-email-cleech@redhat.com>
Download mbox | patch
Permalink /patch/169/
State RFC
Headers show

Comments

Chris Leech - Oct. 13, 2014, 11:13 p.m.
don't fail without PCI

Signed-off-by: Chris Leech <cleech@redhat.com>
---
 lport.c | 166 +++++++++++++++++++++-------------------------------------------
 1 file changed, 53 insertions(+), 113 deletions(-)

Patch

diff --git a/lport.c b/lport.c
index acd1737..e4a2c9c 100644
--- a/lport.c
+++ b/lport.c
@@ -140,51 +140,6 @@  counting_rports(struct dirent *dp, void *arg)
 	return HBA_STATUS_OK;
 }
 
-static int
-check_ifindex(struct dirent *dp, void *arg)
-{
-	char *ifindex = (char *)arg;
-	char hba_dir[256];
-	char buf[256];
-	int rc;
-
-	snprintf(hba_dir, sizeof(hba_dir),
-		 SYSFS_HBA_DIR "/%s", dp->d_name);
-	memset(buf, 0, sizeof(buf));
-	rc = sa_sys_read_line(hba_dir, "ifindex", buf, sizeof(buf) - 1);
-	if (rc)
-		return 0;
-	if (!strncmp(ifindex, buf, sizeof(buf))) {
-		strcpy(arg, dp->d_name);
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * find_phys_if - find the regular network interface name that
- *                has the ifindex that matches the specified iflink.
- *                This ifname will be used to find the PCI info
- *                of a VLAN interface.
- * hba_dir: hba_dir of VLAN interface.
- * buf: returns ifname of regular network interface.
- */
-static int
-find_phys_if(char *hba_dir, char *buf, size_t len)
-{
-	int rc;
-
-	rc = sa_sys_read_line(hba_dir, "iflink", buf, len);
-	if (rc)
-		return 1;
-	/*
-	 * Search for the regular network interface and
-	 * return the interface name in the buf.
-	 */
-	sa_dir_read(SYSFS_HBA_DIR, check_ifindex, buf);
-	return 0;
-}
-
 static void 
 sysfs_scan_pci(struct udev_device *pci,
 	struct hba_info *hba_info,
@@ -220,6 +175,10 @@  sysfs_scan_pci(struct udev_device *pci,
 	/*
 	 * Get Hardware Information via PCI Library
 	 */
+
+	sscanf(udev_device_get_sysname(pci), "%x:%x:%x:%x",
+			&hba_info->domain, &hba_info->bus,
+			&hba_info->dev, &hba_info->func);
 	(void) find_pci_device(hba_info);
 
 	/* Get Number of Ports */
@@ -300,6 +259,48 @@  sysfs_scan_pci(struct udev_device *pci,
 			atp->DriverVersion, sizeof(atp->DriverVersion));
 }
 
+struct udev_device *
+find_netdev_by_ifindex(struct udev *udev, const char *ifindex)
+{
+	struct udev_enumerate *ue;
+	struct udev_list_entry *head;
+	struct udev_device *newnet = NULL;
+
+	ue = udev_enumerate_new(udev);
+	udev_enumerate_add_match_subsystem(ue, "net");
+	udev_enumerate_add_match_sysattr(ue, "ifindex", ifindex); 
+	udev_enumerate_scan_devices(ue);
+	/* enumerate returns a list, but there should only ever be one device
+	 * with a given ifindex */
+	head = udev_enumerate_get_list_entry(ue);
+	if (head)
+		newnet = udev_device_new_from_syspath(udev, udev_list_entry_get_name(head));
+	udev_enumerate_unref(ue);
+	return newnet;
+}
+
+struct udev_device *
+find_phys_if(struct udev_device *net)
+{
+	const char *ifindex;
+	const char *iflink;
+	struct udev *udev;
+	struct udev_device *lower = NULL;
+
+	ifindex = udev_device_get_sysattr_value(net, "ifindex");
+	iflink = udev_device_get_sysattr_value(net, "iflink");
+	if (strcmp(ifindex, iflink)) {
+		udev = udev_device_get_udev(net);
+		lower = find_netdev_by_ifindex(udev, iflink);
+	}
+	if (lower) {
+		return lower;
+	} else {
+		udev_device_ref(net);
+		return net;
+	}
+}
+
 static int
 sysfs_scan(struct udev_device *fc_host)
 {
@@ -311,17 +312,15 @@  sysfs_scan(struct udev_device *fc_host)
 	struct port_info *pp;
 	char hba_dir[80];
 	char drv_dir[80];
-	const char *dev_dir;
 	char ifname[20], buf[256];
 	char *driverName;
 	int data[32], rc, i;
 	char *cp;
-	unsigned int ifindex;
-	unsigned int iflink;
 
 	const char *sysname = udev_device_get_sysname(fc_host);
 	const char *syspath = udev_device_get_syspath(fc_host);
 	struct udev_device *pci;
+	struct udev_device *net;
 	const char *ptr = NULL;
 	const char *attr;
 
@@ -375,73 +374,15 @@  sysfs_scan(struct udev_device *fc_host)
 	if (!cp)
 		goto skip;
 
-	/*
-	 * See if <host_dir>/device is a PCI symlink.
-	 * If not, try it as a net device.
-	 */
-	dev_dir = udev_device_get_sysattr_value(fc_host, "device");
-	i = readlink(dev_dir, buf, sizeof(buf) - 1);
-	if (i < 0)
-		i = 0;
-	buf[i] = '\0';
-
-	if (strstr(buf, "devices/pci") && !strstr(buf, "/net/")) {
-		snprintf(hba_dir, sizeof(hba_dir), "%s/device/..", syspath);
-	} else {
-		/* assume a net device */
-		cp += 6;
-		sa_strncpy_safe(ifname, sizeof(ifname), cp, strlen(cp));
-		snprintf(hba_dir, sizeof(hba_dir),
-			 SYSFS_HBA_DIR "/%s", ifname);
-		/*
-		 * Try as VLAN device or other virtual net device.
-		 * If this is the case, ifindex and iflink will be different.
-		 * iflink is the ifindex of the physical device.
-		 */
-		rc = sa_sys_read_u32(hba_dir, "ifindex", &ifindex);
-		if (rc < 0)
-			goto skip;
-		rc = sa_sys_read_u32(hba_dir, "iflink", &iflink);
-		if (rc < 0)
-			goto skip;
-		if (ifindex != iflink) {
-			rc = find_phys_if(hba_dir, buf, sizeof(buf));
-			if (rc)
-				goto skip;
-			strncpy(ifname, buf, sizeof(ifname));
-		}
-
-		snprintf(hba_dir, sizeof(hba_dir),
-			 SYSFS_HBA_DIR "/%s/device", ifname);
-		i = readlink(hba_dir, buf, sizeof(buf) - 1);
-		if (i < 0)
-			goto skip;
-		buf[i] = '\0';
+	pci = udev_device_get_parent_with_subsystem_devtype(fc_host, "pci", NULL);
+	net = udev_device_get_parent_with_subsystem_devtype(fc_host, "net", NULL);
+	if (!pci && net) {
+		/* check for a vlan device, stacked on a real PCI network device */
+		net = find_phys_if(net);
+		pci = udev_device_get_parent_with_subsystem_devtype(net, "pci", NULL);
 	}
 
 	/*
-	 * Assume a PCI symlink value is in buf.
-	 * Back up to the last path component that looks like a PCI element.
-	 * A sample link value is like:
-	 *	../../devices/pci*.../0000:03:00.0
-	 */
-	rc = 0;
-	do {
-		cp = strrchr(buf, '/');
-		if (!cp)
-			break;
-		rc = sscanf(cp + 1, "%x:%x:%x.%x",
-			    &hba_info.domain, &hba_info.bus,
-			    &hba_info.dev, &hba_info.func);
-		if (rc == 4)
-			break;
-		*cp = '\0';
-	} while (cp && cp > buf);
-
-	if (rc != 4)
-		goto skip;
-
-	/*
 	 * Save the host directory and the hba directory
 	 * in local port structure
 	 */
@@ -546,7 +487,6 @@  sysfs_scan(struct udev_device *fc_host)
 	snprintf(buf, sizeof(buf), "fcoe:%s", ifname);
 	ap->ad_name = strdup(buf);
 
-	pci = udev_device_get_parent_with_subsystem_devtype(fc_host, "pci", NULL);
 	if (pci)
 		sysfs_scan_pci(pci, &hba_info, atp);