[libvirt PATCH v3 07/21] nodedev: add mdevctl devices to node device list

Erik Skultety eskultet at redhat.com
Wed Jan 6 10:39:11 UTC 2021


On Wed, Jan 06, 2021 at 11:27:09AM +0100, Erik Skultety wrote:
> 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 at 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)
> 
> ^This was called mdevctlEnumerateDevices in v2, so I'm wondering why did you
> change the name? I think it was okay the way it was (I double checked that I
> didn't suggest this change in v2 by accident).
> 
> > +{
> > +    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;
> 
> So, what data other than attributes are coming from mdevctl that we have to
> copy the udev provided data from the old def ^this way?
> When I look at virNodeDeviceDef, If I'm not missing anything, the added value
> from mdevctl are the caps, more specifically, attributes right? If that is true
> I think we should revert the logic and use the function that you introduce
> at the end of the patch that copies extra data and use it here as well.
> To describe my thoughts into more details, at the end of the patch you add
> calls to udevAddOneDevice and nodeStateInitializeEnumerate.
> 
> In the former case, we already enumerated the devices, including mdevctl, so
> now when we start an mdev, we get an event from udev and what do we do? We take
> that info and copy the attributes from the existing definition to it, so
> the data flows more or less like udev <- mdevctl.
> In the latter case though, we first enumerated udev devices, then asked mdevctl
> which created a new def ptr for us and we copied the data from udev and then
> redefined the device, so mdevctl <- udev.
> If I'm not missing some crucial information I think the logic can be reverted
> in one of those cases so that we always copy from the same source to the same
> destination to apply a new definition.
> 
> > +
> > +            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);
> > +        else
> > +            event = virNodeDeviceEventUpdateNew(dev->name);
> > +        virNodeDeviceObjEndAPI(&obj);
> > +        virObjectEventStateQueue(driver->nodeDeviceEventState, event);
> > +    }
> > +
> > +    return 0;
> > +}
> > diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h
> > index 80ac7c5320..4315f6d6ed 100644
> > --- a/src/node_device/node_device_driver.h
> > +++ b/src/node_device/node_device_driver.h
> > @@ -126,6 +126,9 @@ int
> >  nodeDeviceParseMdevctlJSON(const char *jsonstring,
> >                             virNodeDeviceDefPtr **devs);
> >  
> > +int
> > +nodeDeviceUpdateMediatedDevices(void);
> > +
> >  void
> >  nodeDeviceGenerateName(virNodeDeviceDefPtr def,
> >                         const char *subsystem,
> > diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
> > index 632413d046..223ee5a2ff 100644
> > --- a/src/node_device/node_device_udev.c
> > +++ b/src/node_device/node_device_udev.c
> > @@ -1494,6 +1494,50 @@ udevSetParent(struct udev_device *device,
> >      return 0;
> >  }
> >  
> > +static virMediatedDeviceAttrPtr *
> > +virMediatedDeviceAttrsCopy(virMediatedDeviceAttrPtr *attrs,
> > +                           size_t nattrs)
> > +{
> > +    size_t i;
> > +    size_t j = 0;
> > +    g_autofree virMediatedDeviceAttrPtr *ret = NULL;
> > +
> > +    if (nattrs == 0)
> > +        return NULL;
> > +
> > +    ret = g_new0(virMediatedDeviceAttrPtr, nattrs);
> > +
> > +    for (i = 0; i < nattrs; i++) {
> > +        virMediatedDeviceAttrPtr attr = virMediatedDeviceAttrNew();
> > +        attr->name = g_strdup(attrs[i]->name);
> > +        attr->value = g_strdup(attrs[i]->value);
> > +        VIR_APPEND_ELEMENT_INPLACE(ret, j, attr);
> > +    }
> > +
> > +    return g_steal_pointer(ret);
> > +}
> > +
> > +/* An existing device definition may have additional info from mdevctl that is
> > + * not available from udev. Transfer this data to the new definition */
> > +static void
> > +nodeDeviceDefCopyExtraData(virNodeDeviceDefPtr dst,
> > +                           virNodeDeviceDefPtr src)
> 
> ^This name is too vague, we're likely going to only use it with mdevs (and if
> the time comes we need to make it generic, we can easily create a wrapper).
> I'd suggest nodeDeviceDefCopyFromMdevctl or something similar to make it clear
> at first glance what we're trying to copy, because extra data is basically
> "void *".
> 
> > +{
> > +    virNodeDevCapMdevPtr srcmdev;
> > +    virNodeDevCapMdevPtr dstmdev;
> > +
> > +    if (dst->caps->data.type != VIR_NODE_DEV_CAP_MDEV)
> > +        return;
> 
> I think ^this check would be better on the caller side since we're tailoring it
> to mdevs.
> 
> > +
> > +    srcmdev = &src->caps->data.mdev;
> > +    dstmdev = &dst->caps->data.mdev;
> > +
> > +    dstmdev->persistent = srcmdev->persistent;
> > +    dstmdev->nattributes = srcmdev->nattributes;
> > +    dstmdev->attributes = virMediatedDeviceAttrsCopy(srcmdev->attributes,
> > +                                                     srcmdev->nattributes);
> > +}
> > +
> >  
> >  static int
> >  udevAddOneDevice(struct udev_device *device)
> > @@ -1527,6 +1571,8 @@ udevAddOneDevice(struct udev_device *device)
> >          goto cleanup;
> >  
> >      if ((obj = virNodeDeviceObjListFindByName(driver->devs, def->name))) {
> > +        nodeDeviceDefCopyExtraData(def, virNodeDeviceObjGetDef(obj));
> 
> ...the check mentioned above should come here, it'll help the code readability
> instantly to signal that we're not trying to change/copy anything unless the
> device for which udev generated an event is an mdev.
> 
> Erik
> 
> > +
> >          virNodeDeviceObjEndAPI(&obj);
> >          new_device = false;
> >      }
> > @@ -1953,6 +1999,8 @@ nodeStateInitializeEnumerate(void *opaque)
> >      /* Populate with known devices */
> >      if (udevEnumerateDevices(udev) != 0)
> >          goto error;

Also, I think a one line commentary explaining why we're explicitly
updating/enumerating mdevs from mdevctl would be nice too, something like
"we don't all the data about mdevs from udev, we query mdevctl for the rest"

Erik

> > +    if (nodeDeviceUpdateMediatedDevices() != 0)
> > +        goto error;
> >  
> >      nodeDeviceLock();
> >      driver->initialized = true;
> > -- 
> > 2.26.2
> > 
> 




More information about the libvir-list mailing list