Don't discard DM_COOKIE events while udev is exiting, like we already do with timely events (like firmware loading). -- Herton R. Krzesinski diff -Naurp udev-173.orig1/libudev/libudev-device.c udev-173/libudev/libudev-device.c --- udev-173.orig1/libudev/libudev-device.c 2011-07-07 16:17:35.923667367 -0300 +++ udev-173/libudev/libudev-device.c 2012-02-02 18:02:49.062873000 -0200 @@ -89,6 +89,7 @@ struct udev_device { bool is_initialized; bool sysattr_list_read; bool db_persist; + bool dm_cookie_set; }; /** @@ -345,6 +346,27 @@ static int udev_device_set_devnode_mode( return 0; } +/** + * udev_device_get_dm_cookie_set: + * @udev_device: udev device + * + * Retrieve the status of DM_COOKIE available for this udev device. + * + * Returns: true if DM_COOKIE was set for this device, false otherwise + **/ +UDEV_EXPORT bool udev_device_get_dm_cookie_set(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_device->dm_cookie_set; +} + +static int udev_device_set_dm_cookie_set(struct udev_device *udev_device) +{ + udev_device->dm_cookie_set = true; + return 0; +} + struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) { udev_device->envp_uptodate = false; @@ -455,6 +477,9 @@ void udev_device_add_property_from_strin udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); } else if (strncmp(property, "DEVMODE=", 8) == 0) { udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8)); + } else if (strncmp(property, "DM_COOKIE=", 10) == 0) { + udev_device_set_dm_cookie_set(udev_device); + udev_device_add_property_from_string(udev_device, property); } else { udev_device_add_property_from_string(udev_device, property); } diff -Naurp udev-173.orig1/libudev/libudev-private.h udev-173/libudev/libudev-private.h --- udev-173.orig1/libudev/libudev-private.h 2011-07-10 20:07:28.713153376 -0300 +++ udev-173/libudev/libudev-private.h 2012-02-02 18:03:08.014892554 -0200 @@ -101,6 +101,7 @@ int udev_device_get_ifindex(struct udev_ void udev_device_set_info_loaded(struct udev_device *device); bool udev_device_get_db_persist(struct udev_device *udev_device); void udev_device_set_db_persist(struct udev_device *udev_device); +bool udev_device_get_dm_cookie_set(struct udev_device *udev_device); /* libudev-device-private.c */ int udev_device_update_db(struct udev_device *udev_device); diff -Naurp udev-173.orig1/udev/udevd.c udev-173/udev/udevd.c --- udev-173.orig1/udev/udevd.c 2012-02-02 17:57:34.000000000 -0200 +++ udev-173/udev/udevd.c 2012-02-02 18:03:27.518872999 -0200 @@ -466,8 +466,10 @@ static int event_queue_insert(struct ude event->state = EVENT_QUEUED; udev_list_node_append(&event->node, &event_list); - /* run all events with a timeout set immediately */ - if (udev_device_get_timeout(dev) > 0) { + /* run all events with a timeout set immediately, or in the case + * it's a dm_cookie event being processed */ + if (udev_device_get_timeout(dev) > 0 || + udev_device_get_dm_cookie_set(dev)) { event_run(event, true); return 0; } @@ -592,7 +594,7 @@ static void event_queue_start(struct ude } } -static void __event_queue_cleanup(struct udev *udev, enum event_state match_type, bool keep_timely) +static void __event_queue_cleanup(struct udev *udev, enum event_state match_type, bool must_keep) { struct udev_list_node *loop, *tmp; @@ -602,9 +604,13 @@ static void __event_queue_cleanup(struct if (match_type != EVENT_UNDEF && match_type != event->state) continue; - /* Keep events which have timelyness requirements - * we will skew these timeouts on coldplug. */ - if (keep_timely && udev_device_get_timeout(event->dev) > 0) + /* Keep events which have timelyness requirements, + * we will skew these timeouts on coldplug. Also, + * dm events with DM_COOKIE set must be kept and + * processed to avoid potential lvm tools deadlock on + * udev_exit */ + if (must_keep && (udev_device_get_timeout(event->dev) > 0 || + udev_device_get_dm_cookie_set(event->dev))) continue; event_queue_delete(event, false); @@ -616,7 +622,7 @@ static void event_queue_cleanup(struct u __event_queue_cleanup(udev, match_type, false); } -static void event_queue_cleanup_nontimely(struct udev *udev, enum event_state match_type) +static void event_queue_cleanup_onexit(struct udev *udev, enum event_state match_type) { __event_queue_cleanup(udev, match_type, true); } @@ -1641,8 +1647,8 @@ int main(int argc, char *argv[]) fd_inotify = -1; } - /* discard queued non-timely events and kill workers */ - event_queue_cleanup_nontimely(udev, EVENT_QUEUED); + /* discard most queued events and kill workers */ + event_queue_cleanup_onexit(udev, EVENT_QUEUED); worker_kill(udev, 0); /* exit after all has cleaned up */ @@ -1694,9 +1700,12 @@ int main(int argc, char *argv[]) dev = udev_monitor_receive_device(monitor); if (dev != NULL) { - /* If we are exiting then only schedule events with - * timeliness requirements. */ - if (!udev_exit || udev_device_get_timeout(dev) > 0) { + /* If we are exiting then only schedule critical + * events (with timeliness requirements or with + * DM_COOKIE set). */ + if (!udev_exit || + udev_device_get_timeout(dev) > 0 || + udev_device_get_dm_cookie_set(dev)) { if (event_queue_insert(dev) < 0) udev_device_unref(dev); } else