Merge pull request #24520 from yuwata/udevadm-wait-listen-kernel-uevents
udevadm-wait: also listen kernel uevents
This commit is contained in:
+49
-38
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chase-symlinks.h"
|
||||
#include "device-monitor-private.h"
|
||||
#include "device-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "event-util.h"
|
||||
@@ -165,28 +166,21 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
|
||||
if (path_strv_contains(arg_devices, name))
|
||||
return check_and_exit(sd_device_monitor_get_event(monitor));
|
||||
|
||||
STRV_FOREACH(p, arg_devices) {
|
||||
const char *link;
|
||||
|
||||
if (!path_startswith(*p, "/dev"))
|
||||
continue;
|
||||
|
||||
FOREACH_DEVICE_DEVLINK(device, link)
|
||||
if (path_equal(*p, link))
|
||||
return check_and_exit(sd_device_monitor_get_event(monitor));
|
||||
}
|
||||
FOREACH_DEVICE_DEVLINK(device, name)
|
||||
if (path_strv_contains(arg_devices, name))
|
||||
return check_and_exit(sd_device_monitor_get_event(monitor));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_monitor(sd_event *event, sd_device_monitor **ret) {
|
||||
static int setup_monitor(sd_event *event, MonitorNetlinkGroup group, const char *description, sd_device_monitor **ret) {
|
||||
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
||||
int r;
|
||||
|
||||
assert(event);
|
||||
assert(ret);
|
||||
|
||||
r = sd_device_monitor_new(&monitor);
|
||||
r = device_monitor_new_full(&monitor, group, /* fd = */ -1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -196,12 +190,11 @@ static int setup_monitor(sd_event *event, sd_device_monitor **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_monitor_start(monitor, device_monitor_handler, NULL);
|
||||
r = sd_device_monitor_set_description(monitor, description);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_description(sd_device_monitor_get_event_source(monitor),
|
||||
"device-monitor-event-source");
|
||||
r = sd_device_monitor_start(monitor, device_monitor_handler, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -257,6 +250,7 @@ static int setup_timer(sd_event *event) {
|
||||
static int reset_timer(sd_event *e, sd_event_source **s);
|
||||
|
||||
static int on_periodic_timer(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
static unsigned counter = 0;
|
||||
sd_event *e;
|
||||
int r;
|
||||
|
||||
@@ -264,9 +258,16 @@ static int on_periodic_timer(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
|
||||
e = sd_event_source_get_event(s);
|
||||
|
||||
r = check_and_exit(e);
|
||||
if (r != 0)
|
||||
return r;
|
||||
/* Even if all devices exists, we try to wait for uevents to be emitted from kernel. */
|
||||
if (check())
|
||||
counter++;
|
||||
else
|
||||
counter = 0;
|
||||
|
||||
if (counter >= 2) {
|
||||
log_debug("All requested devices popped up without receiving kernel uevents.");
|
||||
return sd_event_exit(e, 0);
|
||||
}
|
||||
|
||||
r = reset_timer(e, &s);
|
||||
if (r < 0)
|
||||
@@ -286,24 +287,15 @@ static int setup_periodic_timer(sd_event *event) {
|
||||
|
||||
assert(event);
|
||||
|
||||
/* If --initialized=no is specified, it is not necessary to wait uevents for the specified devices to
|
||||
* be processed by udevd. Let's periodically check the devices. Then, we may be able to finish this
|
||||
* program earlier when udevd is very busy.
|
||||
*
|
||||
* This is useful for working around issues #24360 and #24450.
|
||||
* For some reasons, the kernel sometimes does not emit uevents for loop block device on attach.
|
||||
* Hence, without the periodic timer, no event source for this program will be triggered, and this
|
||||
* will be timed out.
|
||||
* Theoretically, inotify watch may be better, but this program typically expected to run in a short
|
||||
* time. Hence, let's use the simpler periodic timer event source here. */
|
||||
|
||||
if (arg_wait_until != WAIT_UNTIL_ADDED)
|
||||
return 0;
|
||||
|
||||
r = reset_timer(event, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Set the lower priority than device monitor, to make uevents always dispatched first. */
|
||||
r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_NORMAL + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_floating(s, true);
|
||||
}
|
||||
|
||||
@@ -388,7 +380,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
int wait_main(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
||||
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *udev_monitor = NULL, *kernel_monitor = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
int r;
|
||||
|
||||
@@ -424,13 +416,32 @@ int wait_main(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up inotify: %m");
|
||||
|
||||
r = setup_monitor(event, &monitor);
|
||||
r = setup_monitor(event, MONITOR_GROUP_UDEV, "udev-uevent-monitor-event-source", &udev_monitor);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up device monitor: %m");
|
||||
return log_error_errno(r, "Failed to set up udev uevent monitor: %m");
|
||||
|
||||
r = setup_periodic_timer(event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up periodic timer: %m");
|
||||
if (arg_wait_until == WAIT_UNTIL_ADDED) {
|
||||
/* If --initialized=no is specified, it is not necessary to wait uevents for the specified
|
||||
* devices to be processed by udevd. Hence, let's listen on the kernel's uevent stream. Then,
|
||||
* we may be able to finish this program earlier when udevd is very busy.
|
||||
* Note, we still need to also setup udev monitor, as this may be invoked with a devlink
|
||||
* (e.g. /dev/disk/by-id/foo). In that case, the devlink may not exist when we received a
|
||||
* uevent from kernel, as the udevd may not finish to process the uevent yet. Hence, we need
|
||||
* to wait until the event is processed by udevd. */
|
||||
r = setup_monitor(event, MONITOR_GROUP_KERNEL, "kernel-uevent-monitor-event-source", &kernel_monitor);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up kernel uevent monitor: %m");
|
||||
|
||||
/* This is a workaround for issues #24360 and #24450.
|
||||
* For some reasons, the kernel sometimes does not emit uevents for loop block device on
|
||||
* attach. Hence, without the periodic timer, no event source for this program will be
|
||||
* triggered, and this will be timed out.
|
||||
* Theoretically, inotify watch may be better, but this program typically expected to run in
|
||||
* a short time. Hence, let's use the simpler periodic timer event source here. */
|
||||
r = setup_periodic_timer(event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up periodic timer: %m");
|
||||
}
|
||||
|
||||
/* Check before entering the event loop, as devices may be initialized during setting up event sources. */
|
||||
if (check())
|
||||
|
||||
Reference in New Issue
Block a user