From: Kay Sievers Date: Thu, 19 Apr 2007 20:21:05 +0000 (+0200) Subject: udevd: fix serialization of events X-Git-Tag: 174~1998 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=fc630edad4631f4c046052f504a67ce9df381531 udevd: fix serialization of events We see sequences like: UEVENT[1176966403.907336] add@/block/dasda UDEV [1176966403.920359] add@/block/dasda UEVENT[1176966403.964379] add@/block/dasda/dasda1 UEVENT[1176966403.964438] add@/block/dasda/dasda2 UEVENT[1176966403.964483] online@/block/dasda UEVENT[1176966403.964519] online@/block/dasda/dasda1 UEVENT[1176966403.964555] online@/block/dasda/dasda2 UDEV [1176966403.967413] add@/block/dasda/dasda1 UDEV [1176966403.968719] add@/block/dasda/dasda2 UDEV [1176966403.974750] online@/block/dasda/dasda1 UDEV [1176966403.982241] online@/block/dasda/dasda2 UDEV [1176966403.999847] online@/block/dasda where the event for the disk (last event) should come before the events for the partitons. We skipped events for dependency reasons, but the dependency check for later events did not see the skipped events. --- diff --git a/udevd.c b/udevd.c index 8f3329ea6..dccc745ef 100644 --- a/udevd.c +++ b/udevd.c @@ -495,26 +495,49 @@ static int compare_devpath(const char *running, const char *waiting) return 0; } -/* returns still running task for the same device, its parent or its physical device */ -static int running_with_devpath(struct udevd_uevent_msg *msg, int limit) +/* lookup event for identical, parent, child, or physical device */ +static int devpath_busy(struct udevd_uevent_msg *msg, int limit) { struct udevd_uevent_msg *loop_msg; int childs_count = 0; + /* check exec-queue which may still contain delayed events we depend on */ + list_for_each_entry(loop_msg, &exec_list, node) { + /* skip ourself and all later events */ + if (loop_msg->seqnum >= msg->seqnum) + break; + + /* check identical, parent, or child device event */ + if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) { + dbg("%llu, device event still pending %llu (%s)", + msg->seqnum, loop_msg->seqnum, loop_msg->devpath); + return 2; + } + + /* check physical device event (special case of parent) */ + if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0) + if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) { + dbg("%llu, physical device event still pending %llu (%s)", + msg->seqnum, loop_msg->seqnum, loop_msg->devpath); + return 3; + } + } + + /* check runing-queue for still running events */ list_for_each_entry(loop_msg, &running_list, node) { if (limit && childs_count++ > limit) { - dbg("%llu, maximum number (%i) of child reached", msg->seqnum, childs_count); + dbg("%llu, maximum number (%i) of childs reached", msg->seqnum, childs_count); return 1; } - /* return running parent/child device event */ + /* check identical, parent, or child device event */ if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) { - dbg("%llu, child device event still running %llu (%s)", + dbg("%llu, device event still running %llu (%s)", msg->seqnum, loop_msg->seqnum, loop_msg->devpath); return 2; } - /* return running physical device event */ + /* check physical device event (special case of parent) */ if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0) if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) { dbg("%llu, physical device event still running %llu (%s)", @@ -522,11 +545,10 @@ static int running_with_devpath(struct udevd_uevent_msg *msg, int limit) return 3; } } - return 0; } -/* exec queue management routine executes the events and serializes events in the same sequence */ +/* serializes events for the identical and parent and child devices */ static void msg_queue_manager(void) { struct udevd_uevent_msg *loop_msg; @@ -552,8 +574,8 @@ static void msg_queue_manager(void) } } - /* don't run two processes for the same devpath and wait for the parent*/ - if (running_with_devpath(loop_msg, max_childs)) { + /* serialize and wait for parent or child events */ + if (devpath_busy(loop_msg, max_childs) != 0) { dbg("delay seq %llu (%s)", loop_msg->seqnum, loop_msg->devpath); continue; }