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(a)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 :|