[libvirt] [PATCH v3 1/6] nodedev: Introduce udevCheckMonitorFD helper function

John Ferlan jferlan at redhat.com
Mon Aug 28 15:03:12 UTC 2017



On 08/24/2017 07:23 AM, Erik Skultety wrote:
> We need to perform some sanity checks on the udev monitor before every
> use so that we know nothing changed in the meantime. The reason for
> moving the code to a separate function is to be able to perform the same
> check from a worker thread that will replace the udevEventHandleCallback
> in terms of poking udev for device events.
> 
> Signed-off-by: Erik Skultety <eskultet at redhat.com>
> ---
>  src/node_device/node_device_udev.c | 57 ++++++++++++++++++++++++++------------
>  1 file changed, 39 insertions(+), 18 deletions(-)
> 
> diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
> index f4177455c..465d272ba 100644
> --- a/src/node_device/node_device_udev.c
> +++ b/src/node_device/node_device_udev.c
> @@ -1615,47 +1615,68 @@ udevHandleOneDevice(struct udev_device *device)
>  }
>  
>  
> -static void
> -udevEventHandleCallback(int watch ATTRIBUTE_UNUSED,
> -                        int fd,
> -                        int events ATTRIBUTE_UNUSED,
> -                        void *data ATTRIBUTE_UNUSED)
> +/* the caller must be holding the driver lock prior to calling this function */
> +static bool
> +udevCheckMonitorFD(struct udev_monitor *udev_monitor, int fd)

One line for each argument...

I think in keeping with other functions - this should be named
'udevEventCheckMonitorFD'

>  {
> -    struct udev_device *device = NULL;
> -    struct udev_monitor *udev_monitor = DRV_STATE_UDEV_MONITOR(driver);
> -    int udev_fd = -1;
> +    int real_fd = -1;
>  
> -    udev_fd = udev_monitor_get_fd(udev_monitor);
> -    if (fd != udev_fd) {
> +    /* sanity check that the monitor socket hasn't changed */
> +    real_fd = udev_monitor_get_fd(udev_monitor);
> +
> +    if (real_fd != fd) {
>          udevPrivate *priv = driver->privateData;
>  
>          virReportError(VIR_ERR_INTERNAL_ERROR,
>                         _("File descriptor returned by udev %d does not "
>                           "match node device file descriptor %d"),
> -                       fd, udev_fd);
> +                       real_fd, fd);
>  
> -        /* this is a non-recoverable error, let's remove the handle, so that we
> -         * don't get in here again because of some spurious behaviour and report
> -         * the same error multiple times
> +        /* this is a non-recoverable error, thus the event handle has to be
> +         * removed, so that we don't get into the handler again because of some
> +         * spurious behaviour
>           */
>          virEventRemoveHandle(priv->watch);
>          priv->watch = -1;

Hmmm... thinking a couple patches later - this would seem to be a good
candidate for something that udevEventThreadDataFree could do (as long
as it held the appropriate lock of course).

It's almost too bad we couldn't somehow "pretend" to have a restart...
different problem though!

>  
> -        goto cleanup;
> +        return false;
>      }
>  
> -    device = udev_monitor_receive_device(udev_monitor);
> -    if (device == NULL) {
> +    return true;
> +}
> +
> +
> +static void
> +udevEventHandleCallback(int watch ATTRIBUTE_UNUSED,
> +                        int fd,
> +                        int events ATTRIBUTE_UNUSED,
> +                        void *data ATTRIBUTE_UNUSED)
> +{
> +    struct udev_device *device = NULL;
> +    struct udev_monitor *udev_monitor = NULL;
> +
> +    nodeDeviceLock();
> +    udev_monitor = DRV_STATE_UDEV_MONITOR(driver);


Technically there's a couple of things going on here - including the
addition of the nodeDevice{Lock|Unlock}.

Probably would have been best to make the split first, then add the
Lock/Unlock afterwards (or vice versa).

Still once I get to patch 3, I began wondering how the udev interaction
works.

> +
> +    if (!udevCheckMonitorFD(udev_monitor, fd))
> +        goto unlock;> +
> +    if (!(device = udev_monitor_receive_device(udev_monitor))) {
>          virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>                         _("udev_monitor_receive_device returned NULL"));

I almost wonder if it would be better to have this be a
ReportSystemError w/ errno...  Not that udev docs give any guidance
there, but maybe it'd help.

> -        goto cleanup;
> +        goto unlock;

I know this is "existing"; however, if !device, then what's the purpose
of calling udev_device_unref(NULL)? In fact there's one path in
udevGetDMIData which actually checks != NULL before calling - although
it has no reason to since I see no way for it to be NULL at cleanup
(again a different issue).

Also, wouldn't nodeDeviceLock/Unlock wrapping only be necessary within
udevCheckMonitorFD?  Why would the udev call need to be wrapped as well?

John

>      }
>  
> +    nodeDeviceUnlock();
>      udevHandleOneDevice(device);
>  
>   cleanup:
>      udev_device_unref(device);
>      return;
> +
> + unlock:
> +    nodeDeviceUnlock();
> +    goto cleanup;
>  }
>  
>  
> 




More information about the libvir-list mailing list