From 5718ef5318c6f1bc761167ddb6a51f1ff553a9fb Mon Sep 17 00:00:00 2001 From: Ben Cressey Date: Fri, 7 Apr 2023 23:58:59 +0000 Subject: [PATCH 1/3] release: create data filesystem in local-fs.target The local filesystem is expected to be ready before local-fs.target is reached. Signed-off-by: Ben Cressey We don't need to wait for the 'repart' units since this cause boot to hang until the repart units timeout on waiting for a potentiaily non-existent data partition. 'systemd-repart' and 'systemd-makefs' both lock on the block device before operating on it, so repart is guaranteed to finish before makefs can create the filesystem. Co-authored-by: Erikson Tung --- packages/release/prepare-local-fs.service | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/release/prepare-local-fs.service b/packages/release/prepare-local-fs.service index 166b714b70f..49c87d3f58b 100644 --- a/packages/release/prepare-local-fs.service +++ b/packages/release/prepare-local-fs.service @@ -1,6 +1,7 @@ [Unit] Description=Prepare Local Filesystem (/local) DefaultDependencies=no +Before=local-fs.target Wants=dev-disk-by\x2dpartlabel-BOTTLEROCKET\x2dDATA.device After=dev-disk-by\x2dpartlabel-BOTTLEROCKET\x2dDATA.device RefuseManualStart=true From 912efef176f5464c93c3f52f31254978686ac228 Mon Sep 17 00:00:00 2001 From: Erikson Tung Date: Mon, 10 Apr 2023 18:03:14 -0700 Subject: [PATCH 2/3] release: stop & mask repart services if we've successfully created fs We explicitly stop and mask any repart-data service that has a start job waiting on a non-existent data partition after 'makefs' finishes successfully. This prevents awkward start job timeout messages from being printed to the console. --- packages/release/prepare-local-fs.service | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/release/prepare-local-fs.service b/packages/release/prepare-local-fs.service index 49c87d3f58b..4d58c2c0b73 100644 --- a/packages/release/prepare-local-fs.service +++ b/packages/release/prepare-local-fs.service @@ -13,6 +13,11 @@ Type=oneshot # Create the filesystem on the partition, if it doesn't exist. ExecStart=/usr/lib/systemd/systemd-makefs ext4 /dev/disk/by-partlabel/BOTTLEROCKET-DATA +# Stop and mask the repart-data-* oneshots in case they're waiting on non-existent data partitions. +# 'BOTTLEROCKET-DATA' already exists so we can move on. +ExecStart=/usr/bin/systemctl stop repart-data-preferred repart-data-fallback --no-block +ExecStart=/usr/bin/systemctl mask repart-data-preferred repart-data-fallback --no-block + RemainAfterExit=true StandardError=journal+console From 3f6840c5d3b990981e0014f8d8e64bb56adc89e5 Mon Sep 17 00:00:00 2001 From: Erikson Tung Date: Sun, 9 Apr 2023 18:54:58 -0700 Subject: [PATCH 3/3] packages: backport systemd fixes for udevd skipping events (and others) Backports the following, with some minor edits: * https://github.com/systemd/systemd/commit/2d40f02ee4317233365f53c85234be3af6b000a6 * https://github.com/systemd/systemd/pull/22717 * https://github.com/systemd/systemd/commit/400e3d21f8cae53a8ba9f9567f244fbf6f3e076c * https://github.com/systemd/systemd/commit/4f294ffdf18ab9f187400dbbab593a980e60be89 * https://github.com/systemd/systemd/commit/c02fb80479b23e70f4ad6f7717eec5c9444aa7f4 This fixes an issue with kernel uevents getting skipped by udev when the data partition block device is locked by 'systemd-makefs' or 'systemd-repart'. --- ...til-add-ERRNO_IS_DEVICE_ABSENT-macro.patch | 96 ++++++ ...ssary-clone-of-received-sd-device-ob.patch | 85 ++++++ ...uce-device_broadcast-helper-function.patch | 65 ++++ ...e-is-no-blocker-when-failed-to-check.patch | 52 ++++ ...05-udev-store-action-in-struct-Event.patch | 70 +++++ ...nt-when-the-corresponding-block-devi.patch | 286 ++++++++++++++++++ ...-ENOENT-or-friends-which-suggest-the.patch | 34 +++ ...it-worker_lock_block_device-into-two.patch | 121 ++++++++ ...k-device-is-not-locked-when-a-new-ev.patch | 84 +++++ ...d-inequality-for-timeout-of-retrying.patch | 27 ++ ...estart-event-for-previously-locked-d.patch | 85 ++++++ ...ad-selinux-label-database-less-frequ.patch | 43 +++ packages/systemd/systemd.spec | 22 ++ 13 files changed, 1070 insertions(+) create mode 100644 packages/systemd/0001-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch create mode 100644 packages/systemd/0002-udev-drop-unnecessary-clone-of-received-sd-device-ob.patch create mode 100644 packages/systemd/0003-udev-introduce-device_broadcast-helper-function.patch create mode 100644 packages/systemd/0004-udev-assume-there-is-no-blocker-when-failed-to-check.patch create mode 100644 packages/systemd/0005-udev-store-action-in-struct-Event.patch create mode 100644 packages/systemd/0006-udev-requeue-event-when-the-corresponding-block-devi.patch create mode 100644 packages/systemd/0007-udev-only-ignore-ENOENT-or-friends-which-suggest-the.patch create mode 100644 packages/systemd/0008-udev-split-worker_lock_block_device-into-two.patch create mode 100644 packages/systemd/0009-udev-assume-block-device-is-not-locked-when-a-new-ev.patch create mode 100644 packages/systemd/0010-udev-fix-inversed-inequality-for-timeout-of-retrying.patch create mode 100644 packages/systemd/0011-udev-certainly-restart-event-for-previously-locked-d.patch create mode 100644 packages/systemd/0012-udev-try-to-reload-selinux-label-database-less-frequ.patch diff --git a/packages/systemd/0001-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch b/packages/systemd/0001-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch new file mode 100644 index 00000000000..520987e66b4 --- /dev/null +++ b/packages/systemd/0001-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch @@ -0,0 +1,96 @@ +From 52cc55a9297e85866a237c09585cda47b2207746 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 24 Mar 2022 13:50:50 +0100 +Subject: [PATCH 01/12] errno-util: add ERRNO_IS_DEVICE_ABSENT() macro + +Inspired by: https://github.com/systemd/systemd/pull/22717#discussion_r834254495 +--- + src/basic/errno-util.h | 10 +++++++++- + src/home/homework-luks.c | 4 ++-- + src/rfkill/rfkill.c | 2 +- + src/udev/udev-builtin-btrfs.c | 3 ++- + 4 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h +index 09abf0b751..648de50eb4 100644 +--- a/src/basic/errno-util.h ++++ b/src/basic/errno-util.h +@@ -138,10 +138,18 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) { + EPERM); + } + +-/* Three difference errors for "not enough disk space" */ ++/* Three different errors for "not enough disk space" */ + static inline bool ERRNO_IS_DISK_SPACE(int r) { + return IN_SET(abs(r), + ENOSPC, + EDQUOT, + EFBIG); + } ++ ++/* Three different errors for "this device does not quite exist" */ ++static inline bool ERRNO_IS_DEVICE_ABSENT(int r) { ++ return IN_SET(abs(r), ++ ENODEV, ++ ENXIO, ++ ENOENT); ++} +diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c +index 1122e32575..cfe91d87c5 100644 +--- a/src/home/homework-luks.c ++++ b/src/home/homework-luks.c +@@ -494,7 +494,7 @@ static int acquire_open_luks_device( + return r; + + r = sym_crypt_init_by_name(&cd, setup->dm_name); +- if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT) && graceful) ++ if ((ERRNO_IS_DEVICE_ABSENT(r) || r == -EINVAL) && graceful) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name); +@@ -1634,7 +1634,7 @@ int home_deactivate_luks(UserRecord *h, HomeSetup *setup) { + cryptsetup_enable_logging(setup->crypt_device); + + r = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0); +- if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) { ++ if (ERRNO_IS_DEVICE_ABSENT(r) || r == -EINVAL) { + log_debug_errno(r, "LUKS device %s is already detached.", setup->dm_node); + we_detached = false; + } else if (r < 0) +diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c +index bca2f3b812..79fad78723 100644 +--- a/src/rfkill/rfkill.c ++++ b/src/rfkill/rfkill.c +@@ -80,7 +80,7 @@ static int find_device( + + r = sd_device_new_from_subsystem_sysname(&device, "rfkill", sysname); + if (r < 0) +- return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r, ++ return log_full_errno(ERRNO_IS_DEVICE_ABSENT(r) ? LOG_DEBUG : LOG_ERR, r, + "Failed to open device '%s': %m", sysname); + + r = sd_device_get_sysattr_value(device, "name", &name); +diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c +index a0093cb423..f9d4f1dd4e 100644 +--- a/src/udev/udev-builtin-btrfs.c ++++ b/src/udev/udev-builtin-btrfs.c +@@ -6,6 +6,7 @@ + #include + + #include "device-util.h" ++#include "errno-util.h" + #include "fd-util.h" + #include "string-util.h" + #include "strxcpyx.h" +@@ -22,7 +23,7 @@ static int builtin_btrfs(sd_device *dev, sd_netlink **rtnl, int argc, char *argv + + fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC); + if (fd < 0) { +- if (IN_SET(errno, ENOENT, ENXIO, ENODEV)) { ++ if (ERRNO_IS_DEVICE_ABSENT(errno)) { + /* Driver not installed? Then we aren't ready. This is useful in initrds that lack + * btrfs.ko. After the host transition (where btrfs.ko will hopefully become + * available) the device can be retriggered and will then be considered ready. */ +-- +2.25.1 + diff --git a/packages/systemd/0002-udev-drop-unnecessary-clone-of-received-sd-device-ob.patch b/packages/systemd/0002-udev-drop-unnecessary-clone-of-received-sd-device-ob.patch new file mode 100644 index 00000000000..962a7c38716 --- /dev/null +++ b/packages/systemd/0002-udev-drop-unnecessary-clone-of-received-sd-device-ob.patch @@ -0,0 +1,85 @@ +From 99c3273b0d6b7cb94914db4a4df877f5328577be Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 01:13:39 +0900 +Subject: [PATCH 02/12] udev: drop unnecessary clone of received sd-device + object + +As the sd-device object received through sd-device-monitor is sealed, +so the corresponding udev database or uevent file will not be read. +--- + src/udev/udevd.c | 22 +++++----------------- + 1 file changed, 5 insertions(+), 17 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 9320284be6..fbe0be8556 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -122,7 +122,6 @@ typedef struct Event { + EventState state; + + sd_device *dev; +- sd_device *dev_kernel; /* clone of originally received device */ + + uint64_t seqnum; + uint64_t blocker_seqnum; +@@ -161,7 +160,6 @@ static Event *event_free(Event *event) { + + LIST_REMOVE(event, event->manager->events, event); + sd_device_unref(event->dev); +- sd_device_unref(event->dev_kernel); + + sd_event_source_unref(event->timeout_warning_event); + sd_event_source_unref(event->timeout_event); +@@ -976,9 +974,8 @@ static int event_queue_start(Manager *manager) { + } + + static int event_queue_insert(Manager *manager, sd_device *dev) { +- _cleanup_(sd_device_unrefp) sd_device *clone = NULL; +- Event *event; + uint64_t seqnum; ++ Event *event; + int r; + + assert(manager); +@@ -992,15 +989,6 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { + if (r < 0) + return r; + +- /* Save original device to restore the state on failures. */ +- r = device_shallow_clone(dev, &clone); +- if (r < 0) +- return r; +- +- r = device_copy_properties(clone, dev); +- if (r < 0) +- return r; +- + event = new(Event, 1); + if (!event) + return -ENOMEM; +@@ -1008,7 +996,6 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { + *event = (Event) { + .manager = manager, + .dev = sd_device_ref(dev), +- .dev_kernel = TAKE_PTR(clone), + .seqnum = seqnum, + .state = EVENT_QUEUED, + }; +@@ -1444,10 +1431,11 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi + device_tag_index(worker->event->dev, NULL, false); + + if (manager->monitor) { +- /* forward kernel event without amending it */ +- r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); ++ /* Forward kernel event to libudev listeners */ ++ r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev); + if (r < 0) +- log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); ++ log_device_warning_errno(worker->event->dev, r, ++ "Failed to broadcast failed event to libudev listeners, ignoring: %m"); + } + } + +-- +2.25.1 + diff --git a/packages/systemd/0003-udev-introduce-device_broadcast-helper-function.patch b/packages/systemd/0003-udev-introduce-device_broadcast-helper-function.patch new file mode 100644 index 00000000000..07537a25a1a --- /dev/null +++ b/packages/systemd/0003-udev-introduce-device_broadcast-helper-function.patch @@ -0,0 +1,65 @@ +From b28f1747f75aa238ab7c84ecf55dc51b848f1746 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:33:55 +0900 +Subject: [PATCH 03/12] udev: introduce device_broadcast() helper function + +--- + src/udev/udevd.c | 28 ++++++++++++++++++---------- + 1 file changed, 18 insertions(+), 10 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index fbe0be8556..40e78b25cd 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -349,6 +349,21 @@ static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userda + return 1; + } + ++static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) { ++ int r; ++ ++ assert(dev); ++ ++ /* On exit, manager->monitor is already NULL. */ ++ if (!monitor) ++ return; ++ ++ r = device_monitor_send_device(monitor, NULL, dev); ++ if (r < 0) ++ log_device_warning_errno(dev, r, ++ "Failed to broadcast event to libudev listeners, ignoring: %m"); ++} ++ + static int worker_send_message(int fd) { + WorkerMessage message = {}; + +@@ -561,9 +576,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device * + log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m"); + + /* send processed event back to libudev listeners */ +- r = device_monitor_send_device(monitor, NULL, dev); +- if (r < 0) +- log_device_warning_errno(dev, r, "Failed to send device, ignoring: %m"); ++ device_broadcast(monitor, dev); + } + + /* send udevd the result of the event execution */ +@@ -1430,13 +1443,8 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi + device_delete_db(worker->event->dev); + device_tag_index(worker->event->dev, NULL, false); + +- if (manager->monitor) { +- /* Forward kernel event to libudev listeners */ +- r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev); +- if (r < 0) +- log_device_warning_errno(worker->event->dev, r, +- "Failed to broadcast failed event to libudev listeners, ignoring: %m"); +- } ++ /* Forward kernel event to libudev listeners */ ++ device_broadcast(manager->monitor, worker->event->dev); + } + + worker_free(worker); +-- +2.25.1 + diff --git a/packages/systemd/0004-udev-assume-there-is-no-blocker-when-failed-to-check.patch b/packages/systemd/0004-udev-assume-there-is-no-blocker-when-failed-to-check.patch new file mode 100644 index 00000000000..9bbd6228921 --- /dev/null +++ b/packages/systemd/0004-udev-assume-there-is-no-blocker-when-failed-to-check.patch @@ -0,0 +1,52 @@ +From a95aba56e5b31f221eb9133e70ddb1044315e532 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 12 Mar 2022 20:57:15 +0900 +Subject: [PATCH 04/12] udev: assume there is no blocker when failed to check + event dependencies + +Previously, if udevd failed to resolve event dependency, the event is +ignored and libudev listeners did not receive the event. This is +inconsistent with the case when a worker failed to process a event, +in that case, the original uevent sent by the kernel is broadcasted to +listeners. +--- + src/udev/udevd.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 40e78b25cd..ed53470848 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -962,24 +962,21 @@ static int event_queue_start(Manager *manager) { + + /* do not start event if parent or child event is still running or queued */ + r = event_is_blocked(event); ++ if (r > 0) ++ continue; + if (r < 0) { + sd_device_action_t a = _SD_DEVICE_ACTION_INVALID; + + (void) sd_device_get_action(event->dev, &a); + log_device_warning_errno(event->dev, r, +- "Failed to check event dependency, " +- "skipping event (SEQNUM=%"PRIu64", ACTION=%s)", ++ "Failed to check dependencies for event (SEQNUM=%"PRIu64", ACTION=%s), " ++ "assuming there is no blocking event, ignoring: %m", + event->seqnum, + strna(device_action_to_string(a))); +- +- event_free(event); +- return r; + } +- if (r > 0) +- continue; + + r = event_run(event); +- if (r <= 0) ++ if (r <= 0) /* 0 means there are no idle workers. Let's escape from the loop. */ + return r; + } + +-- +2.25.1 + diff --git a/packages/systemd/0005-udev-store-action-in-struct-Event.patch b/packages/systemd/0005-udev-store-action-in-struct-Event.patch new file mode 100644 index 00000000000..706150ad6a2 --- /dev/null +++ b/packages/systemd/0005-udev-store-action-in-struct-Event.patch @@ -0,0 +1,70 @@ +From 2be3e27017de18f5d973ca9b83cc170c784fb8db Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:39:55 +0900 +Subject: [PATCH 05/12] udev: store action in struct Event + +--- + src/udev/udevd.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index ed53470848..abf50b6a71 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -123,6 +123,7 @@ typedef struct Event { + + sd_device *dev; + ++ sd_device_action_t action; + uint64_t seqnum; + uint64_t blocker_seqnum; + +@@ -964,16 +965,12 @@ static int event_queue_start(Manager *manager) { + r = event_is_blocked(event); + if (r > 0) + continue; +- if (r < 0) { +- sd_device_action_t a = _SD_DEVICE_ACTION_INVALID; +- +- (void) sd_device_get_action(event->dev, &a); ++ if (r < 0) + log_device_warning_errno(event->dev, r, + "Failed to check dependencies for event (SEQNUM=%"PRIu64", ACTION=%s), " + "assuming there is no blocking event, ignoring: %m", + event->seqnum, +- strna(device_action_to_string(a))); +- } ++ strna(device_action_to_string(event->action))); + + r = event_run(event); + if (r <= 0) /* 0 means there are no idle workers. Let's escape from the loop. */ +@@ -984,6 +981,7 @@ static int event_queue_start(Manager *manager) { + } + + static int event_queue_insert(Manager *manager, sd_device *dev) { ++ sd_device_action_t action; + uint64_t seqnum; + Event *event; + int r; +@@ -999,6 +997,10 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { + if (r < 0) + return r; + ++ r = sd_device_get_action(dev, &action); ++ if (r < 0) ++ return r; ++ + event = new(Event, 1); + if (!event) + return -ENOMEM; +@@ -1007,6 +1009,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { + .manager = manager, + .dev = sd_device_ref(dev), + .seqnum = seqnum, ++ .action = action, + .state = EVENT_QUEUED, + }; + +-- +2.25.1 + diff --git a/packages/systemd/0006-udev-requeue-event-when-the-corresponding-block-devi.patch b/packages/systemd/0006-udev-requeue-event-when-the-corresponding-block-devi.patch new file mode 100644 index 00000000000..2bb858c5f63 --- /dev/null +++ b/packages/systemd/0006-udev-requeue-event-when-the-corresponding-block-devi.patch @@ -0,0 +1,286 @@ +From 95a447cf47a1a03b50f2dab1f4e5e05aa58aec19 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Mar 2022 13:50:06 +0900 +Subject: [PATCH 06/12] udev: requeue event when the corresponding block device + is locked by another process + +Previously, if a block device is locked by another process, then the +corresponding worker skip to process the corresponding event, and does +not broadcast the uevent to libudev listners. This causes several issues: + +- During a period of a device being locked by a process, if a user trigger + an event with `udevadm trigger --settle`, then it never returned. + +- When there is a delay between close and unlock in a process, then the + synthesized events triggered by inotify may not be processed. This can + happens easily by wrapping mkfs with flock. This causes severe issues + e.g. new devlinks are not created, or old devlinks are not removed. + +This commit makes events are requeued with a tiny delay when the corresponding +block devices are locked by other processes. With this way, the triggered +uevent may be delayed but is always processed by udevd. Hence, the above +issues can be solved. Also, it is not necessary to watch a block device +unconditionally when it is already locked. Hence, the logic is dropped. +--- + src/udev/udevd.c | 154 +++++++++++++++++++++++++++++------------------ + 1 file changed, 97 insertions(+), 57 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index abf50b6a71..01d782421e 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -68,6 +68,8 @@ + #include "version.h" + + #define WORKER_NUM_MAX 2048U ++#define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC) ++#define EVENT_RETRY_TIMEOUT_USEC (3 * USEC_PER_MINUTE) + + static bool arg_debug = false; + static int arg_daemonize = false; +@@ -126,6 +128,8 @@ typedef struct Event { + sd_device_action_t action; + uint64_t seqnum; + uint64_t blocker_seqnum; ++ usec_t retry_again_next_usec; ++ usec_t retry_again_timeout_usec; + + sd_event_source *timeout_warning_event; + sd_event_source *timeout_event; +@@ -150,8 +154,13 @@ typedef struct Worker { + } Worker; + + /* passed from worker to main process */ +-typedef struct WorkerMessage { +-} WorkerMessage; ++typedef enum EventResult { ++ EVENT_RESULT_SUCCESS, ++ EVENT_RESULT_FAILED, ++ EVENT_RESULT_TRY_AGAIN, /* when the block device is locked by another process. */ ++ _EVENT_RESULT_MAX, ++ _EVENT_RESULT_INVALID = -EINVAL, ++} EventResult; + + static Event *event_free(Event *event) { + if (!event) +@@ -365,10 +374,11 @@ static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) { + "Failed to broadcast event to libudev listeners, ignoring: %m"); + } + +-static int worker_send_message(int fd) { +- WorkerMessage message = {}; ++static int worker_send_result(Manager *manager, EventResult result) { ++ assert(manager); ++ assert(manager->worker_watch[WRITE_END] >= 0); + +- return loop_write(fd, &message, sizeof(message), false); ++ return loop_write(manager->worker_watch[WRITE_END], &result, sizeof(result), false); + } + + static int worker_lock_block_device(sd_device *dev, int *ret_fd) { +@@ -493,44 +503,12 @@ static int worker_process_device(Manager *manager, sd_device *dev) { + if (!udev_event) + return -ENOMEM; + ++ /* If this is a block device and the device is locked currently via the BSD advisory locks, ++ * someone else is using it exclusively. We don't run our udev rules now to not interfere. ++ * Instead of processing the event, we requeue the event and will try again after a delay. ++ * ++ * The user-facing side of this: https://systemd.io/BLOCK_DEVICE_LOCKING */ + r = worker_lock_block_device(dev, &fd_lock); +- if (r == -EAGAIN) { +- /* So this is a block device and the device is locked currently via the BSD advisory locks — +- * someone else is exclusively using it. This means we don't run our udev rules now, to not +- * interfere. However we want to know when the device is unlocked again, and retrigger the +- * device again then, so that the rules are run eventually. For that we use IN_CLOSE_WRITE +- * inotify watches (which isn't exactly the same as waiting for the BSD locks to release, but +- * not totally off, as long as unlock+close() is done together, as it usually is). +- * +- * (The user-facing side of this: https://systemd.io/BLOCK_DEVICE_LOCKING) +- * +- * There's a bit of a chicken and egg problem here for this however: inotify watching is +- * supposed to be enabled via an option set via udev rules (OPTIONS+="watch"). If we skip the +- * udev rules here however (as we just said we do), we would thus never see that specific +- * udev rule, and thus never turn on inotify watching. But in order to catch up eventually +- * and run them we we need the inotify watching: hence a classic chicken and egg problem. +- * +- * Our way out here: if we see the block device locked, unconditionally watch the device via +- * inotify, regardless of any explicit request via OPTIONS+="watch". Thus, a device that is +- * currently locked via the BSD file locks will be treated as if we ran a single udev rule +- * only for it: the one that turns on inotify watching for it. If we eventually see the +- * inotify IN_CLOSE_WRITE event, and then run the rules after all and we then realize that +- * this wasn't actually requested (i.e. no OPTIONS+="watch" set) we'll simply turn off the +- * watching again (see below). Effectively this means: inotify watching is now enabled either +- * a) when the udev rules say so, or b) while the device is locked. +- * +- * Worst case scenario hence: in the (unlikely) case someone locked the device and we clash +- * with that we might do inotify watching for a brief moment for a device where we actually +- * weren't supposed to. But that shouldn't be too bad, in particular as BSD locks being taken +- * on a block device is kinda an indication that the inotify logic is desired too, to some +- * 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(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); +- } + if (r < 0) + return r; + +@@ -563,25 +541,29 @@ static int worker_process_device(Manager *manager, sd_device *dev) { + + static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *dev, void *userdata) { + Manager *manager = userdata; ++ EventResult result; + int r; + + assert(dev); + assert(manager); + + r = worker_process_device(manager, dev); +- if (r == -EAGAIN) +- /* if we couldn't acquire the flock(), then proceed quietly */ +- log_device_debug_errno(dev, r, "Device currently locked, not processing."); +- else { +- if (r < 0) +- log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m"); ++ if (r == -EAGAIN) { ++ /* if we couldn't acquire the flock(), then requeue the event */ ++ result = EVENT_RESULT_TRY_AGAIN; ++ log_device_debug_errno(dev, r, "Block device is currently locked, requeueing the event."); ++ } else if (r < 0) { ++ result = EVENT_RESULT_FAILED; ++ log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m"); ++ } else ++ result = EVENT_RESULT_SUCCESS; + ++ if (result != EVENT_RESULT_TRY_AGAIN) + /* send processed event back to libudev listeners */ + device_broadcast(monitor, dev); +- } + + /* send udevd the result of the event execution */ +- r = worker_send_message(manager->worker_watch[WRITE_END]); ++ r = worker_send_result(manager, result); + if (r < 0) + log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m"); + +@@ -801,6 +783,17 @@ static int event_is_blocked(Event *event) { + assert(event->manager); + assert(event->blocker_seqnum <= event->seqnum); + ++ if (event->retry_again_next_usec > 0) { ++ usec_t now_usec; ++ ++ r = sd_event_now(event->manager->event, clock_boottime_or_monotonic(), &now_usec); ++ if (r < 0) ++ return r; ++ ++ if (event->retry_again_next_usec <= now_usec) ++ return true; ++ } ++ + if (event->blocker_seqnum == event->seqnum) + /* we have checked previously and no blocker found */ + return false; +@@ -980,6 +973,44 @@ static int event_queue_start(Manager *manager) { + return 0; + } + ++static int event_requeue(Event *event) { ++ usec_t now_usec; ++ int r; ++ ++ assert(event); ++ assert(event->manager); ++ assert(event->manager->event); ++ ++ event->timeout_warning_event = sd_event_source_disable_unref(event->timeout_warning_event); ++ event->timeout_event = sd_event_source_disable_unref(event->timeout_event); ++ ++ /* add a short delay to suppress busy loop */ ++ r = sd_event_now(event->manager->event, clock_boottime_or_monotonic(), &now_usec); ++ if (r < 0) ++ return log_device_warning_errno(event->dev, r, ++ "Failed to get current time, " ++ "skipping event (SEQNUM=%"PRIu64", ACTION=%s): %m", ++ event->seqnum, strna(device_action_to_string(event->action))); ++ ++ if (event->retry_again_timeout_usec > 0 && event->retry_again_timeout_usec <= now_usec) ++ return log_device_warning_errno(event->dev, SYNTHETIC_ERRNO(ETIMEDOUT), ++ "The underlying block device is locked by a process more than %s, " ++ "skipping event (SEQNUM=%"PRIu64", ACTION=%s).", ++ FORMAT_TIMESPAN(EVENT_RETRY_TIMEOUT_USEC, USEC_PER_MINUTE), ++ event->seqnum, strna(device_action_to_string(event->action))); ++ ++ event->retry_again_next_usec = usec_add(now_usec, EVENT_RETRY_INTERVAL_USEC); ++ if (event->retry_again_timeout_usec == 0) ++ event->retry_again_timeout_usec = usec_add(now_usec, EVENT_RETRY_TIMEOUT_USEC); ++ ++ if (event->worker && event->worker->event == event) ++ event->worker->event = NULL; ++ event->worker = NULL; ++ ++ event->state = EVENT_QUEUED; ++ return 0; ++} ++ + static int event_queue_insert(Manager *manager, sd_device *dev) { + sd_device_action_t action; + uint64_t seqnum; +@@ -1054,11 +1085,8 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat + assert(manager); + + for (;;) { +- WorkerMessage msg; +- struct iovec iovec = { +- .iov_base = &msg, +- .iov_len = sizeof(msg), +- }; ++ EventResult result; ++ struct iovec iovec = IOVEC_MAKE(&result, sizeof(result)); + CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control; + struct msghdr msghdr = { + .msg_iov = &iovec, +@@ -1081,7 +1109,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat + + cmsg_close_all(&msghdr); + +- if (size != sizeof(WorkerMessage)) { ++ if (size != sizeof(EventResult)) { + log_warning("Ignoring worker message with invalid size %zi bytes", size); + continue; + } +@@ -1106,6 +1134,11 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat + worker->state = WORKER_IDLE; + + /* worker returned */ ++ if (result == EVENT_RESULT_TRY_AGAIN && ++ event_requeue(worker->event) < 0) ++ device_broadcast(manager->monitor, worker->event->dev); ++ ++ /* When event_requeue() succeeds, worker->event is NULL, and event_free() handles NULL gracefully. */ + event_free(worker->event); + } + +@@ -1468,8 +1501,15 @@ static int on_post(sd_event_source *s, void *userdata) { + + assert(manager); + +- if (!LIST_IS_EMPTY(manager->events)) ++ if (!LIST_IS_EMPTY(manager->events)) { ++ /* Try to process pending events if idle workers exist. Why is this necessary? ++ * When a worker finished an event and became idle, even if there was a pending event, ++ * the corresponding device might have been locked and the processing of the event ++ * delayed for a while, preventing the worker from processing the event immediately. ++ * Now, the device may be unlocked. Let's try again! */ ++ event_queue_start(manager); + return 1; ++ } + + /* There are no pending events. Let's cleanup idle process. */ + +-- +2.25.1 + diff --git a/packages/systemd/0007-udev-only-ignore-ENOENT-or-friends-which-suggest-the.patch b/packages/systemd/0007-udev-only-ignore-ENOENT-or-friends-which-suggest-the.patch new file mode 100644 index 00000000000..91d37071f9f --- /dev/null +++ b/packages/systemd/0007-udev-only-ignore-ENOENT-or-friends-which-suggest-the.patch @@ -0,0 +1,34 @@ +From 8c8c3f5d7683a9d45823037fe30ba491b167b305 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 12 Mar 2022 20:40:58 +0900 +Subject: [PATCH 07/12] udev: only ignore ENOENT or friends which suggest the + block device is not exist + +The ENOENT, ENXIO, and ENODEV error can happen easily when a block +device appears and soon removed. So, it is reasonable to ignore the +error. But other errors should not occur here, and hence let's handle +them as critical. +--- + src/udev/udevd.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 01d782421e..2b34bbf991 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -428,8 +428,10 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) { + + fd = open(val, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); + if (fd < 0) { +- log_device_debug_errno(dev, errno, "Failed to open '%s', ignoring: %m", val); +- return 0; ++ bool ignore = ERRNO_IS_DEVICE_ABSENT(errno); ++ ++ log_device_debug_errno(dev, errno, "Failed to open '%s'%s: %m", val, ignore ? ", ignoring" : ""); ++ return ignore ? 0 : -errno; + } + + if (flock(fd, LOCK_SH|LOCK_NB) < 0) +-- +2.25.1 + diff --git a/packages/systemd/0008-udev-split-worker_lock_block_device-into-two.patch b/packages/systemd/0008-udev-split-worker_lock_block_device-into-two.patch new file mode 100644 index 00000000000..1cb638560bc --- /dev/null +++ b/packages/systemd/0008-udev-split-worker_lock_block_device-into-two.patch @@ -0,0 +1,121 @@ +From 87d86be1dcfbe10bd774ee346fb644353fd1641f Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:55:25 +0900 +Subject: [PATCH 08/12] udev: split worker_lock_block_device() into two + +This also makes return value initialized when these function return 0 to +follow our coding style. + +Just a preparation for later commits. +--- + src/udev/udevd.c | 54 ++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 41 insertions(+), 13 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 2b34bbf991..c86f401922 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -381,35 +381,29 @@ static int worker_send_result(Manager *manager, EventResult result) { + return loop_write(manager->worker_watch[WRITE_END], &result, sizeof(result), false); + } + +-static int worker_lock_block_device(sd_device *dev, int *ret_fd) { +- _cleanup_close_ int fd = -1; ++static int device_get_block_device(sd_device *dev, const char **ret) { + const char *val; + int r; + + assert(dev); +- assert(ret_fd); +- +- /* Take a shared lock on the device node; this establishes a concept of device "ownership" to +- * serialize device access. External processes holding an exclusive lock will cause udev to skip the +- * event handling; in the case udev acquired the lock, the external process can block until udev has +- * finished its event handling. */ ++ assert(ret); + + if (device_for_action(dev, SD_DEVICE_REMOVE)) +- return 0; ++ goto irrelevant; + + r = sd_device_get_subsystem(dev, &val); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get subsystem: %m"); + + if (!streq(val, "block")) +- return 0; ++ goto irrelevant; + + r = sd_device_get_sysname(dev, &val); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get sysname: %m"); + + if (STARTSWITH_SET(val, "dm-", "md", "drbd")) +- return 0; ++ goto irrelevant; + + r = sd_device_get_devtype(dev, &val); + if (r < 0 && r != -ENOENT) +@@ -422,16 +416,46 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) { + + r = sd_device_get_devname(dev, &val); + if (r == -ENOENT) +- return 0; ++ goto irrelevant; + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get devname: %m"); + ++ *ret = val; ++ return 1; ++ ++irrelevant: ++ *ret = NULL; ++ return 0; ++} ++ ++static int worker_lock_block_device(sd_device *dev, int *ret_fd) { ++ _cleanup_close_ int fd = -1; ++ const char *val; ++ int r; ++ ++ assert(dev); ++ assert(ret_fd); ++ ++ /* Take a shared lock on the device node; this establishes a concept of device "ownership" to ++ * serialize device access. External processes holding an exclusive lock will cause udev to skip the ++ * event handling; in the case udev acquired the lock, the external process can block until udev has ++ * finished its event handling. */ ++ ++ r = device_get_block_device(dev, &val); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ goto nolock; ++ + fd = open(val, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); + if (fd < 0) { + bool ignore = ERRNO_IS_DEVICE_ABSENT(errno); + + log_device_debug_errno(dev, errno, "Failed to open '%s'%s: %m", val, ignore ? ", ignoring" : ""); +- return ignore ? 0 : -errno; ++ if (!ignore) ++ return -errno; ++ ++ goto nolock; + } + + if (flock(fd, LOCK_SH|LOCK_NB) < 0) +@@ -439,6 +463,10 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) { + + *ret_fd = TAKE_FD(fd); + return 1; ++ ++nolock: ++ *ret_fd = -1; ++ return 0; + } + + static int worker_mark_block_device_read_only(sd_device *dev) { +-- +2.25.1 + diff --git a/packages/systemd/0009-udev-assume-block-device-is-not-locked-when-a-new-ev.patch b/packages/systemd/0009-udev-assume-block-device-is-not-locked-when-a-new-ev.patch new file mode 100644 index 00000000000..4a5de4fac4b --- /dev/null +++ b/packages/systemd/0009-udev-assume-block-device-is-not-locked-when-a-new-ev.patch @@ -0,0 +1,84 @@ +From 9fb5157398d4c5d0b6a6ee3ab3ed774feb5574e6 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:56:58 +0900 +Subject: [PATCH 09/12] udev: assume block device is not locked when a new + event is queued + +Then, hopefully, previously requeued events are processed earlier. + +[etungsten: backport to v250 - use LIST_FOREACH_SAFE instead of +LIST_FOREACH] +Signed-off-by: Erikson Tung +--- + src/udev/udevd.c | 40 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 39 insertions(+), 1 deletion(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index c86f401922..e1dc5e56c6 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1041,6 +1041,40 @@ static int event_requeue(Event *event) { + return 0; + } + ++static int event_queue_assume_block_device_unlocked(Manager *manager, sd_device *dev) { ++ const char *devname; ++ int r; ++ ++ /* When a new event for a block device is queued or we get an inotify event, assume that the ++ * device is not locked anymore. The assumption may not be true, but that should not cause any ++ * issues, as in that case events will be requeued soon. */ ++ ++ r = device_get_block_device(dev, &devname); ++ if (r <= 0) ++ return r; ++ ++ Event *event, *tmp; ++ LIST_FOREACH_SAFE(event, event, tmp, manager->events) { ++ const char *event_devname; ++ ++ if (event->state != EVENT_QUEUED) ++ continue; ++ ++ if (event->retry_again_next_usec == 0) ++ continue; ++ ++ if (device_get_block_device(event->dev, &event_devname) <= 0) ++ continue; ++ ++ if (!streq(devname, event_devname)) ++ continue; ++ ++ event->retry_again_next_usec = 0; ++ } ++ ++ return 0; ++} ++ + static int event_queue_insert(Manager *manager, sd_device *dev) { + sd_device_action_t action; + uint64_t seqnum; +@@ -1103,6 +1137,8 @@ static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) + return 1; + } + ++ (void) event_queue_assume_block_device_unlocked(manager, dev); ++ + /* we have fresh events, try to schedule them */ + event_queue_start(manager); + +@@ -1432,8 +1468,10 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda + continue; + + log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode); +- if (e->mask & IN_CLOSE_WRITE) ++ if (e->mask & IN_CLOSE_WRITE) { ++ (void) event_queue_assume_block_device_unlocked(manager, 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(). */ +-- +2.25.1 + diff --git a/packages/systemd/0010-udev-fix-inversed-inequality-for-timeout-of-retrying.patch b/packages/systemd/0010-udev-fix-inversed-inequality-for-timeout-of-retrying.patch new file mode 100644 index 00000000000..0684f08acbe --- /dev/null +++ b/packages/systemd/0010-udev-fix-inversed-inequality-for-timeout-of-retrying.patch @@ -0,0 +1,27 @@ +From b1bdec13285d295785065fb72364e9147a8f6e9e Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 19 Aug 2022 21:25:03 +0900 +Subject: [PATCH 10/12] udev: fix inversed inequality for timeout of retrying + event + +Follow-up for 5d354e525a56955ae7f68062e283dda85ab07794. +--- + src/udev/udevd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e1dc5e56c6..dd200b241c 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -820,7 +820,7 @@ static int event_is_blocked(Event *event) { + if (r < 0) + return r; + +- if (event->retry_again_next_usec <= now_usec) ++ if (event->retry_again_next_usec > now_usec) + return true; + } + +-- +2.25.1 + diff --git a/packages/systemd/0011-udev-certainly-restart-event-for-previously-locked-d.patch b/packages/systemd/0011-udev-certainly-restart-event-for-previously-locked-d.patch new file mode 100644 index 00000000000..7ff868ee6c7 --- /dev/null +++ b/packages/systemd/0011-udev-certainly-restart-event-for-previously-locked-d.patch @@ -0,0 +1,85 @@ +From 93b17554058e18e9a71d97c5d0be51d969a7291d Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 26 Aug 2022 00:16:17 +0900 +Subject: [PATCH 11/12] udev: certainly restart event for previously locked + device + +If udevd receives a uevent for a locked block device, then the event +is requeued. However, the queued event will be processed only when at +least one sd_event_source is processed. Hence, if udevd has no event +under processing, or receives no new uevent, etc., then the requeued +event will be never processed. + +Follow-up for 400e3d21f8cae53a8ba9f9567f244fbf6f3e076c. + +Fixes #24439. +--- + src/udev/udevd.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index dd200b241c..6707befecf 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -128,8 +128,11 @@ typedef struct Event { + sd_device_action_t action; + uint64_t seqnum; + uint64_t blocker_seqnum; ++ ++ /* Used when the device is locked by another program. */ + usec_t retry_again_next_usec; + usec_t retry_again_timeout_usec; ++ sd_event_source *retry_event_source; + + sd_event_source *timeout_warning_event; + sd_event_source *timeout_event; +@@ -171,6 +174,9 @@ static Event *event_free(Event *event) { + LIST_REMOVE(event, event->manager->events, event); + sd_device_unref(event->dev); + ++ /* Do not use sd_event_source_disable_unref() here, as this is called by both workers and the ++ * main process. */ ++ sd_event_source_unref(event->retry_event_source); + sd_event_source_unref(event->timeout_warning_event); + sd_event_source_unref(event->timeout_event); + +@@ -757,6 +763,8 @@ static int event_run(Event *event) { + + log_device_uevent(event->dev, "Device ready for processing"); + ++ (void) event_source_disable(event->retry_event_source); ++ + manager = event->manager; + HASHMAP_FOREACH(worker, manager->workers) { + if (worker->state != WORKER_IDLE) +@@ -1003,6 +1011,11 @@ static int event_queue_start(Manager *manager) { + return 0; + } + ++static int on_event_retry(sd_event_source *s, uint64_t usec, void *userdata) { ++ /* This does nothing. The on_post() callback will start the event if there exists an idle worker. */ ++ return 1; ++} ++ + static int event_requeue(Event *event) { + usec_t now_usec; + int r; +@@ -1033,6 +1046,15 @@ static int event_requeue(Event *event) { + if (event->retry_again_timeout_usec == 0) + event->retry_again_timeout_usec = usec_add(now_usec, EVENT_RETRY_TIMEOUT_USEC); + ++ r = event_reset_time_relative(event->manager->event, &event->retry_event_source, ++ CLOCK_MONOTONIC, EVENT_RETRY_INTERVAL_USEC, 0, ++ on_event_retry, NULL, ++ 0, "retry-event", true); ++ if (r < 0) ++ return log_device_warning_errno(event->dev, r, "Failed to reset timer event source for retrying event, " ++ "skipping event (SEQNUM=%"PRIu64", ACTION=%s): %m", ++ event->seqnum, strna(device_action_to_string(event->action))); ++ + if (event->worker && event->worker->event == event) + event->worker->event = NULL; + event->worker = NULL; +-- +2.25.1 + diff --git a/packages/systemd/0012-udev-try-to-reload-selinux-label-database-less-frequ.patch b/packages/systemd/0012-udev-try-to-reload-selinux-label-database-less-frequ.patch new file mode 100644 index 00000000000..2260fa809fb --- /dev/null +++ b/packages/systemd/0012-udev-try-to-reload-selinux-label-database-less-frequ.patch @@ -0,0 +1,43 @@ +From e5150a06351570f050ede4c12706be460780df24 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 13 Mar 2022 04:45:08 +0900 +Subject: [PATCH 12/12] udev: try to reload selinux label database less + frequently + +Previously, `event_run()` was called repeatedly in one `event_queue_start()` +invocation. Hence, the SELinux label database is reloaded many times needlessly. +Other settings, e.g. udev rules or hwdata, are tried to be reloaded in the +beginning of `event_queue_start()`. Let's also do so for the SELinux database. +--- + src/udev/udevd.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 6707befecf..fd93a1a4c1 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -795,10 +795,6 @@ static int event_run(Event *event) { + /* Re-enable the debug message for the next batch of events */ + log_children_max_reached = true; + +- /* fork with up-to-date SELinux label database, so the child inherits the up-to-date db +- * and, until the next SELinux policy changes, we safe further reloads in future children */ +- mac_selinux_maybe_reload(); +- + /* start new worker and pass initial device */ + r = worker_spawn(manager, event); + if (r < 0) +@@ -988,6 +984,10 @@ static int event_queue_start(Manager *manager) { + return log_warning_errno(r, "Failed to read udev rules: %m"); + } + ++ /* fork with up-to-date SELinux label database, so the child inherits the up-to-date db ++ * and, until the next SELinux policy changes, we safe further reloads in future children */ ++ mac_selinux_maybe_reload(); ++ + LIST_FOREACH_SAFE(event, event, event_next, manager->events) { + if (event->state != EVENT_QUEUED) + continue; +-- +2.25.1 + diff --git a/packages/systemd/systemd.spec b/packages/systemd/systemd.spec index 0d1d959ef92..7016189380b 100644 --- a/packages/systemd/systemd.spec +++ b/packages/systemd/systemd.spec @@ -13,6 +13,28 @@ Source2: systemd-modules-load.conf Source3: journald.conf Source4: issue +# Backports for fixing udev skipping kernel uevents under special circumstances +# * https://github.com/systemd/systemd/commit/2d40f02ee4317233365f53c85234be3af6b000a6 +# * https://github.com/systemd/systemd/pull/22717 +# * https://github.com/systemd/systemd/commit/400e3d21f8cae53a8ba9f9567f244fbf6f3e076c +# * https://github.com/systemd/systemd/commit/4f294ffdf18ab9f187400dbbab593a980e60be89 +# * https://github.com/systemd/systemd/commit/c02fb80479b23e70f4ad6f7717eec5c9444aa7f4 +# From v251: +Patch0001: 0001-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch +Patch0002: 0002-udev-drop-unnecessary-clone-of-received-sd-device-ob.patch +Patch0003: 0003-udev-introduce-device_broadcast-helper-function.patch +Patch0004: 0004-udev-assume-there-is-no-blocker-when-failed-to-check.patch +Patch0005: 0005-udev-store-action-in-struct-Event.patch +Patch0006: 0006-udev-requeue-event-when-the-corresponding-block-devi.patch +Patch0007: 0007-udev-only-ignore-ENOENT-or-friends-which-suggest-the.patch +Patch0008: 0008-udev-split-worker_lock_block_device-into-two.patch +Patch0009: 0009-udev-assume-block-device-is-not-locked-when-a-new-ev.patch +# From v252: +Patch0010: 0010-udev-fix-inversed-inequality-for-timeout-of-retrying.patch +Patch0011: 0011-udev-certainly-restart-event-for-previously-locked-d.patch +# From v251: +Patch0012: 0012-udev-try-to-reload-selinux-label-database-less-frequ.patch + # Local patch to work around the fact that /var is a bind mount from # /local/var, and we want the /local/var/run symlink to point to /run. Patch9001: 9001-use-absolute-path-for-var-run-symlink.patch