]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
nodedev: Fix the improper logic when enumerating SRIOV VF
authorOsier Yang <jyang@redhat.com>
Mon, 25 Mar 2013 13:10:51 +0000 (21:10 +0800)
committerOsier Yang <jyang@redhat.com>
Mon, 25 Mar 2013 13:14:48 +0000 (21:14 +0800)
virPCIGetVirtualFunctions returns 0 even if there is no "virtfn"
entry under the device sysfs path.

And virPCIGetVirtualFunctions returns -1 when it fails to get
the PCI config space of one VF, however, with keeping the
the VFs already detected.

That's why udevProcessPCI and gather_pci_cap use logic like:

if (!virPCIGetVirtualFunctions(syspath,
                               &data->pci_dev.virtual_functions,
                               &data->pci_dev.num_virtual_functions) ||
    data->pci_dev.num_virtual_functions > 0)
    data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;

to tag the PCI device with "virtual_function" cap.

However, this results in a VF will aslo get "virtual_function" cap.

This patch fixes it by:
  * Ignoring the VF which has failure of getting PCI config space
    (given that the successfully detected VFs are kept , it makes
    sense to not give up on the failure of one VF too) with a warning,
    so virPCIGetVirtualFunctions will not return -1 except out of memory.

  * Free the allocated *virtual_functions when out of memory

And thus the logic can be changed to:

    /* Out of memory */
    int ret = virPCIGetVirtualFunctions(syspath,
                                        &data->pci_dev.virtual_functions,
                                        &data->pci_dev.num_virtual_functions);

    if (ret < 0 )
        goto out;
    if (data->pci_dev.num_virtual_functions > 0)
        data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;

src/node_device/node_device_hal.c
src/node_device/node_device_udev.c
src/util/virpci.c

index 12835105055daede350f708d1a882ccf96f4293d..4955c436bc458dfc8b26a2764dfd3ab1de8ee805 100644 (file)
@@ -152,12 +152,16 @@ static int gather_pci_cap(LibHalContext *ctx, const char *udi,
                                        &d->pci_dev.physical_function))
             d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
 
-        if (!virPCIGetVirtualFunctions(sysfs_path,
-                                       &d->pci_dev.virtual_functions,
-            &d->pci_dev.num_virtual_functions) ||
-            d->pci_dev.num_virtual_functions > 0)
-            d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
+        int ret = virPCIGetVirtualFunctions(sysfs_path,
+                                            &d->pci_dev.virtual_functions,
+                                            &d->pci_dev.num_virtual_functions);
+        if (ret < 0) {
+            VIR_FREE(sysfs_path);
+            return -1;
+        }
 
+        if (d->pci_dev.num_virtual_functions > 0)
+            d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
         VIR_FREE(sysfs_path);
     }
 
index 0d8b984b84a0a85c76d752a34bb67e039eeed098..cb11e5fe0bfe62e8a1bf35c3adaededc93f127ec 100644 (file)
@@ -416,6 +416,7 @@ static int udevProcessPCI(struct udev_device *device,
     union _virNodeDevCapData *data = &def->caps->data;
     int ret = -1;
     char *p;
+    int rc;
 
     syspath = udev_device_get_syspath(device);
 
@@ -484,9 +485,13 @@ static int udevProcessPCI(struct udev_device *device,
     if (!virPCIGetPhysicalFunction(syspath, &data->pci_dev.physical_function))
         data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
 
-    if (!virPCIGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions,
-        &data->pci_dev.num_virtual_functions) ||
-        data->pci_dev.num_virtual_functions > 0)
+    rc = virPCIGetVirtualFunctions(syspath,
+                                   &data->pci_dev.virtual_functions,
+                                   &data->pci_dev.num_virtual_functions);
+    /* Out of memory */
+    if (rc < 0)
+        goto out;
+    else if (!rc && (data->pci_dev.num_virtual_functions > 0))
         data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
 
     ret = 0;
index 4bb82aae59750fcccba7e310a279b06d2438d39f..a0da1cd005e80d8f2fa3ee0b74e24df0bf943da2 100644 (file)
@@ -1985,6 +1985,7 @@ virPCIGetVirtualFunctions(const char *sysfs_path,
                           unsigned int *num_virtual_functions)
 {
     int ret = -1;
+    int i;
     DIR *dir = NULL;
     struct dirent *entry = NULL;
     char *device_link = NULL;
@@ -2006,45 +2007,53 @@ virPCIGetVirtualFunctions(const char *sysfs_path,
     *num_virtual_functions = 0;
     while ((entry = readdir(dir))) {
         if (STRPREFIX(entry->d_name, "virtfn")) {
+            virPCIDeviceAddress *config_addr = NULL;
 
             if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) {
                 virReportOOMError();
-                goto out;
+                goto error;
             }
 
             VIR_DEBUG("Number of virtual functions: %d",
                       *num_virtual_functions);
-            if (VIR_REALLOC_N(*virtual_functions,
-                              (*num_virtual_functions) + 1) != 0) {
-                virReportOOMError();
-                VIR_FREE(device_link);
-                goto out;
-            }
 
             if (virPCIGetDeviceAddressFromSysfsLink(device_link,
-                                                    &((*virtual_functions)[*num_virtual_functions])) !=
+                                                    &config_addr) !=
                 SRIOV_FOUND) {
-                /* We should not get back SRIOV_NOT_FOUND in this
-                 * case, so if we do, it's an error. */
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Failed to get SR IOV function from device "
-                                 "link '%s'"), device_link);
+                VIR_WARN("Failed to get SRIOV function from device "
+                         "link '%s'", device_link);
                 VIR_FREE(device_link);
-                goto out;
-            } else {
-                (*num_virtual_functions)++;
+                continue;
             }
+
+            if (VIR_ALLOC_N(*virtual_functions,
+                            *num_virtual_functions + 1) < 0) {
+                virReportOOMError();
+                VIR_FREE(config_addr);
+                goto error;
+            }
+
+            (*virtual_functions)[*num_virtual_functions] = config_addr;
+            (*num_virtual_functions)++;
             VIR_FREE(device_link);
         }
     }
 
     ret = 0;
 
-out:
+cleanup:
+    VIR_FREE(device_link);
     if (dir)
         closedir(dir);
-
     return ret;
+
+error:
+    if (*virtual_functions) {
+        for (i = 0; i < *num_virtual_functions; i++)
+            VIR_FREE((*virtual_functions)[i]);
+        VIR_FREE(*virtual_functions);
+    }
+    goto cleanup;
 }
 
 /*