]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect: retrigger devices if we missed uevents
authorLennart Poettering <lennart@poettering.net>
Wed, 14 Oct 2020 08:52:05 +0000 (10:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 22 Oct 2020 12:58:28 +0000 (14:58 +0200)
On systems that have a udev before
a7fdc6cbd399acdb1a975a7f72b9be4504a38c7c uevents would sometimes be
eaten because of device node collisions that caused the ruleset to fail.
Let's add an (ugly) work-around for this, so that we can even work with
such an older udev.

src/shared/dissect-image.c

index 2721718381361cfed4cdf22ab319ae14bc5bff0b..1820b81e11b2794a9a571c9b0fd434c9bbf345ce 100644 (file)
@@ -368,6 +368,86 @@ static void check_partition_flags(
         }
 }
 
+static int device_wait_for_initialization_harder(
+                sd_device *device,
+                const char *subsystem,
+                usec_t deadline,
+                sd_device **ret) {
+
+        _cleanup_free_ char *uevent = NULL;
+        usec_t start, left, retrigger_timeout;
+        int r;
+
+        start = now(CLOCK_MONOTONIC);
+        left = usec_sub_unsigned(deadline, start);
+
+        if (DEBUG_LOGGING) {
+                char buf[FORMAT_TIMESPAN_MAX];
+                const char *sn = NULL;
+
+                (void) sd_device_get_sysname(device, &sn);
+                log_debug("Waiting for device '%s' to initialize for %s.", strna(sn), format_timespan(buf, sizeof(buf), left, 0));
+        }
+
+        if (left != USEC_INFINITY)
+                retrigger_timeout = CLAMP(left / 4, 1 * USEC_PER_SEC, 5 * USEC_PER_SEC); /* A fourth of the total timeout, but let's clamp to 1s…5s range */
+        else
+                retrigger_timeout = 2 * USEC_PER_SEC;
+
+        for (;;) {
+                usec_t local_deadline, n;
+                bool last_try;
+
+                n = now(CLOCK_MONOTONIC);
+                assert(n >= start);
+
+                /* Find next deadline, when we'll retrigger */
+                local_deadline = start +
+                        DIV_ROUND_UP(n - start, retrigger_timeout) * retrigger_timeout;
+
+                if (deadline != USEC_INFINITY && deadline <= local_deadline) {
+                        local_deadline = deadline;
+                        last_try = true;
+                } else
+                        last_try = false;
+
+                r = device_wait_for_initialization(device, subsystem, local_deadline, ret);
+                if (r >= 0 && DEBUG_LOGGING) {
+                        char buf[FORMAT_TIMESPAN_MAX];
+                        const char *sn = NULL;
+
+                        (void) sd_device_get_sysname(device, &sn);
+                        log_debug("Successfully waited for device '%s' to initialize for %s.", strna(sn), format_timespan(buf, sizeof(buf), usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
+
+                }
+                if (r != -ETIMEDOUT || last_try)
+                        return r;
+
+                if (!uevent) {
+                        const char *syspath;
+
+                        r = sd_device_get_syspath(device, &syspath);
+                        if (r < 0)
+                                return r;
+
+                        uevent = path_join(syspath, "uevent");
+                        if (!uevent)
+                                return -ENOMEM;
+                }
+
+                if (DEBUG_LOGGING) {
+                        char buf[FORMAT_TIMESPAN_MAX];
+
+                        log_debug("Device didn't initialize within %s, assuming lost event. Retriggering device through %s.",
+                                  format_timespan(buf, sizeof(buf), usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0),
+                                  uevent);
+                }
+
+                r = write_string_file(uevent, "change", WRITE_STRING_FILE_DISABLE_BUFFER);
+                if (r < 0)
+                        return r;
+        }
+}
 #endif
 
 #define DEVICE_TIMEOUT_USEC (45 * USEC_PER_SEC)
@@ -448,7 +528,11 @@ int dissect_image(
 
                 /* If udev support is enabled, then let's wait for the device to be initialized before we doing anything. */
 
-                r = device_wait_for_initialization(d, "block", DEVICE_TIMEOUT_USEC, &initialized);
+                r = device_wait_for_initialization_harder(
+                                d,
+                                "block",
+                                usec_add(now(CLOCK_MONOTONIC), DEVICE_TIMEOUT_USEC),
+                                &initialized);
                 if (r < 0)
                         return r;