
On Thu, Dec 24, 2020 at 08:14:31AM -0600, Jonathon Jongsma wrote:
At startup, query devices that are defined by 'mdevctl' and add them to the node device list.
This adds a complication: we now have two potential sources of information for a node device: - udev for all devices and for activated mediated devices - mdevctl for persistent mediated devices
Unfortunately, neither backend returns full information for a mediated device. For example, if a persistent mediated device in the list (with information provided from mdevctl) is 'started', that same device will now be detected by udev. If we simply overwrite the existing device definition with the new one provided by the udev backend, we will lose extra information that was provided by mdevctl (e.g. attributes, etc). To avoid this, make sure to copy the extra information into the new device definition.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> --- src/node_device/node_device_driver.c | 76 ++++++++++++++++++++++++++++ src/node_device/node_device_driver.h | 3 ++ src/node_device/node_device_udev.c | 48 ++++++++++++++++++ 3 files changed, 127 insertions(+)
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 5309b8abd5..0267005af1 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -1144,3 +1144,79 @@ nodeDeviceGenerateName(virNodeDeviceDefPtr def, *(def->name + i) = '_'; } } + + +static int +virMdevctlListDefined(virNodeDeviceDefPtr **devs) +{ + int status; + g_autofree char *output = NULL; + g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlListCommand(true, &output); + + if (virCommandRun(cmd, &status) < 0) + return -1; + + if (!output) + return -1; + + return nodeDeviceParseMdevctlJSON(output, devs); +} + + +int +nodeDeviceUpdateMediatedDevices(void) +{ + g_autofree virNodeDeviceDefPtr *devs = NULL; + int ndevs; + size_t i; + + if ((ndevs = virMdevctlListDefined(&devs)) < 0) { + virReportSystemError(errno, "%s", + _("failed to query mdevs from mdevctl")); + return -1; + } + + for (i = 0; i < ndevs; i++) { + virNodeDeviceObjPtr obj; + virObjectEventPtr event; + virNodeDeviceDefPtr dev = devs[i]; + bool new_device = true; + + dev->driver = g_strdup("vfio_mdev"); + + /* If a device defined by mdevctl is already in the list, that means + * that it was found via the normal device discovery process and thus + * is already activated. Active devices contain some additional + * information (e.g. sysfs path) that is not provided by mdevctl, so + * preserve that info */ + if ((obj = virNodeDeviceObjListFindByName(driver->devs, dev->name))) { + virNodeDeviceDefPtr olddef = virNodeDeviceObjGetDef(obj); + + /* Copy any data from the existing device */ + dev->sysfs_path = g_strdup(olddef->sysfs_path); + dev->parent_sysfs_path = g_strdup(olddef->parent_sysfs_path); + dev->driver = g_strdup(olddef->driver); + dev->devnode = g_strdup(olddef->devnode); + dev->caps->data.mdev.iommuGroupNumber = olddef->caps->data.mdev.iommuGroupNumber; + + virNodeDeviceObjEndAPI(&obj); + new_device = false; + } + + if (!(obj = virNodeDeviceObjListAssignDef(driver->devs, dev))) { + virNodeDeviceDefFree(dev); + return -1; + } + + if (new_device) + event = virNodeDeviceEventLifecycleNew(dev->name, + VIR_NODE_DEVICE_EVENT_CREATED, + 0);
As mentioned in the other patch, we need to have DEFINED/UNDEFINED events. In fact this method doens't seem to remove existing mdevs that no longer exist.
+ else + event = virNodeDeviceEventUpdateNew(dev->name);
This is triggering events for all devices every time any single device changes, even if those devices have no changes. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|