backport upstream patches to fix event loss when the whole disk is locked

This commit is contained in:
chenjiayi 2023-06-11 07:59:19 +08:00
parent d426c1fb9f
commit 1d68f589fa
29 changed files with 2859 additions and 30 deletions

View File

@ -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

View File

@ -0,0 +1,75 @@
From 3f2ada89f3a277625390bf6789ccd4e7aba08743 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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 <sys/ioctl.h>
#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. */

View File

@ -0,0 +1,87 @@
From 52c3bc708fb6a3eb68a3cac780b49192818bd409 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,102 @@
From bd335c961fed6982e5ad8c2322414ff33a46e92e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,28 @@
From 92fd70addf25d4f301ba43ca3e6ede96d9564295 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,350 @@
From e0d61dac3324abc90f61014a98b1bc5a9a1f60ae Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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;

View File

@ -0,0 +1,81 @@
From 82a5de9fd289e1d9b109528bcdddb74534e1a4bf Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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(). */

View File

@ -0,0 +1,54 @@
From 2d40f02ee4317233365f53c85234be3af6b000a6 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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;
}

View File

@ -0,0 +1,86 @@
From 4f294ffdf18ab9f187400dbbab593a980e60be89 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,91 @@
From 044ac33c35ab1aeb35fc8b84462a9549cbbac294 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,28 @@
From 5f4bca9dccdd9e9a888587c6224b08ae5fbe3bdb Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,80 @@
From 5fab6b7b18d0158c005a5bcf096face23377af72 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,85 @@
From c9473aaa5b69c47edab365b46abee6e9ab5b18dc Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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");
}
}

View File

@ -0,0 +1,27 @@
From 400e3d21f8cae53a8ba9f9567f244fbf6f3e076c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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;
}

View File

@ -0,0 +1,66 @@
From c17ab900cbb47f0c136b141bb83557f112501707 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,36 @@
From 5393c52897ff5b57686c867fcab77f9740f4af24 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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) {

View File

@ -0,0 +1,59 @@
From 0744e74c526814e28f2fbcea128f40ed36341fcd Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,544 @@
From 419ec631358c8bf7013db01ae42763e6971d8765 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,36 @@
From ef400c3878ad23aa02bd5bb47f089bdef49e9d8c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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)

View File

@ -0,0 +1,89 @@
From f2a5412bf286cabc047dc96395c2dae978e722b4 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,53 @@
From 4029328014be9350ca9fc0774ad936c8b5e50ff2 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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 */

View File

@ -0,0 +1,141 @@
From a1fa99d84124cdcd4a306113ebe4febc1251c41c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,288 @@
From 5d354e525a56955ae7f68062e283dda85ab07794 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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. */

View File

@ -0,0 +1,58 @@
From c6f78234d1d1c6065ecc56240f217d1fdbeb1771 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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

View File

@ -0,0 +1,123 @@
From 7b7959fba52ba4bb6b5f7001971917760df40fee Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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) {

View File

@ -0,0 +1,71 @@
From 0c3d8182c997c979c7a0ccce88d9fc48638261a5 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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,
};

View File

@ -0,0 +1,31 @@
From 87afc766d199642c6da956657b05690a39542856 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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");
}
}

View File

@ -0,0 +1,36 @@
From 6be97d67c82ef5f45360c4323616739816b8f833 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -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 <chenjiayi22@huawei.com> - 249-51
- backport upstream patches to fix event loss when the whole disk is locked
* Thu Jun 8 2023 licunlong <licunlong1@huawei.com> - 249-50
- set the cpuset.cpus/mems of machine.slice to all by default