[libvirt] [PATCHv2 04/12] pci: new iommu_group functions
Laine Stump
laine at laine.org
Tue Jun 25 16:52:40 UTC 2013
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)
More information about the libvir-list
mailing list