From 1d68f589fadf7dfd1b80ad62131a7fd273dfd2c2 Mon Sep 17 00:00:00 2001 From: chenjiayi Date: Sun, 11 Jun 2023 07:59:19 +0800 Subject: [PATCH] backport upstream patches to fix event loss when the whole disk is locked --- ...the-uevent-when-worker-is-terminated.patch | 52 +- ...til-add-ERRNO_IS_DEVICE_ABSENT-macro.patch | 75 +++ ...-introduce-event_reset_time_relative.patch | 87 +++ ...IST_FOREACH_BACKWARDS-macro-and-drop.patch | 102 ++++ ...-udev-add-usec_add-at-one-more-place.patch | 28 + ...lso-rename-struct-udev_ctrl-UdevCtrl.patch | 350 +++++++++++ ...ot-locked-when-a-new-event-is-queued.patch | 81 +++ ...o-blocker-when-failed-to-check-event.patch | 54 ++ ...t-event-for-previously-locked-device.patch | 86 +++ ...-blocker-again-when-no-blocker-found.patch | 91 +++ ...ss-events-if-there-is-no-free-worker.patch | 28 + ...necessary-calls-of-event_queue_start.patch | 80 +++ ...y-clone-of-received-sd-device-object.patch | 85 +++ ...uality-for-timeout-of-retrying-event.patch | 27 + ...uce-device_broadcast_helper_function.patch | 66 +++ ...ort-udev-make-event_free-return-NULL.patch | 36 ++ ...start-return-negative-errno-on-error.patch | 59 ++ backport-udev-move-several-functions.patch | 544 ++++++++++++++++++ ...T-or-friends-which-suggest-the-block.patch | 36 ++ ...propagate-error-on-spawning-a-worker.patch | 89 +++ ...dev-remove-run-udev-queue-in-on_post.patch | 53 ++ ...name-is_device_busy-event_is_blocked.patch | 141 +++++ ...en-the-corresponding-block-device-is.patch | 288 ++++++++++ ...hen-its-dependency-cannot-be-checked.patch | 58 ++ ...it-worker_lock_block_device-into-two.patch | 123 ++++ ...rt-udev-store-action-in-struct-Event.patch | 71 +++ ...udev-update-comment-and-log-messages.patch | 31 + ...to-clarify-that-the-error-is-ignored.patch | 36 ++ systemd.spec | 32 +- 29 files changed, 2859 insertions(+), 30 deletions(-) create mode 100644 backport-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch create mode 100644 backport-event-util-introduce-event_reset_time_relative.patch create mode 100644 backport-list-introduce-LIST_FOREACH_BACKWARDS-macro-and-drop.patch create mode 100644 backport-udev-add-usec_add-at-one-more-place.patch create mode 100644 backport-udev-also-rename-struct-udev_ctrl-UdevCtrl.patch create mode 100644 backport-udev-assume-block-device-is-not-locked-when-a-new-event-is-queued.patch create mode 100644 backport-udev-assume-there-is-no-blocker-when-failed-to-check-event.patch create mode 100644 backport-udev-certainly-restart-event-for-previously-locked-device.patch create mode 100644 backport-udev-do-not-try-to-find-blocker-again-when-no-blocker-found.patch create mode 100644 backport-udev-do-not-try-to-process-events-if-there-is-no-free-worker.patch create mode 100644 backport-udev-drop-unnecessary-calls-of-event_queue_start.patch create mode 100644 backport-udev-drop-unnecessary-clone-of-received-sd-device-object.patch create mode 100644 backport-udev-fix-inversed-inequality-for-timeout-of-retrying-event.patch create mode 100644 backport-udev-introduce-device_broadcast_helper_function.patch create mode 100644 backport-udev-make-event_free-return-NULL.patch create mode 100644 backport-udev-make-event_queue_start-return-negative-errno-on-error.patch create mode 100644 backport-udev-move-several-functions.patch create mode 100644 backport-udev-only-ignore-ENOENT-or-friends-which-suggest-the-block.patch create mode 100644 backport-udev-propagate-error-on-spawning-a-worker.patch create mode 100644 backport-udev-remove-run-udev-queue-in-on_post.patch create mode 100644 backport-udev-rename-is_device_busy-event_is_blocked.patch create mode 100644 backport-udev-requeue-event-when-the-corresponding-block-device-is.patch create mode 100644 backport-udev-skip-event-when-its-dependency-cannot-be-checked.patch create mode 100644 backport-udev-split-worker_lock_block_device-into-two.patch create mode 100644 backport-udev-store-action-in-struct-Event.patch create mode 100644 backport-udev-update-comment-and-log-messages.patch create mode 100644 backport-udev-update-log-message-to-clarify-that-the-error-is-ignored.patch diff --git a/Retry-to-handle-the-uevent-when-worker-is-terminated.patch b/Retry-to-handle-the-uevent-when-worker-is-terminated.patch index 4d15ad5..39fa1d2 100644 --- a/Retry-to-handle-the-uevent-when-worker-is-terminated.patch +++ b/Retry-to-handle-the-uevent-when-worker-is-terminated.patch @@ -5,32 +5,32 @@ Subject: [PATCH] Retry to handle the uevent when worker is terminated abnormal When processing uevent events fails, retry it. --- - src/udev/udevd.c | 41 ++++++++++++++++++++++++++++++++++++----- - 1 file changed, 36 insertions(+), 5 deletions(-) + src/udev/udevd.c | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/udev/udevd.c b/src/udev/udevd.c -index eb94ed3..5b743ad 100644 +index 75e2086..023fe55 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c -@@ -70,6 +70,7 @@ +@@ -69,6 +69,7 @@ #include "version.h" #define WORKER_NUM_MAX 2048U +#define UEVENT_MAX_RETRY_TIMES 3 + #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; -@@ -114,6 +115,7 @@ typedef struct Event { +@@ -123,6 +124,7 @@ typedef struct Event { Manager *manager; Worker *worker; EventState state; + int retry; sd_device *dev; - sd_device *dev_kernel; /* clone of originally received device */ -@@ -148,6 +150,32 @@ typedef struct Worker { - typedef struct WorkerMessage { - } WorkerMessage; + +@@ -166,6 +168,32 @@ typedef enum EventResult { + _EVENT_RESULT_INVALID = -EINVAL, + } EventResult; +static bool event_retry(Event *event) { + if (!event) @@ -58,36 +58,30 @@ index eb94ed3..5b743ad 100644 + return true; +} + - static void event_free(Event *event) { + static Event *event_free(Event *event) { if (!event) - return; -@@ -638,6 +666,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { - .dev_kernel = TAKE_PTR(clone), + return NULL; +@@ -1118,6 +1146,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { .seqnum = seqnum, + .action = action, .state = EVENT_QUEUED, + .retry = UEVENT_MAX_RETRY_TIMES, }; if (LIST_IS_EMPTY(manager->events)) { -@@ -1314,11 +1343,13 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi +@@ -1547,8 +1576,10 @@ 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 without amending it */ -- r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); -- if (r < 0) -- log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); +- /* Forward kernel event to libudev listeners */ +- device_broadcast(manager->monitor, worker->event->dev); + if (event_retry(worker->event) == false) { -+ if (manager->monitor) { -+ /* forward kernel event without amending it */ -+ r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); -+ if (r < 0) -+ log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); -+ } - } ++ /* Forward kernel event to libudev listeners */ ++ device_broadcast(manager->monitor, worker->event->dev); ++ } } + worker_free(worker); -- -2.23.0 +2.33.0 diff --git a/backport-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch b/backport-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch new file mode 100644 index 0000000..4332d61 --- /dev/null +++ b/backport-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch @@ -0,0 +1,75 @@ +From 3f2ada89f3a277625390bf6789ccd4e7aba08743 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 24 Mar 2022 13:50:50 +0100 +Subject: [PATCH] errno-util: add ERRNO_IS_DEVICE_ABSENT() macro + +Inspired by: https://github.com/systemd/systemd/pull/22717#discussion_r834254495 + +Reference:https://github.com/systemd/systemd/commit/3f2ada89f3a277625390bf6789ccd4e7aba08743 +Conflict:discard change on homework-luks.c + +--- + src/basic/errno-util.h | 10 +++++++++- + src/rfkill/rfkill.c | 2 +- + src/udev/udev-builtin-btrfs.c | 3 ++- + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h +index 09abf0b7512d..648de50eb497 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/rfkill/rfkill.c b/src/rfkill/rfkill.c +index 656afa06ac8b..a833771d97f2 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 a0093cb42347..f9d4f1dd4ef4 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. */ + diff --git a/backport-event-util-introduce-event_reset_time_relative.patch b/backport-event-util-introduce-event_reset_time_relative.patch new file mode 100644 index 0000000..5279c50 --- /dev/null +++ b/backport-event-util-introduce-event_reset_time_relative.patch @@ -0,0 +1,87 @@ +From 52c3bc708fb6a3eb68a3cac780b49192818bd409 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 13 Nov 2021 10:33:08 +0900 +Subject: [PATCH] event-util: introduce event_reset_time_relative() + +Reference:https://github.com/systemd/systemd/commit/52c3bc708fb6a3eb68a3cac780b49192818bd409 +Conflict:NA + +--- + src/libsystemd/sd-event/event-util.c | 24 ++++++++++++++++++++++++ + src/libsystemd/sd-event/event-util.h | 26 ++++++++++++++++++++++---- + 2 files changed, 46 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-event/event-util.c b/src/libsystemd/sd-event/event-util.c +index 132796f..0e53406 100644 +--- a/src/libsystemd/sd-event/event-util.c ++++ b/src/libsystemd/sd-event/event-util.c +@@ -84,6 +84,30 @@ int event_reset_time( + return created; + } + ++int event_reset_time_relative( ++ sd_event *e, ++ sd_event_source **s, ++ clockid_t clock, ++ uint64_t usec, ++ uint64_t accuracy, ++ sd_event_time_handler_t callback, ++ void *userdata, ++ int64_t priority, ++ const char *description, ++ bool force_reset) { ++ ++ usec_t usec_now; ++ int r; ++ ++ assert(e); ++ ++ r = sd_event_now(e, clock, &usec_now); ++ if (r < 0) ++ return log_debug_errno(r, "sd-event: Failed to get the current time: %m"); ++ ++ return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset); ++} ++ + int event_source_disable(sd_event_source *s) { + if (!s) + return 0; +diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h +index c8f97bc..64a4199 100644 +--- a/src/libsystemd/sd-event/event-util.h ++++ b/src/libsystemd/sd-event/event-util.h +@@ -5,9 +5,27 @@ + + #include "sd-event.h" + +-int event_reset_time(sd_event *e, sd_event_source **s, +- clockid_t clock, uint64_t usec, uint64_t accuracy, +- sd_event_time_handler_t callback, void *userdata, +- int64_t priority, const char *description, bool force_reset); ++int event_reset_time( ++ sd_event *e, ++ sd_event_source **s, ++ clockid_t clock, ++ uint64_t usec, ++ uint64_t accuracy, ++ sd_event_time_handler_t callback, ++ void *userdata, ++ int64_t priority, ++ const char *description, ++ bool force_reset); ++int event_reset_time_relative( ++ sd_event *e, ++ sd_event_source **s, ++ clockid_t clock, ++ uint64_t usec, ++ uint64_t accuracy, ++ sd_event_time_handler_t callback, ++ void *userdata, ++ int64_t priority, ++ const char *description, ++ bool force_reset); + int event_source_disable(sd_event_source *s); + int event_source_is_enabled(sd_event_source *s); +-- +2.33.0 + diff --git a/backport-list-introduce-LIST_FOREACH_BACKWARDS-macro-and-drop.patch b/backport-list-introduce-LIST_FOREACH_BACKWARDS-macro-and-drop.patch new file mode 100644 index 0000000..7766b87 --- /dev/null +++ b/backport-list-introduce-LIST_FOREACH_BACKWARDS-macro-and-drop.patch @@ -0,0 +1,102 @@ +From bd335c961fed6982e5ad8c2322414ff33a46e92e Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 16:12:06 +0900 +Subject: [PATCH] list: introduce LIST_FOREACH_BACKWARDS() macro and drop + LIST_FOREACH_AFTER/BEFORE() + +Reference:https://github.com/systemd/systemd/commit/bd335c961fed6982e5ad8c2322414ff33a46e92e +Conflict:NA + +--- + src/basic/list.h | 7 ++----- + src/core/device.c | 8 ++++---- + src/core/swap.c | 4 ++-- + src/udev/udev-rules.c | 2 +- + 4 files changed, 9 insertions(+), 12 deletions(-) + +diff --git a/src/basic/list.h b/src/basic/list.h +index 256b718..e488fff 100644 +--- a/src/basic/list.h ++++ b/src/basic/list.h +@@ -142,11 +142,8 @@ + #define LIST_FOREACH_SAFE(name,i,n,head) \ + for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) + +-#define LIST_FOREACH_BEFORE(name,i,p) \ +- for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) +- +-#define LIST_FOREACH_AFTER(name,i,p) \ +- for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) ++#define LIST_FOREACH_BACKWARDS(name,i,p) \ ++ for ((i) = (p); (i); (i) = (i)->name##_prev) + + /* Iterate through all the members of the list p is included in, but skip over p */ + #define LIST_FOREACH_OTHERS(name,i,p) \ +diff --git a/src/core/device.c b/src/core/device.c +index c24bc12..06270e7 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -785,11 +785,11 @@ static Unit *device_following(Unit *u) { + return NULL; + + /* Make everybody follow the unit that's named after the sysfs path */ +- LIST_FOREACH_AFTER(same_sysfs, other, d) ++ LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) + if (startswith(UNIT(other)->id, "sys-")) + return UNIT(other); + +- LIST_FOREACH_BEFORE(same_sysfs, other, d) { ++ LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) { + if (startswith(UNIT(other)->id, "sys-")) + return UNIT(other); + +@@ -816,13 +816,13 @@ static int device_following_set(Unit *u, Set **_set) { + if (!set) + return -ENOMEM; + +- LIST_FOREACH_AFTER(same_sysfs, other, d) { ++ LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) { + r = set_put(set, other); + if (r < 0) + return r; + } + +- LIST_FOREACH_BEFORE(same_sysfs, other, d) { ++ LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) { + r = set_put(set, other); + if (r < 0) + return r; +diff --git a/src/core/swap.c b/src/core/swap.c +index 83e77d2..7a9628e 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -1323,11 +1323,11 @@ static Unit *swap_following(Unit *u) { + if (streq_ptr(s->what, s->devnode)) + return NULL; + +- LIST_FOREACH_AFTER(same_devnode, other, s) ++ LIST_FOREACH(same_devnode, other, s->same_devnode_next) + if (streq_ptr(other->what, other->devnode)) + return UNIT(other); + +- LIST_FOREACH_BEFORE(same_devnode, other, s) { ++ LIST_FOREACH_BACKWARDS(same_devnode, other, s->same_devnode_prev) { + if (streq_ptr(other->what, other->devnode)) + return UNIT(other); + +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index bf997fc..5e8dad2 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -1154,7 +1154,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) { + if (!FLAGS_SET(line->type, LINE_HAS_GOTO)) + continue; + +- LIST_FOREACH_AFTER(rule_lines, i, line) ++ LIST_FOREACH(rule_lines, i, line->rule_lines_next) + if (streq_ptr(i->label, line->goto_label)) { + line->goto_line = i; + break; +-- +2.33.0 + diff --git a/backport-udev-add-usec_add-at-one-more-place.patch b/backport-udev-add-usec_add-at-one-more-place.patch new file mode 100644 index 0000000..7031856 --- /dev/null +++ b/backport-udev-add-usec_add-at-one-more-place.patch @@ -0,0 +1,28 @@ +From 92fd70addf25d4f301ba43ca3e6ede96d9564295 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 15:41:20 +0900 +Subject: [PATCH] udev: add usec_add() at one more place + +Reference:https://github.com/systemd/systemd/commit/92fd70addf25d4f301ba43ca3e6ede96d9564295 +Conflict:NA + +--- + 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 279b409..2179825 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -893,7 +893,7 @@ static int event_queue_start(Manager *manager) { + assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0); + /* check for changed config, every 3 seconds at most */ + if (manager->last_usec == 0 || +- usec - manager->last_usec > 3 * USEC_PER_SEC) { ++ usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) { + if (udev_rules_check_timestamp(manager->rules) || + udev_builtin_validate()) + manager_reload(manager); +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-also-rename-struct-udev_ctrl-UdevCtrl.patch b/backport-udev-also-rename-struct-udev_ctrl-UdevCtrl.patch new file mode 100644 index 0000000..5013b29 --- /dev/null +++ b/backport-udev-also-rename-struct-udev_ctrl-UdevCtrl.patch @@ -0,0 +1,350 @@ +From e0d61dac3324abc90f61014a98b1bc5a9a1f60ae Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 16 Jun 2021 19:18:56 +0900 +Subject: [PATCH] udev: also rename struct udev_ctrl -> UdevCtrl + +Reference:https://github.com/systemd/systemd/commit/e0d61dac3324abc90f61014a98b1bc5a9a1f60ae +Conflict:NA + +--- + src/udev/udev-ctrl.c | 52 ++++++++++++++++++------------------ + src/udev/udev-ctrl.h | 54 +++++++++++++++++++------------------- + src/udev/udevadm-control.c | 2 +- + src/udev/udevadm-settle.c | 2 +- + src/udev/udevadm-trigger.c | 2 +- + src/udev/udevd.c | 4 +-- + 6 files changed, 58 insertions(+), 58 deletions(-) + +diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c +index 3d563547190c..00279ba3d87d 100644 +--- a/src/udev/udev-ctrl.c ++++ b/src/udev/udev-ctrl.c +@@ -23,14 +23,14 @@ + /* wire protocol magic must match */ + #define UDEV_CTRL_MAGIC 0xdead1dea + +-struct udev_ctrl_msg_wire { ++typedef struct UdevCtrlMessageWire { + char version[16]; + unsigned magic; +- enum udev_ctrl_msg_type type; +- union udev_ctrl_msg_value value; +-}; ++ UdevCtrlMessageType type; ++ UdevCtrlMessageValue value; ++} UdevCtrlMessageWire; + +-struct udev_ctrl { ++struct UdevCtrl { + unsigned n_ref; + int sock; + int sock_connect; +@@ -47,9 +47,9 @@ struct udev_ctrl { + void *userdata; + }; + +-int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { ++int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) { + _cleanup_close_ int sock = -1; +- struct udev_ctrl *uctrl; ++ UdevCtrl *uctrl; + + assert(ret); + +@@ -59,11 +59,11 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { + return log_error_errno(errno, "Failed to create socket: %m"); + } + +- uctrl = new(struct udev_ctrl, 1); ++ uctrl = new(UdevCtrl, 1); + if (!uctrl) + return -ENOMEM; + +- *uctrl = (struct udev_ctrl) { ++ *uctrl = (UdevCtrl) { + .n_ref = 1, + .sock = fd >= 0 ? fd : TAKE_FD(sock), + .sock_connect = -1, +@@ -81,7 +81,7 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { + return 0; + } + +-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { ++int udev_ctrl_enable_receiving(UdevCtrl *uctrl) { + int r; + + assert(uctrl); +@@ -107,7 +107,7 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { + return 0; + } + +-static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) { ++static void udev_ctrl_disconnect(UdevCtrl *uctrl) { + if (!uctrl) + return; + +@@ -115,7 +115,7 @@ static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) { + uctrl->sock_connect = safe_close(uctrl->sock_connect); + } + +-static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) { ++static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) { + assert(uctrl); + + udev_ctrl_disconnect(uctrl); +@@ -127,9 +127,9 @@ static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) { + return mfree(uctrl); + } + +-DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free); ++DEFINE_TRIVIAL_REF_UNREF_FUNC(UdevCtrl, udev_ctrl, udev_ctrl_free); + +-int udev_ctrl_cleanup(struct udev_ctrl *uctrl) { ++int udev_ctrl_cleanup(UdevCtrl *uctrl) { + if (!uctrl) + return 0; + if (uctrl->cleanup_socket) +@@ -137,7 +137,7 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) { + return 0; + } + +-int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) { ++int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event) { + int r; + + assert_return(uctrl, -EINVAL); +@@ -154,25 +154,25 @@ int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) { + return 0; + } + +-sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) { ++sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl) { + assert(uctrl); + + return uctrl->event_source; + } + +-static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) { ++static void udev_ctrl_disconnect_and_listen_again(UdevCtrl *uctrl) { + udev_ctrl_disconnect(uctrl); + udev_ctrl_unref(uctrl); + (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON); + /* We don't return NULL here because uctrl is not freed */ + } + +-DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct udev_ctrl*, udev_ctrl_disconnect_and_listen_again, NULL); ++DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UdevCtrl*, udev_ctrl_disconnect_and_listen_again, NULL); + + static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +- _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL; +- struct udev_ctrl_msg_wire msg_wire; +- struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire)); ++ _cleanup_(udev_ctrl_disconnect_and_listen_againp) UdevCtrl *uctrl = NULL; ++ UdevCtrlMessageWire msg_wire; ++ struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(UdevCtrlMessageWire)); + CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control; + struct msghdr smsg = { + .msg_iov = &iov, +@@ -235,7 +235,7 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32 + } + + static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +- struct udev_ctrl *uctrl = userdata; ++ UdevCtrl *uctrl = userdata; + _cleanup_close_ int sock = -1; + struct ucred ucred; + int r; +@@ -282,7 +282,7 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, + return 0; + } + +-int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) { ++int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata) { + int r; + + assert(uctrl); +@@ -309,8 +309,8 @@ int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void + return 0; + } + +-int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) { +- struct udev_ctrl_msg_wire ctrl_msg_wire = { ++int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf) { ++ UdevCtrlMessageWire ctrl_msg_wire = { + .version = "udev-" STRINGIFY(PROJECT_VERSION), + .magic = UDEV_CTRL_MAGIC, + .type = type, +@@ -339,7 +339,7 @@ int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int in + return 0; + } + +-int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) { ++int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout) { + _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL; + int r; + +diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h +index 680fbf7bff1d..ca80c2aa4e0d 100644 +--- a/src/udev/udev-ctrl.h ++++ b/src/udev/udev-ctrl.h +@@ -6,9 +6,9 @@ + #include "macro.h" + #include "time-util.h" + +-struct udev_ctrl; ++typedef struct UdevCtrl UdevCtrl; + +-enum udev_ctrl_msg_type { ++typedef enum UdevCtrlMessageType { + _UDEV_CTRL_END_MESSAGES, + UDEV_CTRL_SET_LOG_LEVEL, + UDEV_CTRL_STOP_EXEC_QUEUE, +@@ -18,62 +18,62 @@ enum udev_ctrl_msg_type { + UDEV_CTRL_SET_CHILDREN_MAX, + UDEV_CTRL_PING, + UDEV_CTRL_EXIT, +-}; ++} UdevCtrlMessageType; + +-union udev_ctrl_msg_value { ++typedef union UdevCtrlMessageValue { + int intval; + char buf[256]; +-}; ++} UdevCtrlMessageValue; + +-typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type, +- const union udev_ctrl_msg_value *value, void *userdata); ++typedef int (*udev_ctrl_handler_t)(UdevCtrl *udev_ctrl, UdevCtrlMessageType type, ++ const UdevCtrlMessageValue *value, void *userdata); + +-int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd); +-static inline int udev_ctrl_new(struct udev_ctrl **ret) { ++int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd); ++static inline int udev_ctrl_new(UdevCtrl **ret) { + return udev_ctrl_new_from_fd(ret, -1); + } + +-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); +-struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl); +-struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); +-int udev_ctrl_cleanup(struct udev_ctrl *uctrl); +-int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event); +-int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata); +-sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl); ++int udev_ctrl_enable_receiving(UdevCtrl *uctrl); ++UdevCtrl *udev_ctrl_ref(UdevCtrl *uctrl); ++UdevCtrl *udev_ctrl_unref(UdevCtrl *uctrl); ++int udev_ctrl_cleanup(UdevCtrl *uctrl); ++int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event); ++int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata); ++sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl); + +-int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout); ++int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout); + +-int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf); +-static inline int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority) { ++int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf); ++static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) { + return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL); + } + +-static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) { ++static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL); + } + +-static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) { ++static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL); + } + +-static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) { ++static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL); + } + +-static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) { ++static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) { + return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key); + } + +-static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) { ++static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) { + return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL); + } + +-static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) { ++static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL); + } + +-static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) { ++static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL); + } + +-DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); ++DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref); +diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c +index 20820dd64723..06c61e5c07c6 100644 +--- a/src/udev/udevadm-control.c ++++ b/src/udev/udevadm-control.c +@@ -48,7 +48,7 @@ static int help(void) { + } + + int control_main(int argc, char *argv[], void *userdata) { +- _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; ++ _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; + usec_t timeout = 60 * USEC_PER_SEC; + int c, r; + +diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c +index 84b4f9ca4588..6da9439bd28a 100644 +--- a/src/udev/udevadm-settle.c ++++ b/src/udev/udevadm-settle.c +@@ -176,7 +176,7 @@ int settle_main(int argc, char *argv[], void *userdata) { + + /* guarantee that the udev daemon isn't pre-processing */ + if (getuid() == 0) { +- _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; ++ _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; + + if (udev_ctrl_new(&uctrl) >= 0) { + r = udev_ctrl_send_ping(uctrl); +diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c +index 8acf3d9b1189..a24073fb7341 100644 +--- a/src/udev/udevadm-trigger.c ++++ b/src/udev/udevadm-trigger.c +@@ -421,7 +421,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { + } + + if (ping) { +- _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; ++ _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; + + r = udev_ctrl_new(&uctrl); + if (r < 0) +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 6baedd2f2e69..a35b095dd141 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -94,7 +94,7 @@ typedef struct Manager { + sd_netlink *rtnl; + + sd_device_monitor *monitor; +- struct udev_ctrl *ctrl; ++ UdevCtrl *ctrl; + int worker_watch[2]; + + /* used by udev-watch */ +@@ -1067,7 +1067,7 @@ static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) + } + + /* receive the udevd message from userspace */ +-static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) { ++static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) { + Manager *manager = userdata; + int r; + diff --git a/backport-udev-assume-block-device-is-not-locked-when-a-new-event-is-queued.patch b/backport-udev-assume-block-device-is-not-locked-when-a-new-event-is-queued.patch new file mode 100644 index 0000000..9790e2d --- /dev/null +++ b/backport-udev-assume-block-device-is-not-locked-when-a-new-event-is-queued.patch @@ -0,0 +1,81 @@ +From 82a5de9fd289e1d9b109528bcdddb74534e1a4bf Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:56:58 +0900 +Subject: [PATCH] udev: assume block device is not locked when a new event is + queued + +Then, hopefully, previously requeued events are processed earlier. + +Reference:https://github.com/systemd/systemd/commit/82a5de9fd289e1d9b109528bcdddb74534e1a4bf +Conflict:adaption + +--- + 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 eebb2f8..e0f70cc 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1033,6 +1033,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; ++ Event * event; ++ 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; ++ ++ LIST_FOREACH(event, event, 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; +@@ -1095,6 +1129,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); + +@@ -1426,8 +1462,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(). */ diff --git a/backport-udev-assume-there-is-no-blocker-when-failed-to-check-event.patch b/backport-udev-assume-there-is-no-blocker-when-failed-to-check-event.patch new file mode 100644 index 0000000..ad64bd4 --- /dev/null +++ b/backport-udev-assume-there-is-no-blocker-when-failed-to-check-event.patch @@ -0,0 +1,54 @@ +From 2d40f02ee4317233365f53c85234be3af6b000a6 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 12 Mar 2022 20:57:15 +0900 +Subject: [PATCH] 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. + +Reference:https://github.com/systemd/systemd/commit/2d40f02ee4317233365f53c85234be3af6b000a6 +Conflict:NA + +--- + 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 f1f864a4610c..8c690357b8d3 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -951,24 +951,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; + } + + \ No newline at end of file diff --git a/backport-udev-certainly-restart-event-for-previously-locked-device.patch b/backport-udev-certainly-restart-event-for-previously-locked-device.patch new file mode 100644 index 0000000..83682e4 --- /dev/null +++ b/backport-udev-certainly-restart-event-for-previously-locked-device.patch @@ -0,0 +1,86 @@ +From 4f294ffdf18ab9f187400dbbab593a980e60be89 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 26 Aug 2022 00:16:17 +0900 +Subject: [PATCH] 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. + +Reference:https://github.com/systemd/systemd/commit/4f294ffdf18ab9f187400dbbab593a980e60be89 +Conflict:adaption because previous commits in https://github.com/systemd/systemd/pull/23088 are not introduced + +--- + src/udev/udevd.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index a979d43..b15a9d4 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -129,8 +129,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; +@@ -172,6 +175,7 @@ static Event *event_free(Event *event) { + LIST_REMOVE(event, event->manager->events, event); + sd_device_unref(event->dev); + ++ sd_event_source_unref(event->retry_event_source); + sd_event_source_unref(event->timeout_warning_event); + sd_event_source_unref(event->timeout_event); + +@@ -749,6 +753,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) +@@ -995,6 +1001,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; +@@ -1025,6 +1036,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.33.0 + \ No newline at end of file diff --git a/backport-udev-do-not-try-to-find-blocker-again-when-no-blocker-found.patch b/backport-udev-do-not-try-to-find-blocker-again-when-no-blocker-found.patch new file mode 100644 index 0000000..7a122ff --- /dev/null +++ b/backport-udev-do-not-try-to-find-blocker-again-when-no-blocker-found.patch @@ -0,0 +1,91 @@ +From 044ac33c35ab1aeb35fc8b84462a9549cbbac294 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 16:57:32 +0900 +Subject: [PATCH] udev: do not try to find blocker again when no blocker found + previously + +Reference:https://github.com/systemd/systemd/commit/044ac33c35ab1aeb35fc8b84462a9549cbbac294 +Conflict:NA + +--- + src/udev/udevd.c | 45 +++++++++++++++++++++++++++++++++++---------- + 1 file changed, 35 insertions(+), 10 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 20bd556..be2c3ee 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -783,6 +783,35 @@ static int event_is_blocked(Event *event) { + + /* lookup event for identical, parent, child device */ + ++ assert(event); ++ assert(event->manager); ++ assert(event->blocker_seqnum <= event->seqnum); ++ ++ if (event->blocker_seqnum == event->seqnum) ++ /* we have checked previously and no blocker found */ ++ return false; ++ ++ LIST_FOREACH(event, loop_event, event->manager->events) { ++ /* we already found a later event, earlier cannot block us, no need to check again */ ++ if (loop_event->seqnum < event->blocker_seqnum) ++ continue; ++ ++ /* event we checked earlier still exists, no need to check again */ ++ if (loop_event->seqnum == event->blocker_seqnum) ++ return true; ++ ++ /* found ourself, no later event can block us */ ++ if (loop_event->seqnum >= event->seqnum) ++ goto no_blocker; ++ ++ /* found event we have not checked */ ++ break; ++ } ++ ++ assert(loop_event); ++ assert(loop_event->seqnum > event->blocker_seqnum && ++ loop_event->seqnum < event->seqnum); ++ + r = sd_device_get_subsystem(event->dev, &subsystem); + if (r < 0) + return r; +@@ -808,21 +837,13 @@ static int event_is_blocked(Event *event) { + return r; + + /* check if queue contains events we depend on */ +- LIST_FOREACH(event, loop_event, event->manager->events) { ++ LIST_FOREACH(event, loop_event, loop_event) { + size_t loop_devpath_len, common; + const char *loop_devpath; + +- /* we already found a later event, earlier cannot block us, no need to check again */ +- if (loop_event->seqnum < event->blocker_seqnum) +- continue; +- +- /* event we checked earlier still exists, no need to check again */ +- if (loop_event->seqnum == event->blocker_seqnum) +- return true; +- + /* found ourself, no later event can block us */ + if (loop_event->seqnum >= event->seqnum) +- return false; ++ goto no_blocker; + + /* check major/minor */ + if (major(devnum) != 0) { +@@ -882,6 +903,10 @@ static int event_is_blocked(Event *event) { + + event->blocker_seqnum = loop_event->seqnum; + return true; ++ ++no_blocker: ++ event->blocker_seqnum = event->seqnum; ++ return false; + } + + static int event_queue_start(Manager *manager) { +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-do-not-try-to-process-events-if-there-is-no-free-worker.patch b/backport-udev-do-not-try-to-process-events-if-there-is-no-free-worker.patch new file mode 100644 index 0000000..b89df06 --- /dev/null +++ b/backport-udev-do-not-try-to-process-events-if-there-is-no-free-worker.patch @@ -0,0 +1,28 @@ +From 5f4bca9dccdd9e9a888587c6224b08ae5fbe3bdb Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 15:51:34 +0900 +Subject: [PATCH] udev: do not try to process events if there is no free worker + +Reference:https://github.com/systemd/systemd/commit/5f4bca9dccdd9e9a888587c6224b08ae5fbe3bdb +Conflict:NA + +--- + 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 7f41336..e99c2c0 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -927,7 +927,7 @@ static int event_queue_start(Manager *manager) { + continue; + + r = event_run(event); +- if (r < 0) ++ if (r <= 0) + return r; + } + +-- +2.33.0 + diff --git a/backport-udev-drop-unnecessary-calls-of-event_queue_start.patch b/backport-udev-drop-unnecessary-calls-of-event_queue_start.patch new file mode 100644 index 0000000..d9766db --- /dev/null +++ b/backport-udev-drop-unnecessary-calls-of-event_queue_start.patch @@ -0,0 +1,80 @@ +From 5fab6b7b18d0158c005a5bcf096face23377af72 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 26 Aug 2022 00:34:15 +0900 +Subject: [PATCH] udev: drop unnecessary calls of event_queue_start() + +As the subsequent call of on_post() will call it if necessary. + +This also drop unnecessary call of event_source_disable() for killing +idle workers, as the event source is disabled in event_queue_start(). + +Reference:https://github.com/systemd/systemd/commit/5fab6b7b18d0158c005a5bcf096face23377af72 +Conflict:adaption + +--- + src/udev/udevd.c | 21 --------------------- + 1 file changed, 21 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index b15a9d4..75e2086 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1151,9 +1151,6 @@ static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) + + (void) event_queue_assume_block_device_unlocked(manager, dev); + +- /* we have fresh events, try to schedule them */ +- event_queue_start(manager); +- + return 1; + } + +@@ -1220,9 +1217,6 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat + event_free(worker->event); + } + +- /* we have free workers, try to schedule events */ +- event_queue_start(manager); +- + return 1; + } + +@@ -1456,10 +1450,6 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda + + assert(manager); + +- r = event_source_disable(manager->kill_workers_event); +- if (r < 0) +- log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m"); +- + l = read(fd, &buffer, sizeof(buffer)); + if (l < 0) { + if (IN_SET(errno, EAGAIN, EINTR)) +@@ -1516,7 +1506,6 @@ static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void + + static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + Manager *manager = userdata; +- int r; + + assert(manager); + +@@ -1565,16 +1554,6 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi + worker_free(worker); + } + +- /* we can start new workers, try to schedule events */ +- event_queue_start(manager); +- +- /* Disable unnecessary cleanup event */ +- if (hashmap_isempty(manager->workers)) { +- r = event_source_disable(manager->kill_workers_event); +- if (r < 0) +- log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m"); +- } +- + return 1; + } + +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-drop-unnecessary-clone-of-received-sd-device-object.patch b/backport-udev-drop-unnecessary-clone-of-received-sd-device-object.patch new file mode 100644 index 0000000..3a33f70 --- /dev/null +++ b/backport-udev-drop-unnecessary-clone-of-received-sd-device-object.patch @@ -0,0 +1,85 @@ +From c9473aaa5b69c47edab365b46abee6e9ab5b18dc Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 01:13:39 +0900 +Subject: [PATCH] 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. + +Reference:https://github.com/systemd/systemd/commit/c9473aaa5b69c47edab365b46abee6e9ab5b18dc +Conflict:adaption + +--- + src/udev/udevd.c | 21 ++++----------------- + 1 file changed, 4 insertions(+), 17 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 108142e9c619..05397df7a429 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -124,7 +124,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; +@@ -163,7 +162,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); +@@ -973,9 +971,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); +@@ -989,15 +986,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; +@@ -1005,7 +993,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, + }; +@@ -1440,10 +1427,10 @@ 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 unchanged */ +- 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_warning_errno(worker->event->dev_kernel, r, ++ log_device_warning_errno(worker->event->dev, r, + "Failed to broadcast failed event to libudev listeners, ignoring: %m"); + } + } + \ No newline at end of file diff --git a/backport-udev-fix-inversed-inequality-for-timeout-of-retrying-event.patch b/backport-udev-fix-inversed-inequality-for-timeout-of-retrying-event.patch new file mode 100644 index 0000000..b8c6fbe --- /dev/null +++ b/backport-udev-fix-inversed-inequality-for-timeout-of-retrying-event.patch @@ -0,0 +1,27 @@ +From 400e3d21f8cae53a8ba9f9567f244fbf6f3e076c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 19 Aug 2022 21:25:03 +0900 +Subject: [PATCH] udev: fix inversed inequality for timeout of retrying event + +Follow-up for 5d354e525a56955ae7f68062e283dda85ab07794. + +Reference:https://github.com/systemd/systemd/commit/400e3d21f8cae53a8ba9f9567f244fbf6f3e076c +Conflict:NA + +--- + 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 a6926bbfb71d..01162bc7b601 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -898,7 +898,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; + } + diff --git a/backport-udev-introduce-device_broadcast_helper_function.patch b/backport-udev-introduce-device_broadcast_helper_function.patch new file mode 100644 index 0000000..661dd74 --- /dev/null +++ b/backport-udev-introduce-device_broadcast_helper_function.patch @@ -0,0 +1,66 @@ +From c17ab900cbb47f0c136b141bb83557f112501707 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:33:55 +0900 +Subject: [PATCH] udev: introduce device_broadcast() helper function + +Reference:https://github.com/systemd/systemd/commit/c17ab900cbb47f0c136b141bb83557f112501707 +Conflict:NA + +--- + 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 05397df7a429..53728c9f7971 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -344,6 +344,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 = {}; + +@@ -558,9 +573,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 */ +@@ -1426,13 +1439,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); + \ No newline at end of file diff --git a/backport-udev-make-event_free-return-NULL.patch b/backport-udev-make-event_free-return-NULL.patch new file mode 100644 index 0000000..662e6b7 --- /dev/null +++ b/backport-udev-make-event_free-return-NULL.patch @@ -0,0 +1,36 @@ +From 5393c52897ff5b57686c867fcab77f9740f4af24 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 15:21:27 +0900 +Subject: [PATCH] udev: make event_free() return NULL + +Reference:https://github.com/systemd/systemd/commit/5393c52897ff5b57686c867fcab77f9740f4af24.patch +Conflict:NA +--- + src/udev/udevd.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 34a5c9d5d8ee..bb7c0eabe420 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -152,9 +152,9 @@ typedef struct Worker { + typedef struct WorkerMessage { + } WorkerMessage; + +-static void event_free(Event *event) { ++static Event *event_free(Event *event) { + if (!event) +- return; ++ return NULL; + + assert(event->manager); + +@@ -174,7 +174,7 @@ static void event_free(Event *event) { + if (unlink("/run/udev/queue") < 0 && errno != ENOENT) + log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m"); + +- free(event); ++ return mfree(event); + } + + static void event_queue_cleanup(Manager *manager, EventState match_state) { diff --git a/backport-udev-make-event_queue_start-return-negative-errno-on-error.patch b/backport-udev-make-event_queue_start-return-negative-errno-on-error.patch new file mode 100644 index 0000000..73ee2f7 --- /dev/null +++ b/backport-udev-make-event_queue_start-return-negative-errno-on-error.patch @@ -0,0 +1,59 @@ +From 0744e74c526814e28f2fbcea128f40ed36341fcd Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 15:29:02 +0900 +Subject: [PATCH] udev: make event_queue_start() return negative errno on error + +Reference:https://github.com/systemd/systemd/commit/0744e74c526814e28f2fbcea128f40ed36341fcd +Conflict:NA + +--- + src/udev/udevd.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 1b1b126..279b409 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -879,7 +879,7 @@ set_delaying_seqnum: + return true; + } + +-static void event_queue_start(Manager *manager) { ++static int event_queue_start(Manager *manager) { + Event *event; + usec_t usec; + int r; +@@ -888,7 +888,7 @@ static void event_queue_start(Manager *manager) { + + if (LIST_IS_EMPTY(manager->events) || + manager->exit || manager->stop_exec_queue) +- return; ++ return 0; + + assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0); + /* check for changed config, every 3 seconds at most */ +@@ -909,10 +909,8 @@ static void event_queue_start(Manager *manager) { + + if (!manager->rules) { + r = udev_rules_load(&manager->rules, arg_resolve_name_timing); +- if (r < 0) { +- log_warning_errno(r, "Failed to read udev rules: %m"); +- return; +- } ++ if (r < 0) ++ return log_warning_errno(r, "Failed to read udev rules: %m"); + } + + LIST_FOREACH(event, event, manager->events) { +@@ -925,6 +923,8 @@ static void event_queue_start(Manager *manager) { + + event_run(manager, event); + } ++ ++ return 0; + } + + static int event_queue_insert(Manager *manager, sd_device *dev) { +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-move-several-functions.patch b/backport-udev-move-several-functions.patch new file mode 100644 index 0000000..7d69b04 --- /dev/null +++ b/backport-udev-move-several-functions.patch @@ -0,0 +1,544 @@ +From 419ec631358c8bf7013db01ae42763e6971d8765 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 15:14:59 +0900 +Subject: [PATCH] udev: move several functions + +No functional chage. + +Reference:https://github.com/systemd/systemd/commit/419ec631358c8bf7013db01ae42763e6971d8765 +Conflict:adaption + +--- + src/udev/udevd.c | 434 +++++++++++++++++++++++------------------------ + 1 file changed, 216 insertions(+), 218 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 9c9487f..018809e 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -134,8 +134,6 @@ typedef struct Event { + LIST_FIELDS(Event, event); + } Event; + +-static void event_queue_cleanup(Manager *manager, EventState match_state); +- + typedef enum WorkerState { + WORKER_UNDEF, + WORKER_RUNNING, +@@ -181,6 +179,17 @@ static void event_free(Event *event) { + free(event); + } + ++static void event_queue_cleanup(Manager *manager, EventState match_state) { ++ Event *event, *tmp; ++ ++ LIST_FOREACH_SAFE(event, event, tmp, manager->events) { ++ if (match_state != EVENT_UNDEF && match_state != event->state) ++ continue; ++ ++ event_free(event); ++ } ++} ++ + static Worker *worker_free(Worker *worker) { + if (!worker) + return NULL; +@@ -197,6 +206,48 @@ static Worker *worker_free(Worker *worker) { + DEFINE_TRIVIAL_CLEANUP_FUNC(Worker*, worker_free); + DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, Worker, worker_free); + ++static void manager_clear_for_worker(Manager *manager) { ++ assert(manager); ++ ++ manager->inotify_event = sd_event_source_unref(manager->inotify_event); ++ manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); ++ ++ manager->event = sd_event_unref(manager->event); ++ ++ manager->workers = hashmap_free(manager->workers); ++ event_queue_cleanup(manager, EVENT_UNDEF); ++ ++ manager->monitor = sd_device_monitor_unref(manager->monitor); ++ manager->ctrl = udev_ctrl_unref(manager->ctrl); ++ ++ manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]); ++} ++ ++static Manager* manager_free(Manager *manager) { ++ if (!manager) ++ return NULL; ++ ++ udev_builtin_exit(); ++ ++ if (manager->pid == getpid_cached()) ++ udev_ctrl_cleanup(manager->ctrl); ++ ++ manager_clear_for_worker(manager); ++ ++ sd_netlink_unref(manager->rtnl); ++ ++ hashmap_free_free_free(manager->properties); ++ udev_rules_free(manager->rules); ++ ++ safe_close(manager->inotify_fd); ++ safe_close_pair(manager->worker_watch); ++ ++ free(manager->cgroup); ++ return mfree(manager); ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); ++ + static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) { + _cleanup_(worker_freep) Worker *worker = NULL; + int r; +@@ -228,97 +279,75 @@ static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_ + return 0; + } + +-static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) { +- Event *event = userdata; +- +- assert(event); +- assert(event->worker); +- +- kill_and_sigcont(event->worker->pid, arg_timeout_signal); +- event->worker->state = WORKER_KILLED; +- +- log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum); +- +- return 1; +-} ++static void manager_kill_workers(Manager *manager, bool force) { ++ Worker *worker; + +-static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) { +- Event *event = userdata; ++ assert(manager); + +- assert(event); +- assert(event->worker); ++ HASHMAP_FOREACH(worker, manager->workers) { ++ if (worker->state == WORKER_KILLED) ++ continue; + +- log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum); ++ if (worker->state == WORKER_RUNNING && !force) { ++ worker->state = WORKER_KILLING; ++ continue; ++ } + +- return 1; ++ worker->state = WORKER_KILLED; ++ (void) kill(worker->pid, SIGTERM); ++ } + } + +-static void worker_attach_event(Worker *worker, Event *event) { +- sd_event *e; +- +- assert(worker); +- assert(worker->manager); +- assert(event); +- assert(!event->worker); +- assert(!worker->event); +- +- worker->state = WORKER_RUNNING; +- worker->event = event; +- event->state = EVENT_RUNNING; +- event->worker = worker; +- +- e = worker->manager->event; ++static void manager_exit(Manager *manager) { ++ assert(manager); + +- (void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC, +- udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC, +- on_event_timeout_warning, event); ++ manager->exit = true; + +- (void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC, +- arg_event_timeout_usec, USEC_PER_SEC, +- on_event_timeout, event); +-} ++ sd_notify(false, ++ "STOPPING=1\n" ++ "STATUS=Starting shutdown..."); + +-static void manager_clear_for_worker(Manager *manager) { +- assert(manager); ++ /* close sources of new events and discard buffered events */ ++ manager->ctrl = udev_ctrl_unref(manager->ctrl); + + manager->inotify_event = sd_event_source_unref(manager->inotify_event); +- manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); +- +- manager->event = sd_event_unref(manager->event); +- +- manager->workers = hashmap_free(manager->workers); +- event_queue_cleanup(manager, EVENT_UNDEF); ++ manager->inotify_fd = safe_close(manager->inotify_fd); + + manager->monitor = sd_device_monitor_unref(manager->monitor); +- manager->ctrl = udev_ctrl_unref(manager->ctrl); + +- manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]); ++ /* discard queued events and kill workers */ ++ event_queue_cleanup(manager, EVENT_QUEUED); ++ manager_kill_workers(manager, true); + } + +-static Manager* manager_free(Manager *manager) { +- if (!manager) +- return NULL; ++/* reload requested, HUP signal received, rules changed, builtin changed */ ++static void manager_reload(Manager *manager) { + +- udev_builtin_exit(); ++ assert(manager); + +- if (manager->pid == getpid_cached()) +- udev_ctrl_cleanup(manager->ctrl); ++ sd_notify(false, ++ "RELOADING=1\n" ++ "STATUS=Flushing configuration..."); + +- manager_clear_for_worker(manager); ++ manager_kill_workers(manager, false); ++ manager->rules = udev_rules_free(manager->rules); ++ udev_builtin_exit(); + +- sd_netlink_unref(manager->rtnl); ++ sd_notifyf(false, ++ "READY=1\n" ++ "STATUS=Processing with %u children at max", arg_children_max); ++} + +- hashmap_free_free_free(manager->properties); +- udev_rules_free(manager->rules); ++static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) { ++ Manager *manager = userdata; + +- safe_close(manager->inotify_fd); +- safe_close_pair(manager->worker_watch); ++ assert(manager); + +- free(manager->cgroup); +- return mfree(manager); +-} ++ log_debug("Cleanup idle workers"); ++ manager_kill_workers(manager, false); + +-DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); ++ return 1; ++} + + static int worker_send_message(int fd) { + WorkerMessage message = {}; +@@ -597,6 +626,56 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device + return 0; + } + ++static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) { ++ Event *event = userdata; ++ ++ assert(event); ++ assert(event->worker); ++ ++ kill_and_sigcont(event->worker->pid, arg_timeout_signal); ++ event->worker->state = WORKER_KILLED; ++ ++ log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum); ++ ++ return 1; ++} ++ ++static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) { ++ Event *event = userdata; ++ ++ assert(event); ++ assert(event->worker); ++ ++ log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum); ++ ++ return 1; ++} ++ ++static void worker_attach_event(Worker *worker, Event *event) { ++ sd_event *e; ++ ++ assert(worker); ++ assert(worker->manager); ++ assert(event); ++ assert(!event->worker); ++ assert(!worker->event); ++ ++ worker->state = WORKER_RUNNING; ++ worker->event = event; ++ event->state = EVENT_RUNNING; ++ event->worker = worker; ++ ++ e = worker->manager->event; ++ ++ (void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC, ++ udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC, ++ on_event_timeout_warning, event); ++ ++ (void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC, ++ arg_event_timeout_usec, USEC_PER_SEC, ++ on_event_timeout, event); ++} ++ + static int worker_spawn(Manager *manager, Event *event) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL; + Worker *worker; +@@ -689,76 +768,6 @@ static void event_run(Manager *manager, Event *event) { + worker_spawn(manager, event); + } + +-static int event_queue_insert(Manager *manager, sd_device *dev) { +- _cleanup_(sd_device_unrefp) sd_device *clone = NULL; +- Event *event; +- uint64_t seqnum; +- int r; +- +- assert(manager); +- assert(dev); +- +- /* only one process can add events to the queue */ +- assert(manager->pid == getpid_cached()); +- +- /* We only accepts devices received by device monitor. */ +- r = sd_device_get_seqnum(dev, &seqnum); +- 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; +- +- *event = (Event) { +- .manager = manager, +- .dev = sd_device_ref(dev), +- .dev_kernel = TAKE_PTR(clone), +- .seqnum = seqnum, +- .state = EVENT_QUEUED, +- }; +- +- if (LIST_IS_EMPTY(manager->events)) { +- r = touch("/run/udev/queue"); +- if (r < 0) +- log_warning_errno(r, "Failed to touch /run/udev/queue: %m"); +- } +- +- LIST_APPEND(event, manager->events, event); +- +- log_device_uevent(dev, "Device is queued"); +- +- return 0; +-} +- +-static void manager_kill_workers(Manager *manager, bool force) { +- Worker *worker; +- +- assert(manager); +- +- HASHMAP_FOREACH(worker, manager->workers) { +- if (worker->state == WORKER_KILLED) +- continue; +- +- if (worker->state == WORKER_RUNNING && !force) { +- worker->state = WORKER_KILLING; +- continue; +- } +- +- worker->state = WORKER_KILLED; +- (void) kill(worker->pid, SIGTERM); +- } +-} +- + /* lookup event for identical, parent, child device */ + static int is_device_busy(Manager *manager, Event *event) { + const char *subsystem, *devpath, *devpath_old = NULL; +@@ -870,57 +879,6 @@ set_delaying_seqnum: + return true; + } + +-static void manager_exit(Manager *manager) { +- assert(manager); +- +- manager->exit = true; +- +- sd_notify(false, +- "STOPPING=1\n" +- "STATUS=Starting shutdown..."); +- +- /* close sources of new events and discard buffered events */ +- manager->ctrl = udev_ctrl_unref(manager->ctrl); +- +- manager->inotify_event = sd_event_source_unref(manager->inotify_event); +- manager->inotify_fd = safe_close(manager->inotify_fd); +- +- manager->monitor = sd_device_monitor_unref(manager->monitor); +- +- /* discard queued events and kill workers */ +- event_queue_cleanup(manager, EVENT_QUEUED); +- manager_kill_workers(manager, true); +-} +- +-/* reload requested, HUP signal received, rules changed, builtin changed */ +-static void manager_reload(Manager *manager) { +- +- assert(manager); +- +- sd_notify(false, +- "RELOADING=1\n" +- "STATUS=Flushing configuration..."); +- +- manager_kill_workers(manager, false); +- manager->rules = udev_rules_free(manager->rules); +- udev_builtin_exit(); +- +- sd_notifyf(false, +- "READY=1\n" +- "STATUS=Processing with %u children at max", arg_children_max); +-} +- +-static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) { +- Manager *manager = userdata; +- +- assert(manager); +- +- log_debug("Cleanup idle workers"); +- manager_kill_workers(manager, false); +- +- return 1; +-} +- + static void event_queue_start(Manager *manager) { + Event *event; + usec_t usec; +@@ -969,15 +927,77 @@ static void event_queue_start(Manager *manager) { + } + } + +-static void event_queue_cleanup(Manager *manager, EventState match_state) { +- Event *event, *tmp; ++static int event_queue_insert(Manager *manager, sd_device *dev) { ++ _cleanup_(sd_device_unrefp) sd_device *clone = NULL; ++ Event *event; ++ uint64_t seqnum; ++ int r; + +- LIST_FOREACH_SAFE(event, event, tmp, manager->events) { +- if (match_state != EVENT_UNDEF && match_state != event->state) +- continue; ++ assert(manager); ++ assert(dev); + +- event_free(event); ++ /* only one process can add events to the queue */ ++ assert(manager->pid == getpid_cached()); ++ ++ /* We only accepts devices received by device monitor. */ ++ r = sd_device_get_seqnum(dev, &seqnum); ++ 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; ++ ++ *event = (Event) { ++ .manager = manager, ++ .dev = sd_device_ref(dev), ++ .dev_kernel = TAKE_PTR(clone), ++ .seqnum = seqnum, ++ .state = EVENT_QUEUED, ++ }; ++ ++ if (LIST_IS_EMPTY(manager->events)) { ++ r = touch("/run/udev/queue"); ++ if (r < 0) ++ log_warning_errno(r, "Failed to touch /run/udev/queue: %m"); ++ } ++ ++ LIST_APPEND(event, manager->events, event); ++ ++ log_device_uevent(dev, "Device is queued"); ++ ++ return 0; ++} ++ ++static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) { ++ Manager *manager = userdata; ++ int r; ++ ++ assert(manager); ++ ++ DEVICE_TRACE_POINT(kernel_uevent_received, dev); ++ ++ device_ensure_usec_initialized(dev, NULL); ++ ++ r = event_queue_insert(manager, dev); ++ if (r < 0) { ++ log_device_error_errno(dev, r, "Failed to insert device into event queue: %m"); ++ return 1; + } ++ ++ /* we have fresh events, try to schedule them */ ++ event_queue_start(manager); ++ ++ return 1; + } + + static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +@@ -1047,28 +1067,6 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat + return 1; + } + +-static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) { +- Manager *manager = userdata; +- int r; +- +- assert(manager); +- +- DEVICE_TRACE_POINT(kernel_uevent_received, dev); +- +- device_ensure_usec_initialized(dev, NULL); +- +- r = event_queue_insert(manager, dev); +- if (r < 0) { +- log_device_error_errno(dev, r, "Failed to insert device into event queue: %m"); +- return 1; +- } +- +- /* we have fresh events, try to schedule them */ +- event_queue_start(manager); +- +- return 1; +-} +- + /* receive the udevd message from userspace */ + static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) { + Manager *manager = userdata; +-- +2.33.0 diff --git a/backport-udev-only-ignore-ENOENT-or-friends-which-suggest-the-block.patch b/backport-udev-only-ignore-ENOENT-or-friends-which-suggest-the-block.patch new file mode 100644 index 0000000..0a465d3 --- /dev/null +++ b/backport-udev-only-ignore-ENOENT-or-friends-which-suggest-the-block.patch @@ -0,0 +1,36 @@ +From ef400c3878ad23aa02bd5bb47f089bdef49e9d8c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 12 Mar 2022 20:40:58 +0900 +Subject: [PATCH] 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. + +Reference:https://github.com/systemd/systemd/commit/ef400c3878ad23aa02bd5bb47f089bdef49e9d8c +Conflict:NA + +--- + 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 8389c39f652f..f1f864a4610c 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -399,8 +399,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) + \ No newline at end of file diff --git a/backport-udev-propagate-error-on-spawning-a-worker.patch b/backport-udev-propagate-error-on-spawning-a-worker.patch new file mode 100644 index 0000000..73cddc4 --- /dev/null +++ b/backport-udev-propagate-error-on-spawning-a-worker.patch @@ -0,0 +1,89 @@ +From f2a5412bf286cabc047dc96395c2dae978e722b4 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 15:47:34 +0900 +Subject: [PATCH] udev: propagate error on spawning a worker + +Reference:https://github.com/systemd/systemd/commit/f2a5412bf286cabc047dc96395c2dae978e722b4 +Conflict:NA + +--- + src/udev/udevd.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 2179825..7f41336 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -720,16 +720,18 @@ static int worker_spawn(Manager *manager, Event *event) { + return 0; + } + +-static void event_run(Manager *manager, Event *event) { ++static int event_run(Event *event) { + static bool log_children_max_reached = true; ++ Manager *manager; + Worker *worker; + int r; + +- assert(manager); + assert(event); ++ assert(event->manager); + + log_device_uevent(event->dev, "Device ready for processing"); + ++ manager = event->manager; + HASHMAP_FOREACH(worker, manager->workers) { + if (worker->state != WORKER_IDLE) + continue; +@@ -743,29 +745,32 @@ static void event_run(Manager *manager, Event *event) { + continue; + } + worker_attach_event(worker, event); +- return; ++ return 1; /* event is now processing. */ + } + + if (hashmap_size(manager->workers) >= arg_children_max) { +- + /* Avoid spamming the debug logs if the limit is already reached and + * many events still need to be processed */ + if (log_children_max_reached && arg_children_max > 1) { + log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers)); + log_children_max_reached = false; + } +- return; ++ return 0; /* no free worker */ + } + + /* 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 */ ++ * 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 */ +- worker_spawn(manager, event); ++ r = worker_spawn(manager, event); ++ if (r < 0) ++ return r; ++ ++ return 1; /* event is now processing. */ + } + + /* lookup event for identical, parent, child device */ +@@ -921,7 +926,9 @@ static int event_queue_start(Manager *manager) { + if (is_device_busy(manager, event) != 0) + continue; + +- event_run(manager, event); ++ r = event_run(event); ++ if (r < 0) ++ return r; + } + + return 0; +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-remove-run-udev-queue-in-on_post.patch b/backport-udev-remove-run-udev-queue-in-on_post.patch new file mode 100644 index 0000000..fed83ae --- /dev/null +++ b/backport-udev-remove-run-udev-queue-in-on_post.patch @@ -0,0 +1,53 @@ +From 4029328014be9350ca9fc0774ad936c8b5e50ff2 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 13 Mar 2022 21:22:57 +0900 +Subject: [PATCH] udev: remove /run/udev/queue in on_post() + +When the last queued event is processed, information about subsequent +events may be already queued in the netlink socket of sd-device-monitor. +In that case, previously we once removed /run/udev/queue and touch the +file soon later, and `udevadm settle` mistakenly considered all events +are processed. + +To mitigate such situation, this makes /run/udev/queue removed in on_post(). + +Reference:https://github.com/systemd/systemd/commit/4029328014be9350ca9fc0774ad936c8b5e50ff2 +Conflict:NA + +--- + src/udev/udevd.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 6bb9eeb4bb37..8389c39f652f 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -171,12 +171,6 @@ static Event *event_free(Event *event) { + if (event->worker) + event->worker->event = NULL; + +- /* only clean up the queue from the process that created it */ +- if (LIST_IS_EMPTY(event->manager->events) && +- event->manager->pid == getpid_cached()) +- if (unlink("/run/udev/queue") < 0 && errno != ENOENT) +- log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m"); +- + return mfree(event); + } + +@@ -1480,7 +1474,13 @@ static int on_post(sd_event_source *s, void *userdata) { + if (!LIST_IS_EMPTY(manager->events)) + return 1; + +- /* There are no pending events. Let's cleanup idle process. */ ++ /* There are no queued events. Let's remove /run/udev/queue and clean up the idle processes. */ ++ ++ if (unlink("/run/udev/queue") < 0) { ++ if (errno != ENOENT) ++ log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m"); ++ } else ++ log_debug("No events are queued, removing /run/udev/queue."); + + if (!hashmap_isempty(manager->workers)) { + /* There are idle workers */ + \ No newline at end of file diff --git a/backport-udev-rename-is_device_busy-event_is_blocked.patch b/backport-udev-rename-is_device_busy-event_is_blocked.patch new file mode 100644 index 0000000..dde6b33 --- /dev/null +++ b/backport-udev-rename-is_device_busy-event_is_blocked.patch @@ -0,0 +1,141 @@ +From a1fa99d84124cdcd4a306113ebe4febc1251c41c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 16:14:01 +0900 +Subject: [PATCH] udev: rename is_device_busy() -> event_is_blocked() + +Also this rename delaying_seqnum -> blocker_seqnum. + +Reference:https://github.com/systemd/systemd/commit/a1fa99d84124cdcd4a306113ebe4febc1251c41c +Conflict:NA + +--- + src/udev/udevd.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e99c2c0..20bd556 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -126,7 +126,7 @@ typedef struct Event { + sd_device *dev_kernel; /* clone of originally received device */ + + uint64_t seqnum; +- uint64_t delaying_seqnum; ++ uint64_t blocker_seqnum; + + sd_event_source *timeout_warning_event; + sd_event_source *timeout_event; +@@ -773,8 +773,7 @@ static int event_run(Event *event) { + return 1; /* event is now processing. */ + } + +-/* lookup event for identical, parent, child device */ +-static int is_device_busy(Manager *manager, Event *event) { ++static int event_is_blocked(Event *event) { + const char *subsystem, *devpath, *devpath_old = NULL; + dev_t devnum = makedev(0, 0); + Event *loop_event; +@@ -782,6 +781,8 @@ static int is_device_busy(Manager *manager, Event *event) { + int r, ifindex = 0; + bool is_block; + ++ /* lookup event for identical, parent, child device */ ++ + r = sd_device_get_subsystem(event->dev, &subsystem); + if (r < 0) + return r; +@@ -807,21 +808,21 @@ static int is_device_busy(Manager *manager, Event *event) { + return r; + + /* check if queue contains events we depend on */ +- LIST_FOREACH(event, loop_event, manager->events) { ++ LIST_FOREACH(event, loop_event, event->manager->events) { + size_t loop_devpath_len, common; + const char *loop_devpath; + + /* we already found a later event, earlier cannot block us, no need to check again */ +- if (loop_event->seqnum < event->delaying_seqnum) ++ if (loop_event->seqnum < event->blocker_seqnum) + continue; + + /* event we checked earlier still exists, no need to check again */ +- if (loop_event->seqnum == event->delaying_seqnum) ++ if (loop_event->seqnum == event->blocker_seqnum) + return true; + + /* found ourself, no later event can block us */ + if (loop_event->seqnum >= event->seqnum) +- break; ++ return false; + + /* check major/minor */ + if (major(devnum) != 0) { +@@ -833,7 +834,7 @@ static int is_device_busy(Manager *manager, Event *event) { + + if (sd_device_get_devnum(loop_event->dev, &d) >= 0 && + devnum == d && is_block == streq(s, "block")) +- goto set_delaying_seqnum; ++ break; + } + + /* check network device ifindex */ +@@ -842,7 +843,7 @@ static int is_device_busy(Manager *manager, Event *event) { + + if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 && + ifindex == i) +- goto set_delaying_seqnum; ++ break; + } + + if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0) +@@ -850,7 +851,7 @@ static int is_device_busy(Manager *manager, Event *event) { + + /* check our old name */ + if (devpath_old && streq(devpath_old, loop_devpath)) +- goto set_delaying_seqnum; ++ break; + + loop_devpath_len = strlen(loop_devpath); + +@@ -863,24 +864,23 @@ static int is_device_busy(Manager *manager, Event *event) { + + /* identical device event found */ + if (devpath_len == loop_devpath_len) +- goto set_delaying_seqnum; ++ break; + + /* parent device event found */ + if (devpath[common] == '/') +- goto set_delaying_seqnum; ++ break; + + /* child device event found */ + if (loop_devpath[common] == '/') +- goto set_delaying_seqnum; ++ break; + } + +- return false; ++ assert(loop_event); + +-set_delaying_seqnum: + log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64, + event->seqnum, loop_event->seqnum); + +- event->delaying_seqnum = loop_event->seqnum; ++ event->blocker_seqnum = loop_event->seqnum; + return true; + } + +@@ -923,7 +923,7 @@ static int event_queue_start(Manager *manager) { + continue; + + /* do not start event if parent or child event is still running */ +- if (is_device_busy(manager, event) != 0) ++ if (event_is_blocked(event) != 0) + continue; + + r = event_run(event); +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-requeue-event-when-the-corresponding-block-device-is.patch b/backport-udev-requeue-event-when-the-corresponding-block-device-is.patch new file mode 100644 index 0000000..b193b03 --- /dev/null +++ b/backport-udev-requeue-event-when-the-corresponding-block-device-is.patch @@ -0,0 +1,288 @@ +From 5d354e525a56955ae7f68062e283dda85ab07794 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Mar 2022 13:50:06 +0900 +Subject: [PATCH] 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. + +Reference:https://github.com/systemd/systemd/commit/5d354e525a56955ae7f68062e283dda85ab07794 +Conflict:adaption + +--- + 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 d153b03a38e1..973727375b67 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -70,6 +70,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; +@@ -128,6 +130,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; +@@ -152,8 +156,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) +@@ -360,10 +369,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) { +@@ -490,44 +500,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; + +@@ -560,25 +538,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"); + +@@ -794,6 +776,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((char[FORMAT_TIMESPAN_MAX]){}, FORMAT_TIMESPAN_MAX, 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); + } + +@@ -1467,8 +1500,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 queued events. Let's remove /run/udev/queue and clean up the idle processes. */ + + \ No newline at end of file diff --git a/backport-udev-skip-event-when-its-dependency-cannot-be-checked.patch b/backport-udev-skip-event-when-its-dependency-cannot-be-checked.patch new file mode 100644 index 0000000..b28f6b1 --- /dev/null +++ b/backport-udev-skip-event-when-its-dependency-cannot-be-checked.patch @@ -0,0 +1,58 @@ +From c6f78234d1d1c6065ecc56240f217d1fdbeb1771 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Jun 2021 17:14:10 +0900 +Subject: [PATCH] udev: skip event when its dependency cannot be checked + +Reference:https://github.com/systemd/systemd/commit/c6f78234d1d1c6065ecc56240f217d1fdbeb1771 +Conflict:NA + +--- + src/udev/udevd.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index be2c3ee..683938d 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -910,7 +910,7 @@ no_blocker: + } + + static int event_queue_start(Manager *manager) { +- Event *event; ++ Event *event, *event_next; + usec_t usec; + int r; + +@@ -943,12 +943,26 @@ static int event_queue_start(Manager *manager) { + return log_warning_errno(r, "Failed to read udev rules: %m"); + } + +- LIST_FOREACH(event, event, manager->events) { ++ LIST_FOREACH_SAFE(event, event, event_next, manager->events) { + if (event->state != EVENT_QUEUED) + continue; + +- /* do not start event if parent or child event is still running */ +- if (event_is_blocked(event) != 0) ++ /* do not start event if parent or child event is still running or queued */ ++ r = event_is_blocked(event); ++ 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)", ++ event->seqnum, ++ strna(device_action_to_string(a))); ++ ++ event_free(event); ++ return r; ++ } ++ if (r > 0) + continue; + + r = event_run(event); +-- +2.33.0 + \ No newline at end of file diff --git a/backport-udev-split-worker_lock_block_device-into-two.patch b/backport-udev-split-worker_lock_block_device-into-two.patch new file mode 100644 index 0000000..dc8f58b --- /dev/null +++ b/backport-udev-split-worker_lock_block_device-into-two.patch @@ -0,0 +1,123 @@ +From 7b7959fba52ba4bb6b5f7001971917760df40fee Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:55:25 +0900 +Subject: [PATCH] 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. + +Reference:https://github.com/systemd/systemd/commit/7b7959fba52ba4bb6b5f7001971917760df40fee +Conflict:NA + +--- + 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 973727375b67..0b620cb7dcac 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -376,35 +376,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) +@@ -417,16 +411,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) +@@ -434,6 +458,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) { + \ No newline at end of file diff --git a/backport-udev-store-action-in-struct-Event.patch b/backport-udev-store-action-in-struct-Event.patch new file mode 100644 index 0000000..b0281bd --- /dev/null +++ b/backport-udev-store-action-in-struct-Event.patch @@ -0,0 +1,71 @@ +From 0c3d8182c997c979c7a0ccce88d9fc48638261a5 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 25 Mar 2022 02:39:55 +0900 +Subject: [PATCH] udev: store action in struct Event + +Reference:https://github.com/systemd/systemd/commit/0c3d8182c997c979c7a0ccce88d9fc48638261a5 +Conflict:NA + +--- + 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 53728c9f7971..d153b03a38e1 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -125,6 +125,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, + }; + + diff --git a/backport-udev-update-comment-and-log-messages.patch b/backport-udev-update-comment-and-log-messages.patch new file mode 100644 index 0000000..17dbaf9 --- /dev/null +++ b/backport-udev-update-comment-and-log-messages.patch @@ -0,0 +1,31 @@ +From 87afc766d199642c6da956657b05690a39542856 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 12 Mar 2022 20:48:36 +0900 +Subject: [PATCH] udev: update comment and log message + +Reference:https://github.com/systemd/systemd/commit/87afc766d199642c6da956657b05690a39542856 +Conflict:NA + +--- + src/udev/udevd.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 41d0ec1e137c..0407068d5112 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1448,10 +1448,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 */ ++ /* Forward kernel event unchanged */ + r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); + 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_kernel, r, ++ "Failed to broadcast failed event to libudev listeners, ignoring: %m"); + } + } + + \ No newline at end of file diff --git a/backport-udev-update-log-message-to-clarify-that-the-error-is-ignored.patch b/backport-udev-update-log-message-to-clarify-that-the-error-is-ignored.patch new file mode 100644 index 0000000..06065e2 --- /dev/null +++ b/backport-udev-update-log-message-to-clarify-that-the-error-is-ignored.patch @@ -0,0 +1,36 @@ +From 6be97d67c82ef5f45360c4323616739816b8f833 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 16 Jun 2021 21:02:01 +0900 +Subject: [PATCH] udev: update log message to clarify that the error is ignored + +Reference:https://github.com/systemd/systemd/commit/6be97d67c82ef5f45360c4323616739816b8f833 +Conflict:NA + +--- + src/udev/udevd.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 546bfe039e1d..34a5c9d5d8ee 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -171,8 +171,8 @@ static void event_free(Event *event) { + /* only clean up the queue from the process that created it */ + if (LIST_IS_EMPTY(event->manager->events) && + event->manager->pid == getpid_cached()) +- if (unlink("/run/udev/queue") < 0) +- log_warning_errno(errno, "Failed to unlink /run/udev/queue: %m"); ++ if (unlink("/run/udev/queue") < 0 && errno != ENOENT) ++ log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m"); + + free(event); + } +@@ -965,7 +965,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { + if (LIST_IS_EMPTY(manager->events)) { + r = touch("/run/udev/queue"); + if (r < 0) +- log_warning_errno(r, "Failed to touch /run/udev/queue: %m"); ++ log_warning_errno(r, "Failed to touch /run/udev/queue, ignoring: %m"); + } + + LIST_APPEND(event, manager->events, event); diff --git a/systemd.spec b/systemd.spec index 16f33ff..1dcb121 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 249 -Release: 50 +Release: 51 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -451,6 +451,33 @@ Patch6403: backport-core-unit-merge-two-loops-into-one.patch Patch6404: backport-core-unit-merge-unit-names-after-merging-deps.patch Patch6405: backport-core-unit-fix-log-message.patch Patch6406: backport-test-add-test-case-for-sysv-generator-and-invalid-de.patch +Patch6407: backport-udev-also-rename-struct-udev_ctrl-UdevCtrl.patch +Patch6408: backport-udev-move-several-functions.patch +Patch6409: backport-udev-update-log-message-to-clarify-that-the-error-is-ignored.patch +Patch6410: backport-udev-make-event_free-return-NULL.patch +Patch6411: backport-udev-make-event_queue_start-return-negative-errno-on-error.patch +Patch6412: backport-udev-add-usec_add-at-one-more-place.patch +Patch6413: backport-udev-propagate-error-on-spawning-a-worker.patch +Patch6414: backport-udev-do-not-try-to-process-events-if-there-is-no-free-worker.patch +Patch6415: backport-udev-rename-is_device_busy-event_is_blocked.patch +Patch6416: backport-list-introduce-LIST_FOREACH_BACKWARDS-macro-and-drop.patch +Patch6417: backport-udev-do-not-try-to-find-blocker-again-when-no-blocker-found.patch +Patch6418: backport-udev-skip-event-when-its-dependency-cannot-be-checked.patch +Patch6419: backport-event-util-introduce-event_reset_time_relative.patch +Patch6420: backport-udev-update-comment-and-log-messages.patch +Patch6421: backport-udev-remove-run-udev-queue-in-on_post.patch +Patch6422: backport-errno-util-add-ERRNO_IS_DEVICE_ABSENT-macro.patch +Patch6423: backport-udev-only-ignore-ENOENT-or-friends-which-suggest-the-block.patch +Patch6424: backport-udev-assume-there-is-no-blocker-when-failed-to-check-event.patch +Patch6425: backport-udev-drop-unnecessary-clone-of-received-sd-device-object.patch +Patch6426: backport-udev-introduce-device_broadcast_helper_function.patch +Patch6427: backport-udev-store-action-in-struct-Event.patch +Patch6428: backport-udev-requeue-event-when-the-corresponding-block-device-is.patch +Patch6429: backport-udev-split-worker_lock_block_device-into-two.patch +Patch6430: backport-udev-assume-block-device-is-not-locked-when-a-new-event-is-queued.patch +Patch6431: backport-udev-fix-inversed-inequality-for-timeout-of-retrying-event.patch +Patch6432: backport-udev-certainly-restart-event-for-previously-locked-device.patch +Patch6433: backport-udev-drop-unnecessary-calls-of-event_queue_start.patch Patch9001: update-rtc-with-system-clock-when-shutdown.patch Patch9002: udev-add-actions-while-rename-netif-failed.patch @@ -1922,6 +1949,9 @@ fi %{_libdir}/security/pam_systemd.so %changelog +* Mon Jun 12 2023 chenjiayi - 249-51 +- backport upstream patches to fix event loss when the whole disk is locked + * Thu Jun 8 2023 licunlong - 249-50 - set the cpuset.cpus/mems of machine.slice to all by default