--- a/sys/kern/kern_udev.c +++ b/sys/kern/kern_udev.c @@ -534,11 +534,26 @@ udev_event_insert(int ev_type, prop_dictionary_t dict) static void udev_clean_events_locked(void) { struct udev_event_kernel *ev; - while ((ev = TAILQ_FIRST(&udev_evq)) && - ev->ev.ev_dict != NULL) { + /* + * Reap events that every reader has passed (markers have + * ev_dict == NULL and are skipped). The event's single + * reference on ev_dict is released HERE and nowhere else. + * + * When the last reader is gone (udev_initiated_count == 0) no + * marker can remain in the queue, so drain everything -- + * otherwise undelivered events leak their dictionaries forever. + */ + while ((ev = TAILQ_FIRST(&udev_evq)) != NULL && + (udev_initiated_count == 0 || ev->ev.ev_dict != NULL)) { + if (ev->ev.ev_dict != NULL) { + prop_object_release(ev->ev.ev_dict); + ev->ev.ev_dict = NULL; + } TAILQ_REMOVE(&udev_evq, ev, link); objcache_put(udev_event_kernel_cache, ev); --udev_evqlen; } } @@ -566,7 +581,6 @@ udev_event_externalize(struct udev_event_kernel *ev) if (prop_dictionary_set(dict, "evdict", ev->ev.ev_dict) == false) { prop_object_release(dict); return NULL; } - prop_object_release(ev->ev.ev_dict); xml = prop_dictionary_externalize(dict);