X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fudev%2Fudevd.c;h=b69f3f87de90a12625bfeb7674651d5f78b5e46b;hp=790531022c08d3e7d8186463d6c5218b0800b4aa;hb=40fe8b11be9c1a1b38b91db097a5d6ebfa99304c;hpb=0f9963a8b8c1d60a467c0cdc04d5e7bfce9d7c75 diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 790531022..b69f3f87d 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -95,8 +95,9 @@ struct event { size_t devpath_len; const char *devpath_old; dev_t devnum; - bool is_block; int ifindex; + bool is_block; + bool nodelay; }; static inline struct event *node_to_event(struct udev_list_node *node) @@ -121,7 +122,7 @@ struct worker { struct udev_monitor *monitor; enum worker_state state; struct event *event; - unsigned long long event_start_usec; + usec_t event_start_usec; }; /* passed from worker to main process */ @@ -262,6 +263,9 @@ static void worker_new(struct event *event) /* request TERM signal if parent exits */ prctl(PR_SET_PDEATHSIG, SIGTERM); + /* reset OOM score, we only protect the main daemon */ + write_one_line_file("/proc/self/oom_score_adj", "0"); + for (;;) { struct udev_event *udev_event; struct worker_message msg; @@ -374,7 +378,7 @@ out: worker->monitor = worker_monitor; worker->pid = pid; worker->state = WORKER_RUNNING; - worker->event_start_usec = now_usec(); + worker->event_start_usec = now(CLOCK_MONOTONIC); worker->event = event; event->state = EVENT_RUNNING; udev_list_node_append(&worker->node, &worker_list); @@ -405,7 +409,7 @@ static void event_run(struct event *event) worker_ref(worker); worker->event = event; worker->state = WORKER_RUNNING; - worker->event_start_usec = now_usec(); + worker->event_start_usec = now(CLOCK_MONOTONIC); event->state = EVENT_RUNNING; return; } @@ -435,8 +439,10 @@ static int event_queue_insert(struct udev_device *dev) event->devpath_len = strlen(event->devpath); event->devpath_old = udev_device_get_devpath_old(dev); event->devnum = udev_device_get_devnum(dev); - event->is_block = (strcmp("block", udev_device_get_subsystem(dev)) == 0); + event->is_block = streq("block", udev_device_get_subsystem(dev)); event->ifindex = udev_device_get_ifindex(dev); + if (streq(udev_device_get_subsystem(dev), "firmware")) + event->nodelay = true; udev_queue_export_device_queued(udev_queue_export, dev); log_debug("seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(dev), @@ -516,6 +522,10 @@ static bool is_devpath_busy(struct event *event) return true; } + /* allow to bypass the dependency tracking */ + if (event->nodelay) + continue; + /* parent device event found */ if (event->devpath[common] == '/') { event->delaying_seqnum = loop_event->seqnum; @@ -803,8 +813,8 @@ static void static_dev_create_from_modules(struct udev *udev) FILE *f; uname(&kernel); - util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL); - f = fopen(modules, "r"); + util_strscpyl(modules, sizeof(modules), ROOTPREFIX "/lib/modules/", kernel.release, "/modules.devname", NULL); + f = fopen(modules, "re"); if (f == NULL) return; @@ -842,10 +852,11 @@ static void static_dev_create_from_modules(struct udev *udev) if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3) continue; + mode = 0600; if (type == 'c') - mode = S_IFCHR; + mode |= S_IFCHR; else if (type == 'b') - mode = S_IFBLK; + mode |= S_IFBLK; else continue; @@ -867,7 +878,7 @@ static int mem_size_mb(void) char buf[4096]; long int memsize = -1; - f = fopen("/proc/meminfo", "r"); + f = fopen("/proc/meminfo", "re"); if (f == NULL) return -1; @@ -887,7 +898,6 @@ static int mem_size_mb(void) static int convert_db(struct udev *udev) { char filename[UTIL_PATH_SIZE]; - FILE *f; struct udev_enumerate *udev_enumerate; struct udev_list_entry *list_entry; @@ -896,19 +906,14 @@ static int convert_db(struct udev *udev) return 0; /* make sure we do not get here again */ - mkdir_parents("/run/udev/data", 0755); - mkdir(filename, 0755); + mkdir_p("/run/udev/data", 0755); /* old database */ util_strscpyl(filename, sizeof(filename), "/dev/.udev/db", NULL); if (access(filename, F_OK) < 0) return 0; - f = fopen("/dev/kmsg", "w"); - if (f != NULL) { - fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid()); - fclose(f); - } + print_kmsg("converting old udev database\n"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) @@ -1010,10 +1015,54 @@ static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) return 0; } +/* + * read the kernel commandline, in case we need to get into debug mode + * udev.log-priority= syslog priority + * udev.children-max= events are fully serialized if set to 1 + * udev.exec-delay= delay execution of every executed program + */ +static void kernel_cmdline_options(struct udev *udev) +{ + char *line, *w, *state; + size_t l; + + if (read_one_line_file("/proc/cmdline", &line) < 0) + return; + + FOREACH_WORD_QUOTED(w, l, line, state) { + char *s, *opt; + + s = strndup(w, l); + if (!s) + break; + + /* accept the same options for the initrd, prefixed with "rd." */ + if (in_initrd() && startswith(s, "rd.")) + opt = s + 3; + else + opt = s; + + if (startswith(opt, "udev.log-priority=")) { + int prio; + + prio = util_log_priority(opt + 18); + log_set_max_level(prio); + udev_set_log_priority(udev, prio); + } else if (startswith(opt, "udev.children-max=")) { + children_max = strtoul(opt + 18, NULL, 0); + } else if (startswith(opt, "udev.exec-delay=")) { + exec_delay = strtoul(opt + 16, NULL, 0); + } + + free(s); + } + + free(line); +} + int main(int argc, char *argv[]) { struct udev *udev; - FILE *f; sigset_t mask; int daemonize = false; int resolve_names = 1; @@ -1038,8 +1087,9 @@ int main(int argc, char *argv[]) if (udev == NULL) goto exit; - log_open(); + log_set_target(LOG_TARGET_AUTO); log_parse_environment(); + log_open(); udev_set_log_fn(udev, udev_main_log); log_debug("version %s\n", VERSION); label_init("/dev"); @@ -1064,7 +1114,7 @@ int main(int argc, char *argv[]) case 'D': debug = true; log_set_max_level(LOG_DEBUG); - udev_set_log_priority(udev, LOG_INFO); + udev_set_log_priority(udev, LOG_DEBUG); break; case 'N': if (strcmp (optarg, "early") == 0) { @@ -1098,39 +1148,7 @@ int main(int argc, char *argv[]) } } - /* - * read the kernel commandline, in case we need to get into debug mode - * udev.log-priority= syslog priority - * udev.children-max= events are fully serialized if set to 1 - * - */ - f = fopen("/proc/cmdline", "r"); - if (f != NULL) { - char cmdline[4096]; - - if (fgets(cmdline, sizeof(cmdline), f) != NULL) { - char *pos; - - pos = strstr(cmdline, "udev.log-priority="); - if (pos != NULL) { - pos += strlen("udev.log-priority="); - udev_set_log_priority(udev, util_log_priority(pos)); - } - - pos = strstr(cmdline, "udev.children-max="); - if (pos != NULL) { - pos += strlen("udev.children-max="); - children_max = strtoul(pos, NULL, 0); - } - - pos = strstr(cmdline, "udev.exec-delay="); - if (pos != NULL) { - pos += strlen("udev.exec-delay="); - exec_delay = strtoul(pos, NULL, 0); - } - } - fclose(f); - } + kernel_cmdline_options(udev); if (getuid() != 0) { fprintf(stderr, "root privileges required\n"); @@ -1144,7 +1162,7 @@ int main(int argc, char *argv[]) mkdir("/run/udev", 0755); - dev_setup(); + dev_setup(NULL); static_dev_create_from_modules(udev); /* before opening new files, make sure std{in,out,err} fds are in a sane state */ @@ -1166,7 +1184,7 @@ int main(int argc, char *argv[]) } if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) { - /* get control and netlink socket from from systemd */ + /* get control and netlink socket from systemd */ udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl); if (udev_ctrl == NULL) { log_error("error taking over udev control socket"); @@ -1230,7 +1248,6 @@ int main(int argc, char *argv[]) if (daemonize) { pid_t pid; - int fd; pid = fork(); switch (pid) { @@ -1247,20 +1264,12 @@ int main(int argc, char *argv[]) setsid(); - fd = open("/proc/self/oom_score_adj", O_RDWR|O_CLOEXEC); - if (fd >= 0) { - write(fd, "-1000", 5); - close(fd); - } + write_one_line_file("/proc/self/oom_score_adj", "-1000"); } else { sd_notify(1, "READY=1"); } - f = fopen("/dev/kmsg", "w"); - if (f != NULL) { - fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid()); - fclose(f); - } + print_kmsg("starting version " VERSION "\n"); if (!debug) { int fd; @@ -1353,9 +1362,9 @@ int main(int argc, char *argv[]) /* set value depending on the amount of RAM */ if (memsize > 0) - children_max = 128 + (memsize / 8); + children_max = 16 + (memsize / 8); else - children_max = 128; + children_max = 16; } log_debug("set children_max to %u\n", children_max); @@ -1365,7 +1374,7 @@ int main(int argc, char *argv[]) udev_list_node_init(&worker_list); for (;;) { - static unsigned long long last_usec; + static usec_t last_usec; struct epoll_event ev[8]; int fdcount; int timeout; @@ -1436,7 +1445,7 @@ int main(int argc, char *argv[]) if (worker->state != WORKER_RUNNING) continue; - if ((now_usec() - worker->event_start_usec) > 30 * 1000 * 1000) { + if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > 30 * 1000 * 1000) { log_error("worker [%u] %s timeout; kill it\n", worker->pid, worker->event ? worker->event->devpath : ""); kill(worker->pid, SIGKILL); @@ -1470,13 +1479,13 @@ int main(int argc, char *argv[]) } /* check for changed config, every 3 seconds at most */ - if ((now_usec() - last_usec) > 3 * 1000 * 1000) { + if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * 1000 * 1000) { if (udev_rules_check_timestamp(rules)) reload = true; if (udev_builtin_validate(udev)) reload = true; - last_usec = now_usec(); + last_usec = now(CLOCK_MONOTONIC); } /* reload requested, HUP signal received, rules changed, builtin changed */ @@ -1484,7 +1493,7 @@ int main(int argc, char *argv[]) worker_kill(udev); rules = udev_rules_unref(rules); udev_builtin_exit(udev); - reload = 0; + reload = false; } /* event has finished */ @@ -1496,7 +1505,7 @@ int main(int argc, char *argv[]) dev = udev_monitor_receive_device(monitor); if (dev != NULL) { - udev_device_set_usec_initialized(dev, now_usec()); + udev_device_set_usec_initialized(dev, now(CLOCK_MONOTONIC)); if (event_queue_insert(dev) < 0) udev_device_unref(dev); } @@ -1504,6 +1513,7 @@ int main(int argc, char *argv[]) /* start new events */ if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) { + udev_builtin_init(udev); if (rules == NULL) rules = udev_rules_new(udev, resolve_names); if (rules != NULL)