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. > + > + 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 > +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() ? > + > + 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 {} > + > + ret = 0; > +cleanup: > + return ret; > +} > + Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list