From f6c721b4da5a92242a6acecba2bd89db9e6616ef Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 1 Aug 2023 03:27:33 +0900
Subject: [PATCH 7013/7019] udev-builtin-net_id: split-out
 pci_get_hotplug_slot() and pci_get_hotplug_slot_from_address()

No functional changes, just refactoring.

(cherry picked from commit f1e3eaa730190a60fdb780be26ee331b8c811e34)
---
 src/udev/udev-builtin-net_id.c | 199 +++++++++++++++++++--------------
 1 file changed, 117 insertions(+), 82 deletions(-)

diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index ab6c8be995..ccc131f3ba 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -316,14 +316,121 @@ static int parse_hotplug_slot_from_function_id(sd_device *dev, int slots_dirfd,
         return 1;
 }
 
-static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
-        const char *sysname, *attr;
+static int pci_get_hotplug_slot_from_address(
+                sd_device *dev,
+                sd_device *pci,
+                DIR *dir,
+                uint32_t *ret) {
+
+        const char *sysname;
+        int r;
+
+        assert(dev);
+        assert(pci);
+        assert(dir);
+        assert(ret);
+
+        r = sd_device_get_sysname(dev, &sysname);
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
+
+        rewinddir(dir);
+        FOREACH_DIRENT_ALL(de, dir, break) {
+                _cleanup_free_ char *path = NULL;
+                const char *address;
+                uint32_t slot;
+
+                if (dot_or_dot_dot(de->d_name))
+                        continue;
+
+                if (de->d_type != DT_DIR)
+                        continue;
+
+                r = safe_atou32(de->d_name, &slot);
+                if (r < 0 || slot <= 0)
+                        continue;
+
+                path = path_join("slots", de->d_name, "address");
+                if (!path)
+                        return -ENOMEM;
+
+                if (sd_device_get_sysattr_value(pci, path, &address) < 0)
+                        continue;
+
+                /* match slot address with device by stripping the function */
+                if (!startswith(sysname, address))
+                        continue;
+
+                *ret = slot;
+                return 1; /* found */
+        }
+
+        *ret = 0;
+        return 0; /* not found */
+}
+
+static int pci_get_hotplug_slot(sd_device *dev, uint32_t *ret) {
         _cleanup_(sd_device_unrefp) sd_device *pci = NULL;
         _cleanup_closedir_ DIR *dir = NULL;
+        int r;
+
+        assert(dev);
+        assert(ret);
+
+        /* ACPI _SUN — slot user number */
+        r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci");
+        if (r < 0)
+                return log_debug_errno(r, "Failed to create sd_device object for pci subsystem: %m");
+
+        r = device_opendir(pci, "slots", &dir);
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Cannot open 'slots' subdirectory: %m");
+
+        for (sd_device *slot_dev = dev; slot_dev; ) {
+                uint32_t slot = 0;  /* avoid false maybe-uninitialized warning */
+
+                r = parse_hotplug_slot_from_function_id(slot_dev, dirfd(dir), &slot);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        *ret = slot;
+                        return 1; /* domain should be ignored. */
+                }
+
+                r = pci_get_hotplug_slot_from_address(slot_dev, pci, dir, &slot);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        /* We found the match between PCI device and slot. However, we won't use the slot
+                         * index if the device is a PCI bridge, because it can have other child devices that
+                         * will try to claim the same index and that would create name collision. */
+                        if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(slot_dev)) {
+                                if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && is_pci_multifunction(dev) <= 0)
+                                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE),
+                                                                      "Not using slot information because the PCI device associated with "
+                                                                      "the hotplug slot is a bridge and the PCI device has a single function.");
+
+                                if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT))
+                                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE),
+                                                                      "Not using slot information because the PCI device is a bridge.");
+                        }
+
+                        *ret = slot;
+                        return 0; /* domain can be still used. */
+                }
+
+                if (sd_device_get_parent_with_subsystem_devtype(slot_dev, "pci", NULL, &slot_dev) < 0)
+                        break;
+        }
+
+        return -ENOENT;
+}
+
+static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
+        const char *sysname, *attr;
         unsigned domain, bus, slot, func;
-        sd_device *hotplug_slot_dev;
         unsigned long dev_port = 0;
-        uint32_t hotplug_slot = 0;
+        uint32_t hotplug_slot = 0;  /* avoid false maybe-uninitialized warning */
         size_t l;
         char *s;
         int r;
@@ -394,85 +501,13 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
                          domain, bus, slot, func, strempty(info->phys_port_name), dev_port,
                          special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_path));
 
-        /* ACPI _SUN — slot user number */
-        r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci");
-        if (r < 0)
-                return log_debug_errno(r, "sd_device_new_from_subsystem_sysname() failed: %m");
-
-        r = device_opendir(pci, "slots", &dir);
+        r = pci_get_hotplug_slot(names->pcidev, &hotplug_slot);
         if (r < 0)
-                return log_device_debug_errno(dev, r, "Cannot access 'slots' subdirectory: %m");
-
-        hotplug_slot_dev = names->pcidev;
-        while (hotplug_slot_dev) {
-                r = parse_hotplug_slot_from_function_id(hotplug_slot_dev, dirfd(dir), &hotplug_slot);
-                if (r < 0)
-                        return 0;
-                if (r > 0) {
-                        domain = 0; /* See comments in parse_hotplug_slot_from_function_id(). */
-                        break;
-                }
-
-                r = sd_device_get_sysname(hotplug_slot_dev, &sysname);
-                if (r < 0)
-                        return log_device_debug_errno(hotplug_slot_dev, r, "Failed to get sysname: %m");
-
-                FOREACH_DIRENT_ALL(de, dir, break) {
-                        _cleanup_free_ char *path = NULL;
-                        const char *address;
-                        uint32_t i;
-
-                        if (dot_or_dot_dot(de->d_name))
-                                continue;
-
-                        if (de->d_type != DT_DIR)
-                                continue;
-
-                        r = safe_atou32(de->d_name, &i);
-                        if (r < 0 || i <= 0)
-                                continue;
-
-                        path = path_join("slots", de->d_name, "address");
-                        if (!path)
-                                return -ENOMEM;
-
-                        if (sd_device_get_sysattr_value(pci, path, &address) < 0)
-                                continue;
-
-                        /* match slot address with device by stripping the function */
-                        if (!startswith(sysname, address))
-                                continue;
-
-                        hotplug_slot = i;
-
-                        /* We found the match between PCI device and slot. However, we won't use the slot
-                         * index if the device is a PCI bridge, because it can have other child devices that
-                         * will try to claim the same index and that would create name collision. */
-                        if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) {
-                                if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && is_pci_multifunction(names->pcidev) <= 0) {
-                                        log_device_debug(dev,
-                                                         "Not using slot information because the PCI device associated with "
-                                                         "the hotplug slot is a bridge and the PCI device has a single function.");
-                                        return 0;
-                                }
-
-                                if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) {
-                                        log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
-                                        return 0;
-                                }
-                        }
-
-                        break;
-                }
-                if (hotplug_slot > 0)
-                        break;
-                if (sd_device_get_parent_with_subsystem_devtype(hotplug_slot_dev, "pci", NULL, &hotplug_slot_dev) < 0)
-                        break;
-                rewinddir(dir);
-        }
-
-        if (hotplug_slot == 0)
-                return 0;
+                return r;
+        if (r > 0)
+                /* If the hotplug slot is found through the function ID, then drop the domain from the name.
+                 * See comments in parse_hotplug_slot_from_function_id(). */
+                domain = 0;
 
         s = names->pci_slot;
         l = sizeof(names->pci_slot);
-- 
2.43.0

