summaryrefslogtreecommitdiff
path: root/udev/udevadm-settle.c
diff options
context:
space:
mode:
authorScott James Remnant <scott@ubuntu.com>2009-03-10 13:00:16 +0000
committerScott James Remnant <scott@ubuntu.com>2009-03-12 10:02:37 +0000
commitbb38678e3ccc02bcd970ccde3d8166a40edf92d3 (patch)
tree77c38998c139205350553b38bc727d0790e6bb0d /udev/udevadm-settle.c
parentc2c24d4d3c8f83c5f4507bb13ba6c989f9d6ea45 (diff)
udevadm: settle - synchronise with the udev daemon
There's still a slight race condition when using udevadm settle, if the udev daemon has a pending inotify event but hasn't yet generated the "change" uevent for it, the kernel and udev sequence numbers will match and settle will exit. Now udevadm settle will send a control message to udevd, which will respond by sending SIGUSR1 back to the waiting udevadm settle once it has completed the main loop iteration in which it received the control message. If there were no pending inotify events, this will simply wake up the udev daemon and allow settle to continue. If there are pending inotify events, they are handled first in the main loop so when settle is continued they will have been turned into uevents and the kernel sequence number will have been incremented. Since the inotify event is pending for udevd when the close() system call returns (it's queued as part of the kernel handling for that system call), and since the kernel sequence number is incremented by writing to the uevent file (as udevd does), this solves the race. When the settle continues, if there were pending inotify events that udevd had not read, they are now pending uevents which settle can wait for. Signed-off-by: Scott James Remnant <scott@ubuntu.com>
Diffstat (limited to 'udev/udevadm-settle.c')
-rw-r--r--udev/udevadm-settle.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/udev/udevadm-settle.c b/udev/udevadm-settle.c
index 54f905bf6f..1c3c28176b 100644
--- a/udev/udevadm-settle.c
+++ b/udev/udevadm-settle.c
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2006-2008 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2009 Canonical Ltd.
+ * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,6 +43,8 @@ static void asmlinkage sig_handler(int signum)
switch (signum) {
case SIGALRM:
is_timeout = 1;
+ case SIGUSR1:
+ ;
}
}
@@ -70,6 +74,7 @@ int udevadm_settle(struct udev *udev, int argc, char *argv[])
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
while (1) {
int option;
@@ -148,6 +153,24 @@ int udevadm_settle(struct udev *udev, int argc, char *argv[])
}
}
+ /* guarantee that the udev daemon isn't pre-processing */
+ if (getuid() == 0) {
+ struct udev_ctrl *uctrl;
+
+ uctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH);
+ if (uctrl != NULL) {
+ sigset_t mask, oldmask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ sigaddset(&mask, SIGALRM);
+ sigprocmask(SIG_BLOCK, &mask, &oldmask);
+ if (udev_ctrl_send_settle(uctrl) > 0)
+ sigsuspend(&oldmask);
+ udev_ctrl_unref(uctrl);
+ }
+ }
+
while (!is_timeout) {
/* exit if queue is empty */
if (udev_queue_get_queue_is_empty(udev_queue))