|
|
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 |
|