#include "sd-event.h"
#include "alloc-util.h"
-#include "build.h"
#include "cgroup-util.h"
#include "cpu-set-util.h"
#include "dev-setup.h"
#include "udev-util.h"
#include "udev-watch.h"
#include "user-util.h"
+#include "version.h"
#define WORKER_NUM_MAX 2048U
sd_device_monitor *monitor;
struct udev_ctrl *ctrl;
- int fd_inotify;
int worker_watch[2];
+ /* used by udev-watch */
+ int inotify_fd;
sd_event_source *inotify_event;
+
sd_event_source *kill_workers_event;
usec_t last_usec;
WORKER_RUNNING,
WORKER_IDLE,
WORKER_KILLED,
+ WORKER_KILLING,
};
struct worker {
hashmap_free_free_free(manager->properties);
udev_rules_free(manager->rules);
- safe_close(manager->fd_inotify);
+ safe_close(manager->inotify_fd);
safe_close_pair(manager->worker_watch);
return mfree(manager);
* degree — they go hand-in-hand after all. */
log_device_debug(dev, "Block device is currently locked, installing watch to wait until the lock is released.");
- (void) udev_watch_begin(dev);
+ (void) udev_watch_begin(manager->inotify_fd, dev);
/* Now the watch is installed, let's lock the device again, maybe in the meantime things changed */
r = worker_lock_block_device(dev, &fd_lock);
(void) worker_mark_block_device_read_only(dev);
/* apply rules, create node, symlinks */
- r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules);
+ r = udev_event_execute_rules(
+ udev_event,
+ manager->inotify_fd,
+ arg_event_timeout_usec,
+ arg_timeout_signal,
+ manager->properties,
+ manager->rules);
if (r < 0)
return r;
/* in case rtnl was initialized */
manager->rtnl = sd_netlink_ref(udev_event->rtnl);
- /* apply/restore/end inotify watch */
- if (udev_event->inotify_watch) {
- (void) udev_watch_begin(dev);
- r = device_update_db(dev);
- if (r < 0)
- return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m");
- } else
- (void) udev_watch_end(dev);
+ r = udev_event_process_inotify_watch(udev_event, manager->inotify_fd);
+ if (r < 0)
+ return r;
log_device_uevent(dev, "Device processed");
return 0;
if (r < 0)
log_debug_errno(r, "Failed to reset OOM score, ignoring: %m");
- /* Clear unnecessary data in Manager object.*/
+ /* Clear unnecessary data in Manager object. */
manager_clear_for_worker(manager);
r = sd_event_new(&manager->event);
return log_error_errno(r, "Failed to fork() worker: %m");
}
if (r == 0) {
+ DEVICE_TRACE_POINT(worker_spawned, event->dev, getpid());
+
/* Worker process */
r = worker_main(manager, worker_monitor, sd_device_ref(event->dev));
log_close();
return 0;
}
-static void manager_kill_workers(Manager *manager) {
+static void manager_kill_workers(Manager *manager, bool force) {
struct worker *worker;
assert(manager);
if (worker->state == WORKER_KILLED)
continue;
+ if (worker->state == WORKER_RUNNING && !force) {
+ worker->state = WORKER_KILLING;
+ continue;
+ }
+
worker->state = WORKER_KILLED;
(void) kill(worker->pid, SIGTERM);
}
manager->ctrl = udev_ctrl_unref(manager->ctrl);
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
- manager->fd_inotify = safe_close(manager->fd_inotify);
+ manager->inotify_fd = safe_close(manager->inotify_fd);
manager->monitor = sd_device_monitor_unref(manager->monitor);
/* discard queued events and kill workers */
event_queue_cleanup(manager, EVENT_QUEUED);
- manager_kill_workers(manager);
+ manager_kill_workers(manager, true);
}
/* reload requested, HUP signal received, rules changed, builtin changed */
"RELOADING=1\n"
"STATUS=Flushing configuration...");
- manager_kill_workers(manager);
+ manager_kill_workers(manager, false);
manager->rules = udev_rules_free(manager->rules);
udev_builtin_exit();
assert(manager);
log_debug("Cleanup idle workers");
- manager_kill_workers(manager);
+ manager_kill_workers(manager, false);
return 1;
}
continue;
}
- if (worker->state != WORKER_KILLED)
+ if (worker->state == WORKER_KILLING) {
+ worker->state = WORKER_KILLED;
+ (void) kill(worker->pid, SIGTERM);
+ } else if (worker->state != WORKER_KILLED)
worker->state = WORKER_IDLE;
/* worker returned */
assert(manager);
+ DEVICE_TRACE_POINT(kernel_uevent_received, dev);
+
device_ensure_usec_initialized(dev, NULL);
r = event_queue_insert(manager, dev);
log_debug("Received udev control message (SET_LOG_LEVEL), setting log_level=%i", value->intval);
log_set_max_level(value->intval);
manager->log_level = value->intval;
- manager_kill_workers(manager);
+ manager_kill_workers(manager, false);
break;
case UDEV_CTRL_STOP_EXEC_QUEUE:
log_debug("Received udev control message (STOP_EXEC_QUEUE)");
}
key = val = NULL;
- manager_kill_workers(manager);
+ manager_kill_workers(manager, false);
break;
}
case UDEV_CTRL_SET_CHILDREN_MAX:
if (r < 0)
return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m");
+ DEVICE_TRACE_POINT(synthetic_change_event, dev);
+
return 0;
}
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
const char *devnode;
- if (udev_watch_lookup(e->wd, &dev) <= 0)
+ r = device_new_from_watch_handle(&dev, e->wd);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m");
continue;
+ }
if (sd_device_get_devname(dev, &devnode) < 0)
continue;
log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode);
if (e->mask & IN_CLOSE_WRITE)
- synthesize_change(dev);
- else if (e->mask & IN_IGNORED)
- udev_watch_end(dev);
+ (void) synthesize_change(dev);
+
+ /* Do not handle IN_IGNORED here. It should be handled by worker in 'remove' uevent;
+ * udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */
}
return 1;
return log_oom();
*manager = (Manager) {
- .fd_inotify = -1,
+ .inotify_fd = -1,
.worker_watch = { -1, -1 },
.cgroup = cgroup,
};
if (r < 0)
return log_error_errno(r, "Failed to enable SO_PASSCRED: %m");
- r = udev_watch_init();
- if (r < 0)
- return log_error_errno(r, "Failed to create inotify descriptor: %m");
- manager->fd_inotify = r;
+ manager->inotify_fd = inotify_init1(IN_CLOEXEC);
+ if (manager->inotify_fd < 0)
+ return log_error_errno(errno, "Failed to create inotify descriptor: %m");
- udev_watch_restore();
+ udev_watch_restore(manager->inotify_fd);
/* block and listen to all signals on signalfd */
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
if (r < 0)
return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m");
- r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
+ r = sd_event_add_io(manager->event, &manager->inotify_event, manager->inotify_fd, EPOLLIN, on_inotify, manager);
if (r < 0)
return log_error_errno(r, "Failed to create inotify event source: %m");