[systemd-devel] [PATCH] allow udev to correctly handle 'change' after device has disappeared

NeilBrown neilb at suse.de
Sun Nov 18 17:03:42 PST 2012


On Thu, 08 Nov 2012 17:48:44 +0100 Kay Sievers <kay at vrfy.org> wrote:

> On Thu, 2012-11-08 at 11:13 +0100, Robert Milasan wrote:
> > From: Neil Brown <nfbrown at suse.com>
> > Date: Thu, 8 Nov 2012 10:39:06 +0100
> > Subject: [PATCH] If a 'change' event does not get handled by udev until
> > after the device has subsequently disappeared, udev mis-handles
> >  it. This can happen with 'md' devices which emit a change
> >  event and then a remove event when they are stopped. It is
> >  normally only noticed if udev is very busy (lots of arrays
> >  being stopped at once) or the machine is otherwise loaded
> >  and reponding slowly.
> > 
> > There are two problems.
> > 
> > 1/ udev_device_new_from_syspath() will refuse to create the device
> >   structure if the device does not exist in /sys, and particularly if
> > the uevent file does not exist.
> >   If a 'db' file does exist, that is sufficient evidence that the device
> >   is genuine and should be created.  Equally if we have just received an
> >   event from the kernel about the device, it must be real.
> > 
> >   This patch just disabled the test for the 'uevent' file, it doesn't
> >   try imposing any other tests - it isn't clear that they are really
> >   needed.
> > 
> > 2/ udev_event_execute_rules() calls udev_device_read_db() on a 'device'
> >    structure that is largely uninitialised and in particular does not
> >    have the 'subsystem' set.  udev_device_read_db() needs the subsystem
> >    so it tries to read the 'subsystem' symlink out of sysfs.  If the
> > device is already deleted, this naturally fails.
> >    udev_event_execute_rules() knows the subsystem (as it was in the
> > event message) so this patch simply sets the subsystem for the device
> > structure to be loaded to match the subsystem of the device structure
> > that is handling the event.
> > 
> > With these two changes, deleted handling of change events will still
> > correctly remove any symlinks that are not needed any more.
> 
> The problem is that at the time the 'change' event is handled, the
> device is already removed by the kernel, right? That way we fail to read
> the database with the currently created symlinks?
> 
> The udev_device_new_from_syspath() is a public API from libudev. We
> should probably not change that and not allow other tools than udev
> itself, to create device structures for devices which are not around
> anymore.
> 
> Any chance to check if the patch below fixes the issue you see too. It
> would preserve the current libudev behavior.

Hi Kay,
 yes, that patch looks much nicer than mine.  Testing so far suggests it
 works just as well if not better.

Thanks,
NeilBrown


> 
> Thanks,
> Kay
> 
> diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
> index 08476e6..b267141 100644
> --- a/src/libudev/libudev-device.c
> +++ b/src/libudev/libudev-device.c
> @@ -246,7 +246,7 @@ static int udev_device_set_devtype(struct udev_device *udev_device, const char *
>          return 0;
>  }
>  
> -static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
> +int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
>  {
>          free(udev_device->subsystem);
>          udev_device->subsystem = strdup(subsystem);
> diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h
> index d233565..49cebc1 100644
> --- a/src/libudev/libudev-private.h
> +++ b/src/libudev/libudev-private.h
> @@ -48,6 +48,7 @@ struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
>  /* libudev-device.c */
>  struct udev_device *udev_device_new(struct udev *udev);
>  mode_t udev_device_get_devnode_mode(struct udev_device *udev_device);
> +int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem);
>  int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
>  int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
>  int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink);
> diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
> index 2b9fdf6..39f36f9 100644
> --- a/src/udev/udev-event.c
> +++ b/src/udev/udev-event.c
> @@ -797,8 +797,10 @@ int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules,
>                  if (major(udev_device_get_devnum(dev)) != 0)
>                          udev_node_remove(dev);
>          } else {
> -                event->dev_db = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev));
> +                event->dev_db = udev_device_new(event->udev);
>                  if (event->dev_db != NULL) {
> +                        udev_device_set_syspath(event->dev_db, udev_device_get_syspath(dev));
> +                        udev_device_set_subsystem(event->dev_db, udev_device_get_subsystem(dev));
>                          udev_device_read_db(event->dev_db, NULL);
>                          udev_device_set_info_loaded(event->dev_db);
>  
> 
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 828 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/systemd-devel/attachments/20121119/b84fff20/attachment.pgp>


More information about the systemd-devel mailing list