43fe83
From 025c32f0b7f6f968e1b33442b68c2e65e11bc43f Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <025c32f0b7f6f968e1b33442b68c2e65e11bc43f.1383922565.git.jdenemar@redhat.com>
43fe83
From: Laine Stump <laine@laine.org>
43fe83
Date: Fri, 8 Nov 2013 05:42:33 -0700
43fe83
Subject: [PATCH] pci: properly handle out-of-order SRIOV virtual functions
43fe83
43fe83
This resolves:
43fe83
43fe83
  https://bugzilla.redhat.com/show_bug.cgi?id=1025397
43fe83
43fe83
When virPCIGetVirtualFunctions created the list of an SRIOV Physical
43fe83
Function's (PF) Virtual Functions (VF), it had assumed that the order
43fe83
of "virtfn*" links returned by readdir() from the PF's sysfs directory
43fe83
was already in the correct order. Experience has shown that this is
43fe83
not always the case - it can be in alphabetical order (which would
43fe83
e.g. place virtfn11 before virtfn2) or even some seemingly random
43fe83
order (see the example in the bugzilla report)
43fe83
43fe83
This results in 1) incorrect assumptions made by consumers of the
43fe83
output of the virt_functions list of virsh nodedev-dumpxml, and 2)
43fe83
setting MAC address and vlan tag on the wrong VF (since libvirt uses
43fe83
netlink to set mac address and vlan tag, netlink requires the VF#, and
43fe83
the function virPCIGetVirtualFunctionIndex() returns the wrong index
43fe83
due to the improperly ordered VF list).
43fe83
43fe83
The solution provided by this patch is for virPCIGetVirtualFunctions
43fe83
to no longer scan the entire device directory in its natural order,
43fe83
but instead to check for links individually by name "virtfn%d" where
43fe83
%d starts at 0 and increases with each success. Since VFs are created
43fe83
contiguously by the kernel, this will guarantee that all VFs are
43fe83
found, and placed in the arry in the correct order.
43fe83
43fe83
One note of use to the uninitiated is that VIR_APPEND_ELEMENT always
43fe83
either increments *num_virtual_functions or fails, so no this isn't an
43fe83
endless loop.
43fe83
43fe83
(NB: the SRIOV_* defines at the top of virpci.c were removed
43fe83
because they are unnecessary and/or not used.)
43fe83
43fe83
(cherry picked from commit 88c1fcd5e7b6568fdb1a06e0d9001c37d5e1cb78)
43fe83
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 src/util/virpci.c | 76 ++++++++++++++++++-------------------------------------
43fe83
 1 file changed, 24 insertions(+), 52 deletions(-)
43fe83
43fe83
diff --git a/src/util/virpci.c b/src/util/virpci.c
43fe83
index 87ea81b..39bbac8 100644
43fe83
--- a/src/util/virpci.c
43fe83
+++ b/src/util/virpci.c
43fe83
@@ -49,10 +49,6 @@
43fe83
 #define PCI_ID_LEN 10   /* "XXXX XXXX" */
43fe83
 #define PCI_ADDR_LEN 13 /* "XXXX:XX:XX.X" */
43fe83
 
43fe83
-#define SRIOV_FOUND 0
43fe83
-#define SRIOV_NOT_FOUND 1
43fe83
-#define SRIOV_ERROR -1
43fe83
-
43fe83
 struct _virPCIDevice {
43fe83
     unsigned int  domain;
43fe83
     unsigned int  bus;
43fe83
@@ -2379,6 +2375,7 @@ virPCIGetPhysicalFunction(const char *vf_sysfs_path,
43fe83
     return ret;
43fe83
 }
43fe83
 
43fe83
+
43fe83
 /*
43fe83
  * Returns virtual functions of a physical function
43fe83
  */
43fe83
@@ -2389,10 +2386,8 @@ virPCIGetVirtualFunctions(const char *sysfs_path,
43fe83
 {
43fe83
     int ret = -1;
43fe83
     size_t i;
43fe83
-    DIR *dir = NULL;
43fe83
-    struct dirent *entry = NULL;
43fe83
     char *device_link = NULL;
43fe83
-    char errbuf[64];
43fe83
+    virPCIDeviceAddress *config_addr = NULL;
43fe83
 
43fe83
     VIR_DEBUG("Attempting to get SR IOV virtual functions for device"
43fe83
               "with sysfs path '%s'", sysfs_path);
43fe83
@@ -2400,65 +2395,42 @@ virPCIGetVirtualFunctions(const char *sysfs_path,
43fe83
     *virtual_functions = NULL;
43fe83
     *num_virtual_functions = 0;
43fe83
 
43fe83
-    dir = opendir(sysfs_path);
43fe83
-    if (dir == NULL) {
43fe83
-        memset(errbuf, '\0', sizeof(errbuf));
43fe83
-        virReportSystemError(errno,
43fe83
-                             _("Failed to open dir '%s'"),
43fe83
-                             sysfs_path);
43fe83
-        return ret;
43fe83
-    }
43fe83
-
43fe83
-    while ((entry = readdir(dir))) {
43fe83
-        if (STRPREFIX(entry->d_name, "virtfn")) {
43fe83
-            virPCIDeviceAddress *config_addr = NULL;
43fe83
-
43fe83
-            if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) {
43fe83
-                virReportOOMError();
43fe83
-                goto error;
43fe83
-            }
43fe83
+    do {
43fe83
+        /* look for virtfn%d links until one isn't found */
43fe83
+        if (virAsprintf(&device_link, "%s/virtfn%zu", sysfs_path, *num_virtual_functions) < 0)
43fe83
+            goto error;
43fe83
 
43fe83
-            VIR_DEBUG("Number of virtual functions: %zu",
43fe83
-                      *num_virtual_functions);
43fe83
+        if (!virFileExists(device_link))
43fe83
+            break;
43fe83
 
43fe83
-            if (virPCIGetDeviceAddressFromSysfsLink(device_link,
43fe83
-                                                    &config_addr) !=
43fe83
-                SRIOV_FOUND) {
43fe83
-                VIR_WARN("Failed to get SRIOV function from device "
43fe83
-                         "link '%s'", device_link);
43fe83
-                VIR_FREE(device_link);
43fe83
-                continue;
43fe83
-            }
43fe83
+        if (virPCIGetDeviceAddressFromSysfsLink(device_link, &config_addr) < 0) {
43fe83
+            virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
+                           _("Failed to get SRIOV function from device link '%s'"),
43fe83
+                           device_link);
43fe83
+            goto error;
43fe83
+        }
43fe83
 
43fe83
-            if (VIR_REALLOC_N(*virtual_functions,
43fe83
-                              *num_virtual_functions + 1) < 0) {
43fe83
-                VIR_FREE(config_addr);
43fe83
-                goto error;
43fe83
-            }
43fe83
+        VIR_DEBUG("Found virtual function %zu", *num_virtual_functions);
43fe83
+        if (VIR_APPEND_ELEMENT(*virtual_functions, *num_virtual_functions, config_addr) < 0)
43fe83
+            goto error;
43fe83
+        VIR_FREE(device_link);
43fe83
 
43fe83
-            (*virtual_functions)[*num_virtual_functions] = config_addr;
43fe83
-            (*num_virtual_functions)++;
43fe83
-            VIR_FREE(device_link);
43fe83
-        }
43fe83
-    }
43fe83
+    } while (1);
43fe83
 
43fe83
     ret = 0;
43fe83
-
43fe83
 cleanup:
43fe83
     VIR_FREE(device_link);
43fe83
-    if (dir)
43fe83
-        closedir(dir);
43fe83
+    VIR_FREE(config_addr);
43fe83
     return ret;
43fe83
 
43fe83
 error:
43fe83
-    if (*virtual_functions) {
43fe83
-        for (i = 0; i < *num_virtual_functions; i++)
43fe83
-            VIR_FREE((*virtual_functions)[i]);
43fe83
-        VIR_FREE(*virtual_functions);
43fe83
-    }
43fe83
+    for (i = 0; i < *num_virtual_functions; i++)
43fe83
+        VIR_FREE((*virtual_functions)[i]);
43fe83
+    VIR_FREE(*virtual_functions);
43fe83
     goto cleanup;
43fe83
 }
43fe83
 
43fe83
+
43fe83
 /*
43fe83
  * Returns 1 if vf device is a virtual function, 0 if not, -1 on error
43fe83
  */
43fe83
-- 
43fe83
1.8.4.2
43fe83