summaryrefslogtreecommitdiff
path: root/udevd.c
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2007-04-19 22:21:05 +0200
committerKay Sievers <kay.sievers@vrfy.org>2007-04-19 22:21:05 +0200
commitfc630edad4631f4c046052f504a67ce9df381531 (patch)
tree3f3f0a0381dec758cb35a47a5bc6578edd4cd9a1 /udevd.c
parent3a6704cba7f0e37bcb957f836fa1d5f873f20dae (diff)
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.
Diffstat (limited to 'udevd.c')
-rw-r--r--udevd.c42
1 files changed, 32 insertions, 10 deletions
diff --git a/udevd.c b/udevd.c
index 8f3329ea63..dccc745eff 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;
}