pciGetVirtualFunctions returns 0 even if there is no "virtfn" entry under the device sysfs path. And pciGetVirtualFunctions returns -1 when it tries to get the PCI config space of the VF, however, with keeping the the VFs already detected. That's why udevProcessPCI and gather_pci_cap use logic like: if (!pciGetVirtualFunctions(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. 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 of the device (given that the succesfully detected VFs are kept , it makes sense to not give up on the failure of one VF too) with a warning, so pciGetVirtualFunctions will always return 0 except out of memory. * Free the allocated *virtual_functions when out of memory And thus the logic can be changed to: /* Out of memory */ if (pciGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions, &data->pci_dev.num_virtual_functions) < 0) goto out; else if (!pciGetVirtualFunctions(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; This also fixes a memory leak in the old codes (it realloc the *virtual_functions first, and doesn't shrink it when it fails on getting the PCI config space). --- src/node_device/node_device_hal.c | 13 +++++++++-- src/node_device/node_device_udev.c | 11 +++++++-- src/util/pci.c | 37 +++++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index ff73db0..69e6ebf 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -151,10 +151,17 @@ static int gather_pci_cap(LibHalContext *ctx, const char *udi, if (!pciGetPhysicalFunction(sysfs_path, &d->pci_dev.physical_function)) d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; - if (!pciGetVirtualFunctions(sysfs_path, &d->pci_dev.virtual_functions, - &d->pci_dev.num_virtual_functions) || - d->pci_dev.num_virtual_functions > 0) + if (!pciGetVirtualFunctions(sysfs_path, + &d->pci_dev.virtual_functions, + &d->pci_dev.num_virtual_functions) < 0) { + VIR_FREE(sysfs_path); + return -1; + } else if (!pciGetVirtualFunctions(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; + } VIR_FREE(sysfs_path); } diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index acd78f2..72b8850 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -484,9 +484,14 @@ static int udevProcessPCI(struct udev_device *device, if (!pciGetPhysicalFunction(syspath, &data->pci_dev.physical_function)) data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; - if (!pciGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions, - &data->pci_dev.num_virtual_functions) || - data->pci_dev.num_virtual_functions > 0) + /* Out of memory */ + if (pciGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions, + &data->pci_dev.num_virtual_functions) < 0) + goto out; + else if (!pciGetVirtualFunctions(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; ret = 0; diff --git a/src/util/pci.c b/src/util/pci.c index d1ad121..3b4d96a 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -1930,6 +1930,7 @@ pciGetVirtualFunctions(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; @@ -1952,6 +1953,7 @@ pciGetVirtualFunctions(const char *sysfs_path, *num_virtual_functions = 0; while ((entry = readdir(dir))) { if (STRPREFIX(entry->d_name, "virtfn")) { + struct pci_config_address *config_addr = NULL; if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) { virReportOOMError(); @@ -1960,24 +1962,23 @@ pciGetVirtualFunctions(const char *sysfs_path, 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 (pciGetPciConfigAddressFromSysfsDeviceLink(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; + continue; } else { + if (VIR_ALLOC_N(*virtual_functions, + *num_virtual_functions + 1) < 0) { + virReportOOMError(); + VIR_FREE(config_addr); + goto out; + } + + (*virtual_functions)[*num_virtual_functions] = config_addr; (*num_virtual_functions)++; } VIR_FREE(device_link); @@ -1985,8 +1986,18 @@ pciGetVirtualFunctions(const char *sysfs_path, } ret = 0; + goto cleanup; out: + if (*virtual_functions) { + for (i = 0; i < *num_virtual_functions; i++) + VIR_FREE((*virtual_functions)[i]); + VIR_FREE(*virtual_functions); + } + +cleanup: + if (device_link) + VIR_FREE(device_link); if (dir) closedir(dir); -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list