]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udevadm-wait: also listen kernel uevent stream if --initialized=no
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 31 Aug 2022 15:32:27 +0000 (00:32 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 Sep 2022 21:09:42 +0000 (06:09 +0900)
Suggested at https://github.com/systemd/systemd/pull/24471#discussion_r959703103.

src/udev/udevadm-wait.c

index bebf9b6bae1fa035d01c6c8632c1dea760890c18..f0c28a7905a0e414691ae6c94e8d8da3d40686bb 100644 (file)
@@ -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"
@@ -179,14 +180,14 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
         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 +197,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;
 
@@ -374,7 +374,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;
 
@@ -410,16 +410,23 @@ 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");
 
         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. 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.
+                 * 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.