From 0b3dfb3d72e1df5f38ecb9669e37e5e77d958343 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 7 Nov 2005 02:22:44 +0100 Subject: [PATCH] udevd: depend on netlink and remove all sequence reorder logic Netlink will never get out-of-order and we just depend on it from now on. Udevsend messages will have no effect if they contain a sequence number (SEQNUM). Thanks to Bastian Blank , for the debugging session which identified a bug where the timeouts are not working if inotify was not available. All the timeout handling is removed now and this issue should be solved. Signed-off-by: Kay Sievers --- Makefile | 1 - udev.h | 2 +- udevd.c | 185 ++++++----------------------------------------------- udevd.h | 9 +-- udevsend.c | 31 +-------- 5 files changed, 23 insertions(+), 205 deletions(-) diff --git a/Makefile b/Makefile index 8d280acd4..afa649e52 100644 --- a/Makefile +++ b/Makefile @@ -270,7 +270,6 @@ udev_version.h: @echo \#define UDEV_CONFIG_DIR \"$(configdir)\" >> $@ @echo \#define UDEV_CONFIG_FILE \"$(configdir)/udev.conf\" >> $@ @echo \#define UDEV_RULES_FILE \"$(configdir)/rules.d\" >> $@ - @echo \#define UDEV_BIN \"$(sbindir)/udev\" >> $@ @echo \#define UDEVD_BIN \"$(sbindir)/udevd\" >> $@ # man pages diff --git a/udev.h b/udev.h index 66edfd66b..ecc0a44f9 100644 --- a/udev.h +++ b/udev.h @@ -36,7 +36,7 @@ #define VALUE_SIZE 128 #define DEFAULT_PARTITIONS_COUNT 15 -#define UDEV_ALARM_TIMEOUT 120 +#define UDEV_ALARM_TIMEOUT 180 struct udev_rules; diff --git a/udevd.c b/udevd.c index 64a6f4d00..dcf578181 100644 --- a/udevd.c +++ b/udevd.c @@ -31,16 +31,14 @@ #include #include #include +#include #include #include -#include #include #include #include -#include #include #include -#include #include #include "list.h" @@ -61,19 +59,14 @@ static pid_t sid; static int signal_pipe[2] = {-1, -1}; static volatile int sigchilds_waiting; -static volatile int run_msg_q; static volatile int udev_exit; static volatile int reload_config; -static int init_phase = 1; static int run_exec_q; static int stop_exec_q; -static int event_timeout; static int max_childs; static int max_childs_running; -static unsigned long long expected_seqnum; static char udev_log[32]; -static LIST_HEAD(msg_list); static LIST_HEAD(exec_list); static LIST_HEAD(running_list); @@ -92,14 +85,11 @@ void log_message(int priority, const char *format, ...) } #endif -static void msg_dump_queue(void) +static void msg_queue_insert(struct uevent_msg *msg) { -#ifdef DEBUG - struct uevent_msg *msg; - - list_for_each_entry(msg, &msg_list, node) - dbg("sequence %llu in queue", msg->seqnum); -#endif + list_add(&msg->node, &exec_list); + msg->queue_time = time(NULL); + run_exec_q = 1; } static void msg_queue_delete(struct uevent_msg *msg) @@ -108,53 +98,6 @@ static void msg_queue_delete(struct uevent_msg *msg) free(msg); } -/* orders the message in the queue by sequence number */ -static void msg_queue_insert(struct uevent_msg *msg) -{ - struct uevent_msg *loop_msg; - struct sysinfo info; - - if (msg->seqnum == 0) { - dbg("no SEQNUM, move straight to the exec queue"); - list_add_tail(&msg->node, &exec_list); - run_exec_q = 1; - return; - } - - /* store timestamp of queuing */ - sysinfo(&info); - msg->queue_time = info.uptime; - - /* with the first event we provide a phase of shorter timeout */ - if (init_phase) { - static long init_time; - - if (init_time == 0) - init_time = info.uptime; - if (info.uptime - init_time >= UDEVD_INIT_TIME) - init_phase = 0; - } - - /* sort message by sequence number into list */ - list_for_each_entry_reverse(loop_msg, &msg_list, node) { - if (loop_msg->seqnum < msg->seqnum) - break; - - if (loop_msg->seqnum == msg->seqnum) { - dbg("ignoring duplicate message seq %llu", msg->seqnum); - free(msg); - return; - } - } - list_add(&msg->node, &loop_msg->node); - info("seq %llu queued, '%s' '%s'", msg->seqnum, msg->action, msg->devpath); - - /* run msg queue manager */ - run_msg_q = 1; - - return; -} - static void asmlinkage udev_event_sig_handler(int signum) { if (signum == SIGALRM) @@ -205,7 +148,6 @@ static int udev_event_process(struct uevent_msg *msg) static void udev_event_run(struct uevent_msg *msg) { pid_t pid; - struct sysinfo info; pid = fork(); switch (pid) { @@ -232,9 +174,8 @@ static void udev_event_run(struct uevent_msg *msg) break; default: /* get SIGCHLD in main loop */ - sysinfo(&info); info("seq %llu forked, pid [%d], '%s' '%s', %ld seconds old", - msg->seqnum, pid, msg->action, msg->subsystem, info.uptime - msg->queue_time); + msg->seqnum, pid, msg->action, msg->subsystem, time(NULL) - msg->queue_time); msg->pid = pid; } } @@ -436,61 +377,6 @@ static void exec_queue_manager(void) } } -static void msg_move_exec(struct uevent_msg *msg) -{ - list_move_tail(&msg->node, &exec_list); - run_exec_q = 1; - expected_seqnum = msg->seqnum+1; - dbg("moved seq %llu to exec, next expected is %llu", - msg->seqnum, expected_seqnum); -} - -/* msg queue management routine handles the timeouts and dispatches the events */ -static void msg_queue_manager(void) -{ - struct uevent_msg *loop_msg; - struct uevent_msg *tmp_msg; - struct sysinfo info; - long msg_age = 0; - int timeout = event_timeout; - - dbg("msg queue manager, next expected is %llu", expected_seqnum); -recheck: - sysinfo(&info); - list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, node) { - /* move event with expected sequence to the exec list */ - if (loop_msg->seqnum == expected_seqnum) { - msg_move_exec(loop_msg); - continue; - } - - /* limit timeout during initialization phase */ - if (init_phase) { - if (timeout > UDEVD_INIT_EVENT_TIMEOUT) - timeout = UDEVD_INIT_EVENT_TIMEOUT; - dbg("initialization phase, timeout %i seconds", timeout); - } - - /* move event with expired timeout to the exec list */ - msg_age = info.uptime - loop_msg->queue_time; - dbg("seq %llu is %li seconds old", loop_msg->seqnum, msg_age); - if (msg_age >= timeout) { - msg_move_exec(loop_msg); - goto recheck; - } else - break; - } - - msg_dump_queue(); - - /* set timeout for remaining queued events */ - if (!list_empty(&msg_list)) { - struct itimerval itv = {{0, 0}, {timeout - msg_age, 0}}; - info("next event expires in %li seconds", timeout - msg_age); - setitimer(ITIMER_REAL, &itv, NULL); - } -} - static struct uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size) { int bufpos; @@ -691,10 +577,6 @@ static void asmlinkage sig_handler(int signum) case SIGTERM: udev_exit = 1; break; - case SIGALRM: - /* set flag, then write to pipe if needed */ - run_msg_q = 1; - break; case SIGCHLD: /* set flag, then write to pipe if needed */ sigchilds_waiting = 1; @@ -712,13 +594,11 @@ static void udev_done(int pid) { /* find msg associated with pid and delete it */ struct uevent_msg *msg; - struct sysinfo info; list_for_each_entry(msg, &running_list, node) { if (msg->pid == pid) { - sysinfo(&info); if (msg->queue_time) - info("seq %llu, pid [%d] exit, %ld seconds old", msg->seqnum, msg->pid, info.uptime - msg->queue_time); + info("seq %llu, pid [%d] exit, %ld seconds old", msg->seqnum, msg->pid, time(NULL) - msg->queue_time); else info("seq 0, pid [%d] exit", msg->pid); msg_queue_delete(msg); @@ -818,10 +698,10 @@ int main(int argc, char *argv[], char *envp[]) struct sigaction act; fd_set readfds; const char *value; - int uevent_netlink_active = 0; int daemonize = 0; int i; int rc = 0; + int maxfd; /* redirect std fd's, if the kernel forks us, we don't have them at all */ fd = open("/dev/null", O_RDWR); @@ -943,7 +823,6 @@ int main(int argc, char *argv[], char *envp[]) act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); - sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); sigaction(SIGHUP, &act, NULL); @@ -952,21 +831,6 @@ int main(int argc, char *argv[], char *envp[]) if (inotify_fd > 0) inotify_add_watch(inotify_fd, udev_rules_filename, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); - /* init of expected_seqnum value */ - value = getenv("UDEVD_EXPECTED_SEQNUM"); - if (value) { - expected_seqnum = strtoull(value, NULL, 10); - info("initialize expected_seqnum to %llu", expected_seqnum); - } - - /* timeout to wait for missing events */ - value = getenv("UDEVD_EVENT_TIMEOUT"); - if (value) - event_timeout = strtoul(value, NULL, 10); - else - event_timeout = UDEVD_EVENT_TIMEOUT; - info("initialize event_timeout to %u", event_timeout); - /* maximum limit of forked childs */ value = getenv("UDEVD_MAX_CHILDS"); if (value) @@ -990,6 +854,11 @@ int main(int argc, char *argv[], char *envp[]) sprintf(udev_log, "UDEV_LOG=%i", udev_log_priority); putenv(udev_log); + maxfd = udevd_sock; + maxfd = UDEV_MAX(maxfd, uevent_netlink_sock); + maxfd = UDEV_MAX(maxfd, signal_pipe[READ_END]); + maxfd = UDEV_MAX(maxfd, inotify_fd); + while (!udev_exit) { struct uevent_msg *msg; int fdcount; @@ -1001,7 +870,7 @@ int main(int argc, char *argv[], char *envp[]) if (inotify_fd > 0) FD_SET(inotify_fd, &readfds); - fdcount = select(UDEV_MAX(uevent_netlink_sock, inotify_fd)+1, &readfds, NULL, NULL, NULL); + fdcount = select(maxfd+1, &readfds, NULL, NULL, NULL); if (fdcount < 0) { if (errno != EINTR) dbg("error in select: %s", strerror(errno)); @@ -1012,9 +881,8 @@ int main(int argc, char *argv[], char *envp[]) if (FD_ISSET(udevd_sock, &readfds)) { msg = get_udevd_msg(); if (msg) { - /* discard kernel messages if netlink is active */ - if (uevent_netlink_active && msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) { - info("skip uevent_helper message with SEQNUM, netlink is active"); + if (msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) { + info("skip non-kernel message with SEQNUM"); free(msg); } else msg_queue_insert(msg); @@ -1024,14 +892,8 @@ int main(int argc, char *argv[], char *envp[]) /* get kernel netlink message */ if (FD_ISSET(uevent_netlink_sock, &readfds)) { msg = get_netlink_msg(); - if (msg) { + if (msg) msg_queue_insert(msg); - /* disable udevsend with first netlink message */ - if (!uevent_netlink_active) { - info("uevent_nl message received, disable udevsend messages"); - uevent_netlink_active = 1; - } - } } /* received a signal, clear our notification pipe */ @@ -1068,24 +930,13 @@ int main(int argc, char *argv[], char *envp[]) udev_rules_init(&rules, 1); } - /* forked child have returned */ + /* forked child has returned */ if (sigchilds_waiting) { sigchilds_waiting = 0; reap_sigchilds(); } - if (run_msg_q) { - run_msg_q = 0; - msg_queue_manager(); - } - if (run_exec_q) { - /* clean up running_list before calling exec_queue_manager() */ - if (sigchilds_waiting) { - sigchilds_waiting = 0; - reap_sigchilds(); - } - run_exec_q = 0; if (!stop_exec_q) exec_queue_manager(); diff --git a/udevd.h b/udevd.h index db510ab24..884c4b007 100644 --- a/udevd.h +++ b/udevd.h @@ -29,13 +29,6 @@ #define UDEVD_PRIORITY -4 #define UDEV_PRIORITY -2 -/* duration of initialization phase with shorter timeout */ -#define UDEVD_INIT_TIME 5 -#define UDEVD_INIT_EVENT_TIMEOUT 2 - -/* timeout to wait for missing events */ -#define UDEVD_EVENT_TIMEOUT 5 - /* maximum limit of runnig childs */ #define UDEVD_MAX_CHILDS 64 /* start to throttle forking if maximum number of running childs in our session is reached */ @@ -68,7 +61,7 @@ struct uevent_msg { enum udevd_msg_type type; struct list_head node; pid_t pid; - long queue_time; + time_t queue_time; char *action; char *devpath; char *subsystem; diff --git a/udevsend.c b/udevsend.c index 0ba1b58a4..29d5bc155 100644 --- a/udevsend.c +++ b/udevsend.c @@ -89,27 +89,6 @@ static int start_daemon(void) return 0; } -static void run_udev(const char *subsystem) -{ - char *const argv[] = { "udev", (char *)subsystem, NULL }; - pid_t pid; - - pid = fork(); - switch (pid) { - case 0: - /* child */ - execv(UDEV_BIN, argv); - err("exec of udev child failed"); - _exit(1); - break; - case -1: - err("fork of udev child failed"); - break; - default: - waitpid(pid, NULL, 0); - } -} - int main(int argc, char *argv[], char *envp[]) { static struct udevd_msg usend_msg; @@ -132,7 +111,7 @@ int main(int argc, char *argv[], char *envp[]) sock = socket(AF_LOCAL, SOCK_DGRAM, 0); if (sock == -1) { err("error getting socket"); - goto fallback; + goto exit; } memset(&saddr, 0x00, sizeof(struct sockaddr_un)); @@ -192,7 +171,7 @@ int main(int argc, char *argv[], char *envp[]) if (errno != ECONNREFUSED) { err("error sending message (%s)", strerror(errno)); - goto fallback; + goto exit; } if (!started_daemon) { @@ -200,7 +179,7 @@ int main(int argc, char *argv[], char *envp[]) retval = start_daemon(); if (retval) { dbg("error starting daemon"); - goto fallback; + goto exit; } dbg("udevd daemon started"); started_daemon = 1; @@ -210,10 +189,6 @@ int main(int argc, char *argv[], char *envp[]) } } -fallback: - err("unable to connect to event daemon, try to call udev directly"); - run_udev(subsystem); - exit: if (sock != -1) close(sock); -- 2.30.2