From 23902d1c843257d23e0b2225e4a015b52b291090 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 27 Aug 2022 15:58:46 +0900 Subject: [PATCH 1/3] Revert "test: wait for loop device to be removed" This reverts commit 1a0e065e9f154f46fd68cd45f46310bc7df7a51c. This does not work as expected. After `losetup --detach`, the kernel lazily removes the loop device. But, systemd-dissect should gracefully handle that. If it does not, then it is a bug in systemd-dissect. Let's not hide the real issue in systemd-dissect. --- test/units/testsuite-50.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh index 0111a3a2e4..42c311be26 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -189,7 +189,6 @@ if [ "${HAVE_OPENSSL}" -eq 1 ]; then sfdisk --part-label "${image}.gpt" 3 "Signature Partition" fi loop="$(losetup --show -P -f "${image}.gpt")" -# kernel sometimes(?) does not emit add uevent for partitions, let's wait for the whole block device. udevadm wait --timeout 60 --settle "${loop:?}" dd if="${image}.raw" of="${loop}p1" dd if="${image}.verity" of="${loop}p2" @@ -197,11 +196,6 @@ if [ "${HAVE_OPENSSL}" -eq 1 ]; then dd if="${image}.verity-sig" of="${loop}p3" fi losetup -d "${loop}" -# Interestingly, kernel does not emit remove uevent for the whole block device, but does for partitions. -udevadm wait --timeout 60 --settle --removed "${loop}p1" "${loop}p2" -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - udevadm wait --timeout 60 --settle --removed "${loop}p3" -fi # Derive partition UUIDs from root hash, in UUID syntax ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)" From 3228f89b8cf475ba3a93feaf3c151ca06fc99eeb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 27 Aug 2022 01:17:46 +0900 Subject: [PATCH 2/3] udevadm-wait: introduce periodic timer for checking devices When --initialized=no is specified, it is not necessary to wait for uevents to be processed by udevd. --- src/udev/udevadm-wait.c | 69 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/udev/udevadm-wait.c b/src/udev/udevadm-wait.c index 29c8ee5cf4..d9692ab86e 100644 --- a/src/udev/udevadm-wait.c +++ b/src/udev/udevadm-wait.c @@ -9,6 +9,7 @@ #include "chase-symlinks.h" #include "device-util.h" #include "errno-util.h" +#include "event-util.h" #include "fd-util.h" #include "fs-util.h" #include "inotify-util.h" @@ -97,10 +98,17 @@ static bool check(void) { } static int check_and_exit(sd_event *event) { + int r; + assert(event); - if (check()) - return sd_event_exit(event, 0); + if (check()) { + r = sd_event_exit(event, 0); + if (r < 0) + return r; + + return 1; + } return 0; } @@ -246,6 +254,59 @@ static int setup_timer(sd_event *event) { return sd_event_source_set_floating(s, true); } +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) { + sd_event *e; + int r; + + assert(s); + + e = sd_event_source_get_event(s); + + r = check_and_exit(e); + if (r != 0) + return r; + + r = reset_timer(e, &s); + if (r < 0) + log_warning_errno(r, "Failed to reset periodic timer event source, ignoring: %m"); + + return 0; +} + +static int reset_timer(sd_event *e, sd_event_source **s) { + return event_reset_time_relative(e, s, CLOCK_BOOTTIME, 250 * USEC_PER_MSEC, 0, + on_periodic_timer, NULL, 0, "periodic-timer-event-source", false); +} + +static int setup_periodic_timer(sd_event *event) { + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + int r; + + 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; + + return sd_event_source_set_floating(s, true); +} + static int help(void) { printf("%s wait [OPTIONS] DEVICE [DEVICE…]\n\n" "Wait for devices or device symlinks being created.\n\n" @@ -367,6 +428,10 @@ int wait_main(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to set up device monitor: %m"); + 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()) return 0; From ba44a5c77cac3460a55d4e8c75900b0c78a94b10 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 27 Aug 2022 16:13:27 +0900 Subject: [PATCH 3/3] test-50-dissect: wait for and lock loop block partition devices --- test/units/testsuite-50.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh index 42c311be26..e4204fcdc2 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -189,11 +189,20 @@ if [ "${HAVE_OPENSSL}" -eq 1 ]; then sfdisk --part-label "${image}.gpt" 3 "Signature Partition" fi loop="$(losetup --show -P -f "${image}.gpt")" -udevadm wait --timeout 60 --settle "${loop:?}" -dd if="${image}.raw" of="${loop}p1" -dd if="${image}.verity" of="${loop}p2" +partitions=( + "${loop:?}p1" + "${loop:?}p2" +) if [ "${HAVE_OPENSSL}" -eq 1 ]; then - dd if="${image}.verity-sig" of="${loop}p3" + partitions+=( "${loop:?}p3" ) +fi +# The kernel sometimes(?) does not emit "add" uevent for loop block partition devices. +# Let's not expect the devices to be initialized. +udevadm wait --timeout 60 --settle --initialized=no "${partitions[@]}" +udevadm lock --device="${loop}p1" dd if="${image}.raw" of="${loop}p1" +udevadm lock --device="${loop}p2" dd if="${image}.verity" of="${loop}p2" +if [ "${HAVE_OPENSSL}" -eq 1 ]; then + udevadm lock --device="${loop}p3" dd if="${image}.verity-sig" of="${loop}p3" fi losetup -d "${loop}"