virPCIGetVirtualFunctions: Simplify cleanup of returned data

Introduce a struct for holding the list of VFs returned by
virPCIGetVirtualFunctions so that we can employ automatic memory
clearing and also allow querying more information at once.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Peter Krempa 2021-08-03 16:45:36 +02:00
parent 00f804c1cf
commit c97518d9b8
5 changed files with 72 additions and 52 deletions

View File

@ -2647,6 +2647,7 @@ static int
virNodeDeviceGetPCISRIOVCaps(const char *sysfsPath, virNodeDeviceGetPCISRIOVCaps(const char *sysfsPath,
virNodeDevCapPCIDev *pci_dev) virNodeDevCapPCIDev *pci_dev)
{ {
g_autoptr(virPCIVirtualFunctionList) vfs = g_new0(virPCIVirtualFunctionList, 1);
size_t i; size_t i;
int ret; int ret;
@ -2668,11 +2669,16 @@ virNodeDeviceGetPCISRIOVCaps(const char *sysfsPath,
if (pci_dev->physical_function) if (pci_dev->physical_function)
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
ret = virPCIGetVirtualFunctions(sysfsPath, &pci_dev->virtual_functions, if (virPCIGetVirtualFunctions(sysfsPath, &vfs) < 0)
&pci_dev->num_virtual_functions, return -1;
&pci_dev->max_virtual_functions);
if (ret < 0) pci_dev->virtual_functions = g_new0(virPCIDeviceAddress *, vfs->nfunctions);
return ret;
for (i = 0; i < vfs->nfunctions; i++)
pci_dev->virtual_functions[i] = g_steal_pointer(&vfs->functions[i].addr);
pci_dev->num_virtual_functions = vfs->nfunctions;
pci_dev->max_virtual_functions = vfs->maxfunctions;
if (pci_dev->num_virtual_functions > 0 || if (pci_dev->num_virtual_functions > 0 ||
pci_dev->max_virtual_functions > 0) pci_dev->max_virtual_functions > 0)

View File

@ -3017,6 +3017,7 @@ virPCIHeaderTypeToString;
virPCIIsVirtualFunction; virPCIIsVirtualFunction;
virPCIStubDriverTypeFromString; virPCIStubDriverTypeFromString;
virPCIStubDriverTypeToString; virPCIStubDriverTypeToString;
virPCIVirtualFunctionListFree;
virZPCIDeviceAddressIsIncomplete; virZPCIDeviceAddressIsIncomplete;
virZPCIDeviceAddressIsPresent; virZPCIDeviceAddressIsPresent;

View File

@ -1231,7 +1231,7 @@ virNetDevGetVirtualFunctions(const char *pfname,
size_t i; size_t i;
g_autofree char *pf_sysfs_device_link = NULL; g_autofree char *pf_sysfs_device_link = NULL;
g_autofree char *pfPhysPortID = NULL; g_autofree char *pfPhysPortID = NULL;
unsigned int max_vfs; g_autoptr(virPCIVirtualFunctionList) vfs = NULL;
*virt_fns = NULL; *virt_fns = NULL;
*n_vfname = 0; *n_vfname = 0;
@ -1242,14 +1242,18 @@ virNetDevGetVirtualFunctions(const char *pfname,
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0) if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0)
goto cleanup; goto cleanup;
if (virPCIGetVirtualFunctions(pf_sysfs_device_link, virt_fns, n_vfname, &max_vfs) < 0) if (virPCIGetVirtualFunctions(pf_sysfs_device_link, &vfs) < 0)
goto cleanup; goto cleanup;
*vfname = g_new0(char *, *n_vfname); *vfname = g_new0(char *, vfs->nfunctions);
*virt_fns = g_new0(virPCIDeviceAddress *, vfs->nfunctions);
*n_vfname = vfs->nfunctions;
for (i = 0; i < *n_vfname; i++) { for (i = 0; i < *n_vfname; i++) {
g_autofree char *pci_sysfs_device_link = NULL; g_autofree char *pci_sysfs_device_link = NULL;
virt_fns[i] = g_steal_pointer(&vfs->functions[i].addr);
if (virPCIDeviceAddressGetSysfsFile((*virt_fns)[i], if (virPCIDeviceAddressGetSysfsFile((*virt_fns)[i],
&pci_sysfs_device_link) < 0) { &pci_sysfs_device_link) < 0) {
virReportSystemError(ENOSYS, "%s", virReportSystemError(ENOSYS, "%s",

View File

@ -2247,6 +2247,22 @@ virZPCIDeviceAddressIsPresent(const virZPCIDeviceAddress *addr)
} }
void
virPCIVirtualFunctionListFree(virPCIVirtualFunctionList *list)
{
size_t i;
if (!list)
return;
for (i = 0; i < list->nfunctions; i++) {
g_free(list->functions[i].addr);
}
g_free(list);
}
#ifdef __linux__ #ifdef __linux__
virPCIDeviceAddress * virPCIDeviceAddress *
@ -2321,62 +2337,54 @@ virPCIGetPhysicalFunction(const char *vf_sysfs_path,
*/ */
int int
virPCIGetVirtualFunctions(const char *sysfs_path, virPCIGetVirtualFunctions(const char *sysfs_path,
virPCIDeviceAddress ***virtual_functions, virPCIVirtualFunctionList **vfs)
size_t *num_virtual_functions,
unsigned int *max_virtual_functions)
{ {
size_t i;
g_autofree char *totalvfs_file = NULL; g_autofree char *totalvfs_file = NULL;
g_autofree char *totalvfs_str = NULL; g_autofree char *totalvfs_str = NULL;
g_autofree virPCIDeviceAddress *config_addr = NULL; g_autoptr(virPCIVirtualFunctionList) list = g_new0(virPCIVirtualFunctionList, 1);
*virtual_functions = NULL; *vfs = NULL;
*num_virtual_functions = 0;
*max_virtual_functions = 0;
totalvfs_file = g_strdup_printf("%s/sriov_totalvfs", sysfs_path); totalvfs_file = g_strdup_printf("%s/sriov_totalvfs", sysfs_path);
if (virFileExists(totalvfs_file)) { if (virFileExists(totalvfs_file)) {
char *end = NULL; /* so that terminating \n doesn't create error */ char *end = NULL; /* so that terminating \n doesn't create error */
unsigned long long maxfunctions = 0;
if (virFileReadAll(totalvfs_file, 16, &totalvfs_str) < 0) if (virFileReadAll(totalvfs_file, 16, &totalvfs_str) < 0)
goto error; return -1;
if (virStrToLong_ui(totalvfs_str, &end, 10, max_virtual_functions) < 0) { if (virStrToLong_ull(totalvfs_str, &end, 10, &maxfunctions) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unrecognized value in %s: %s"), _("Unrecognized value in %s: %s"),
totalvfs_file, totalvfs_str); totalvfs_file, totalvfs_str);
goto error; return -1;
} }
list->maxfunctions = maxfunctions;
} }
do { do {
g_autofree char *device_link = NULL; g_autofree char *device_link = NULL;
struct virPCIVirtualFunction fnc = { NULL };
/* look for virtfn%d links until one isn't found */ /* look for virtfn%d links until one isn't found */
device_link = g_strdup_printf("%s/virtfn%zu", sysfs_path, device_link = g_strdup_printf("%s/virtfn%zu", sysfs_path, list->nfunctions);
*num_virtual_functions);
if (!virFileExists(device_link)) if (!virFileExists(device_link))
break; break;
if (!(config_addr = virPCIGetDeviceAddressFromSysfsLink(device_link))) { if (!(fnc.addr = virPCIGetDeviceAddressFromSysfsLink(device_link))) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to get SRIOV function from device link '%s'"), _("Failed to get SRIOV function from device link '%s'"),
device_link); device_link);
goto error; return -1;
} }
VIR_APPEND_ELEMENT(*virtual_functions, *num_virtual_functions, config_addr); VIR_APPEND_ELEMENT(list->functions, list->nfunctions, fnc);
} while (1); } while (1);
VIR_DEBUG("Found %zu virtual functions for %s", VIR_DEBUG("Found %zu virtual functions for %s", list->nfunctions, sysfs_path);
*num_virtual_functions, sysfs_path);
return 0;
error: *vfs = g_steal_pointer(&list);
for (i = 0; i < *num_virtual_functions; i++) return 0;
VIR_FREE((*virtual_functions)[i]);
VIR_FREE(*virtual_functions);
*num_virtual_functions = 0;
return -1;
} }
@ -2403,24 +2411,21 @@ virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
{ {
int ret = -1; int ret = -1;
size_t i; size_t i;
size_t num_virt_fns = 0;
unsigned int max_virt_fns = 0;
g_autofree virPCIDeviceAddress *vf_bdf = NULL; g_autofree virPCIDeviceAddress *vf_bdf = NULL;
virPCIDeviceAddress **virt_fns = NULL; g_autoptr(virPCIVirtualFunctionList) virt_fns = NULL;
if (!(vf_bdf = virPCIGetDeviceAddressFromSysfsLink(vf_sysfs_device_link))) if (!(vf_bdf = virPCIGetDeviceAddressFromSysfsLink(vf_sysfs_device_link)))
return ret; return ret;
if (virPCIGetVirtualFunctions(pf_sysfs_device_link, &virt_fns, if (virPCIGetVirtualFunctions(pf_sysfs_device_link, &virt_fns) < 0) {
&num_virt_fns, &max_virt_fns) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Error getting physical function's '%s' " _("Error getting physical function's '%s' "
"virtual_functions"), pf_sysfs_device_link); "virtual_functions"), pf_sysfs_device_link);
goto out; goto out;
} }
for (i = 0; i < num_virt_fns; i++) { for (i = 0; i < virt_fns->nfunctions; i++) {
if (virPCIDeviceAddressEqual(vf_bdf, virt_fns[i])) { if (virPCIDeviceAddressEqual(vf_bdf, virt_fns->functions[i].addr)) {
*vf_index = i; *vf_index = i;
ret = 0; ret = 0;
break; break;
@ -2428,12 +2433,6 @@ virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
} }
out: out:
/* free virtual functions */
for (i = 0; i < num_virt_fns; i++)
VIR_FREE(virt_fns[i]);
VIR_FREE(virt_fns);
return ret; return ret;
} }
@ -2641,9 +2640,7 @@ virPCIGetPhysicalFunction(const char *vf_sysfs_path G_GNUC_UNUSED,
int int
virPCIGetVirtualFunctions(const char *sysfs_path G_GNUC_UNUSED, virPCIGetVirtualFunctions(const char *sysfs_path G_GNUC_UNUSED,
virPCIDeviceAddress ***virtual_functions G_GNUC_UNUSED, virPCIVirtualFunctionList **vfs G_GNUC_UNUSED)
size_t *num_virtual_functions G_GNUC_UNUSED,
unsigned int *max_virtual_functions G_GNUC_UNUSED)
{ {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
return -1; return -1;

View File

@ -212,10 +212,22 @@ virPCIGetDeviceAddressFromSysfsLink(const char *device_link);
int virPCIGetPhysicalFunction(const char *vf_sysfs_path, int virPCIGetPhysicalFunction(const char *vf_sysfs_path,
virPCIDeviceAddress **pf); virPCIDeviceAddress **pf);
struct virPCIVirtualFunction {
virPCIDeviceAddress *addr;
};
struct _virPCIVirtualFunctionList {
struct virPCIVirtualFunction *functions;
size_t nfunctions;
size_t maxfunctions;
};
typedef struct _virPCIVirtualFunctionList virPCIVirtualFunctionList;
void virPCIVirtualFunctionListFree(virPCIVirtualFunctionList *list);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virPCIVirtualFunctionList, virPCIVirtualFunctionListFree);
int virPCIGetVirtualFunctions(const char *sysfs_path, int virPCIGetVirtualFunctions(const char *sysfs_path,
virPCIDeviceAddress ***virtual_functions, virPCIVirtualFunctionList **vfs);
size_t *num_virtual_functions,
unsigned int *max_virtual_functions);
int virPCIIsVirtualFunction(const char *vf_sysfs_device_link); int virPCIIsVirtualFunction(const char *vf_sysfs_device_link);