On 06/25/2013 06:40 AM, Daniel P. Berrange wrote:
On Mon, Jun 24, 2013 at 11:05:30PM -0400, Laine Stump wrote:
> Any device which belongs to an "IOMMU group" (used by vfio) will
> have links to all devices of its group listed in
> /sys/bus/pci/$device/iommu_group/devices;
> /sys/bus/pci/$device/iommu_group is actually a link to
> /sys/kernel/iommu_groups/$n, where $n is the group number (there
> will be a corresponding device node at /dev/vfio/$n once the
> devices are bound to the vfio-pci driver)
> diff --git a/src/util/virpci.c b/src/util/virpci.c
> index fc04cac..5209372 100644
> --- a/src/util/virpci.c
> +++ b/src/util/virpci.c
> @@ -1852,6 +1852,223 @@ cleanup:
> return ret;
> }
>
> +
> +/* virPCIIOMMUGroupIterate:
> + * Call @actor for all devices in the same iommu_group as orig
> + * (including orig itself) Even if there is no iommu_group for the
> + * device, call @actor once for orig.
> + */
> +int
> +virPCIIOMMUGroupIterate(virPCIDeviceAddressPtr orig,
> + virPCIDeviceAddressActor actor,
> + void *opaque)
> +{
> + char *groupPath = NULL;
> + DIR *groupDir = NULL;
> + int ret = -1;
> + struct dirent *ent;
> +
> + if (virAsprintf(&groupPath,
> + PCI_SYSFS
"devices/%04x:%02x:%02x.%x/iommu_group/devices",
> + orig->domain, orig->bus, orig->slot, orig->function)
< 0) {
> + virReportOOMError();
> + goto cleanup;
> + }
> +
> + if (!(groupDir = opendir(groupPath))) {
> + /* just process the original device, nothing more */
> + ret = (actor)(orig, opaque);
> + goto cleanup;
> + }
> +
Since Eric isn't around to nit-pick, I'll do it :-)
Set 'errno = 0' here before the readdir() call
> + while ((ent = readdir(groupDir)) != NULL) {
> + virPCIDeviceAddress newDev;
> +
> + if (ent->d_name[0] == '.')
> + continue;
> +
> + if (virPCIParseDeviceAddress(ent->d_name, &newDev) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Found invalid device link '%s' in
'%s'"),
> + ent->d_name, groupPath);
> + goto cleanup;
> + }
> +
> + if ((actor)(&newDev, opaque) < 0)
> + goto cleanup;
And here
errno = 0;
> + }
Then do
if (errno != 0) {
virReportSystemError(errno, _("Failed to read directory entry for
%s"), grouppath)
goto cleanup
}
that way you distinguish EOF from error when readdir() returns NULL.
/me makes a note that we should write a wrapper around readdir(),
since almost all our code has this wrong.
Definitely. If I ever did know about this idiosyncracy of readdir() in
the past, I had certainly forgotten it.
> +
> + ret = 0;
> +
> +cleanup:
> + VIR_FREE(groupPath);
> + if (groupDir)
> + closedir(groupDir);
> + return ret;
> +}
> +
> +
> +static int
> +virPCIDeviceGetIOMMUGroupAddOne(virPCIDeviceAddressPtr newDevAddr, void *opaque)
> +{
> + int ret = -1;
> + virPCIDeviceListPtr groupList = opaque;
> + virPCIDevicePtr newDev;
> +
> + if (!(newDev = virPCIDeviceNew(newDevAddr->domain, newDevAddr->bus,
> + newDevAddr->slot, newDevAddr->function)))
{
> + goto cleanup;
> + }
> +
> + if (virPCIDeviceListAdd(groupList, newDev) < 0) {
> + goto cleanup;
> + }
> + newDev = NULL; /* it's now on the list */
> + ret = 0;
> +cleanup:
> + virPCIDeviceFree(newDev);
> + return ret;
> +}
> +
> +
> +/*
> + * virPCIDeviceGetIOMMUGroupList - return a virPCIDeviceList containing
> + * all of the devices in the same iommu_group as @dev.
> + *
> + * Return the new list, or NULL on failure
> + */
> +virPCIDeviceListPtr
> +virPCIDeviceGetIOMMUGroupList(virPCIDevicePtr dev)
> +{
> + virPCIDeviceListPtr groupList = virPCIDeviceListNew();
> + virPCIDeviceAddress devAddr = { dev->domain, dev->bus,
> + dev->slot, dev->function };
> +
> + if (!groupList)
> + goto error;
> +
> + if (virPCIIOMMUGroupIterate(&devAddr, virPCIDeviceGetIOMMUGroupAddOne,
> + groupList) < 0) {
> + goto error;
> + }
Overkill with {} here
In addition to the necessary braces when the body is > 1 line, I also
like to have {} when the conditional itself is > 1 line (and I've been
doing that ever since I can remember). If you dislike it I can cease and
desist, though :-)
> +static int
> +virPCIGetIOMMUGroupAddressesAddOne(virPCIDeviceAddressPtr newDevAddr, void *opaque)
> +{
> + int ret = -1;
> + virPCIDeviceAddressListPtr addrList = opaque;
> + virPCIDeviceAddressPtr copyAddr;
> +
> + /* make a copy to insert onto the list */
> + if (VIR_ALLOC(copyAddr) < 0)
> + goto cleanup;
> +
> + *copyAddr = *newDevAddr;
> +
> + if (VIR_APPEND_ELEMENT(*addrList->iommuGroupDevices,
> + *addrList->nIommuGroupDevices, copyAddr) < 0) {
> + goto cleanup;
> + }
Overkill with {}
Missing virReportOOMError() ?
Yes. I caught myself omitting one of those the other night, and at the
time thought to myself "I think I left one out somewhere else too...".
Maybe we should send *all* VIR_* macros down the same road as
VIR_STRDUP, and integrate OOM error logging into them.
> +
> + ret = 0;
> +cleanup:
> + VIR_FREE(copyAddr);
> + return ret;
> +}
> +
> +
> +/*
> + * virPCIGetIOMMUGroupAddresses - return a virPCIDeviceList containing
> + * all of the devices in the same iommu_group as @dev.
> + *
> + * Return the new list, or NULL on failure
> + */
> +int
> +virPCIGetIOMMUGroupAddresses(virPCIDeviceAddressPtr devAddr,
> + virPCIDeviceAddressPtr **iommuGroupDevices,
> + size_t *nIommuGroupDevices)
> +{
> + int ret = -1;
> + virPCIDeviceAddressList addrList = { iommuGroupDevices,
> + nIommuGroupDevices };
> +
> + if (virPCIIOMMUGroupIterate(devAddr,
> + virPCIGetIOMMUGroupAddressesAddOne,
> + &addrList) < 0) {
> + goto cleanup;
> + }
Overkill with {}
Same deal - the condition is 3 lines long and this gives me a visual
crush. It could just be because I'm accustomed to it though (I also used
to hate the K&R/libvirt style of putting the opening brace at the end of
the line, but I've gotten used to that too)