Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport systemd fixes for udevd skipping events (and others) #2999

Merged
merged 3 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/release/prepare-local-fs.service
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[Unit]
Description=Prepare Local Filesystem (/local)
DefaultDependencies=no
Before=local-fs.target
Wants=dev-disk-by\x2dpartlabel-BOTTLEROCKET\x2dDATA.device
After=dev-disk-by\x2dpartlabel-BOTTLEROCKET\x2dDATA.device
RefuseManualStart=true
Expand All @@ -12,6 +13,11 @@ Type=oneshot
# Create the filesystem on the partition, if it doesn't exist.
ExecStart=/usr/lib/systemd/systemd-makefs ext4 /dev/disk/by-partlabel/BOTTLEROCKET-DATA

# Stop and mask the repart-data-* oneshots in case they're waiting on non-existent data partitions.
# 'BOTTLEROCKET-DATA' already exists so we can move on.
ExecStart=/usr/bin/systemctl stop repart-data-preferred repart-data-fallback --no-block
ExecStart=/usr/bin/systemctl mask repart-data-preferred repart-data-fallback --no-block

RemainAfterExit=true
StandardError=journal+console

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
From 52cc55a9297e85866a237c09585cda47b2207746 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 24 Mar 2022 13:50:50 +0100
Subject: [PATCH 01/12] errno-util: add ERRNO_IS_DEVICE_ABSENT() macro

Inspired by: https://github.com/systemd/systemd/pull/22717#discussion_r834254495
---
src/basic/errno-util.h | 10 +++++++++-
src/home/homework-luks.c | 4 ++--
src/rfkill/rfkill.c | 2 +-
src/udev/udev-builtin-btrfs.c | 3 ++-
4 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
index 09abf0b751..648de50eb4 100644
--- a/src/basic/errno-util.h
+++ b/src/basic/errno-util.h
@@ -138,10 +138,18 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) {
EPERM);
}

-/* Three difference errors for "not enough disk space" */
+/* Three different errors for "not enough disk space" */
static inline bool ERRNO_IS_DISK_SPACE(int r) {
return IN_SET(abs(r),
ENOSPC,
EDQUOT,
EFBIG);
}
+
+/* Three different errors for "this device does not quite exist" */
+static inline bool ERRNO_IS_DEVICE_ABSENT(int r) {
+ return IN_SET(abs(r),
+ ENODEV,
+ ENXIO,
+ ENOENT);
+}
diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c
index 1122e32575..cfe91d87c5 100644
--- a/src/home/homework-luks.c
+++ b/src/home/homework-luks.c
@@ -494,7 +494,7 @@ static int acquire_open_luks_device(
return r;

r = sym_crypt_init_by_name(&cd, setup->dm_name);
- if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT) && graceful)
+ if ((ERRNO_IS_DEVICE_ABSENT(r) || r == -EINVAL) && graceful)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name);
@@ -1634,7 +1634,7 @@ int home_deactivate_luks(UserRecord *h, HomeSetup *setup) {
cryptsetup_enable_logging(setup->crypt_device);

r = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0);
- if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
+ if (ERRNO_IS_DEVICE_ABSENT(r) || r == -EINVAL) {
log_debug_errno(r, "LUKS device %s is already detached.", setup->dm_node);
we_detached = false;
} else if (r < 0)
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c
index bca2f3b812..79fad78723 100644
--- a/src/rfkill/rfkill.c
+++ b/src/rfkill/rfkill.c
@@ -80,7 +80,7 @@ static int find_device(

r = sd_device_new_from_subsystem_sysname(&device, "rfkill", sysname);
if (r < 0)
- return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r,
+ return log_full_errno(ERRNO_IS_DEVICE_ABSENT(r) ? LOG_DEBUG : LOG_ERR, r,
"Failed to open device '%s': %m", sysname);

r = sd_device_get_sysattr_value(device, "name", &name);
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
index a0093cb423..f9d4f1dd4e 100644
--- a/src/udev/udev-builtin-btrfs.c
+++ b/src/udev/udev-builtin-btrfs.c
@@ -6,6 +6,7 @@
#include <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. */
--
2.25.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
From 99c3273b0d6b7cb94914db4a4df877f5328577be 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 02/12] udev: drop unnecessary clone of received sd-device
object

As the sd-device object received through sd-device-monitor is sealed,
so the corresponding udev database or uevent file will not be read.
---
src/udev/udevd.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 9320284be6..fbe0be8556 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -122,7 +122,6 @@ typedef struct Event {
EventState state;

sd_device *dev;
- sd_device *dev_kernel; /* clone of originally received device */

uint64_t seqnum;
uint64_t blocker_seqnum;
@@ -161,7 +160,6 @@ static Event *event_free(Event *event) {

LIST_REMOVE(event, event->manager->events, event);
sd_device_unref(event->dev);
- sd_device_unref(event->dev_kernel);

sd_event_source_unref(event->timeout_warning_event);
sd_event_source_unref(event->timeout_event);
@@ -976,9 +974,8 @@ static int event_queue_start(Manager *manager) {
}

static int event_queue_insert(Manager *manager, sd_device *dev) {
- _cleanup_(sd_device_unrefp) sd_device *clone = NULL;
- Event *event;
uint64_t seqnum;
+ Event *event;
int r;

assert(manager);
@@ -992,15 +989,6 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
if (r < 0)
return r;

- /* Save original device to restore the state on failures. */
- r = device_shallow_clone(dev, &clone);
- if (r < 0)
- return r;
-
- r = device_copy_properties(clone, dev);
- if (r < 0)
- return r;
-
event = new(Event, 1);
if (!event)
return -ENOMEM;
@@ -1008,7 +996,6 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
*event = (Event) {
.manager = manager,
.dev = sd_device_ref(dev),
- .dev_kernel = TAKE_PTR(clone),
.seqnum = seqnum,
.state = EVENT_QUEUED,
};
@@ -1444,10 +1431,11 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
device_tag_index(worker->event->dev, NULL, false);

if (manager->monitor) {
- /* forward kernel event without amending it */
- r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
+ /* Forward kernel event to libudev listeners */
+ r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev);
if (r < 0)
- log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m");
+ log_device_warning_errno(worker->event->dev, r,
+ "Failed to broadcast failed event to libudev listeners, ignoring: %m");
}
}

--
2.25.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
From b28f1747f75aa238ab7c84ecf55dc51b848f1746 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 03/12] udev: introduce device_broadcast() helper function

---
src/udev/udevd.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index fbe0be8556..40e78b25cd 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -349,6 +349,21 @@ static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userda
return 1;
}

+static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) {
+ int r;
+
+ assert(dev);
+
+ /* On exit, manager->monitor is already NULL. */
+ if (!monitor)
+ return;
+
+ r = device_monitor_send_device(monitor, NULL, dev);
+ if (r < 0)
+ log_device_warning_errno(dev, r,
+ "Failed to broadcast event to libudev listeners, ignoring: %m");
+}
+
static int worker_send_message(int fd) {
WorkerMessage message = {};

@@ -561,9 +576,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *
log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m");

/* send processed event back to libudev listeners */
- r = device_monitor_send_device(monitor, NULL, dev);
- if (r < 0)
- log_device_warning_errno(dev, r, "Failed to send device, ignoring: %m");
+ device_broadcast(monitor, dev);
}

/* send udevd the result of the event execution */
@@ -1430,13 +1443,8 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
device_delete_db(worker->event->dev);
device_tag_index(worker->event->dev, NULL, false);

- if (manager->monitor) {
- /* Forward kernel event to libudev listeners */
- r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev);
- if (r < 0)
- log_device_warning_errno(worker->event->dev, r,
- "Failed to broadcast failed event to libudev listeners, ignoring: %m");
- }
+ /* Forward kernel event to libudev listeners */
+ device_broadcast(manager->monitor, worker->event->dev);
}

worker_free(worker);
--
2.25.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
From a95aba56e5b31f221eb9133e70ddb1044315e532 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 04/12] udev: assume there is no blocker when failed to check
event dependencies

Previously, if udevd failed to resolve event dependency, the event is
ignored and libudev listeners did not receive the event. This is
inconsistent with the case when a worker failed to process a event,
in that case, the original uevent sent by the kernel is broadcasted to
listeners.
---
src/udev/udevd.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 40e78b25cd..ed53470848 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -962,24 +962,21 @@ static int event_queue_start(Manager *manager) {

/* do not start event if parent or child event is still running or queued */
r = event_is_blocked(event);
+ if (r > 0)
+ continue;
if (r < 0) {
sd_device_action_t a = _SD_DEVICE_ACTION_INVALID;

(void) sd_device_get_action(event->dev, &a);
log_device_warning_errno(event->dev, r,
- "Failed to check event dependency, "
- "skipping event (SEQNUM=%"PRIu64", ACTION=%s)",
+ "Failed to check dependencies for event (SEQNUM=%"PRIu64", ACTION=%s), "
+ "assuming there is no blocking event, ignoring: %m",
event->seqnum,
strna(device_action_to_string(a)));
-
- event_free(event);
- return r;
}
- if (r > 0)
- continue;

r = event_run(event);
- if (r <= 0)
+ if (r <= 0) /* 0 means there are no idle workers. Let's escape from the loop. */
return r;
}

--
2.25.1

70 changes: 70 additions & 0 deletions packages/systemd/0005-udev-store-action-in-struct-Event.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
From 2be3e27017de18f5d973ca9b83cc170c784fb8db 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 05/12] udev: store action in struct Event

---
src/udev/udevd.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index ed53470848..abf50b6a71 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -123,6 +123,7 @@ typedef struct Event {

sd_device *dev;

+ sd_device_action_t action;
uint64_t seqnum;
uint64_t blocker_seqnum;

@@ -964,16 +965,12 @@ static int event_queue_start(Manager *manager) {
r = event_is_blocked(event);
if (r > 0)
continue;
- if (r < 0) {
- sd_device_action_t a = _SD_DEVICE_ACTION_INVALID;
-
- (void) sd_device_get_action(event->dev, &a);
+ if (r < 0)
log_device_warning_errno(event->dev, r,
"Failed to check dependencies for event (SEQNUM=%"PRIu64", ACTION=%s), "
"assuming there is no blocking event, ignoring: %m",
event->seqnum,
- strna(device_action_to_string(a)));
- }
+ strna(device_action_to_string(event->action)));

r = event_run(event);
if (r <= 0) /* 0 means there are no idle workers. Let's escape from the loop. */
@@ -984,6 +981,7 @@ static int event_queue_start(Manager *manager) {
}

static int event_queue_insert(Manager *manager, sd_device *dev) {
+ sd_device_action_t action;
uint64_t seqnum;
Event *event;
int r;
@@ -999,6 +997,10 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
if (r < 0)
return r;

+ r = sd_device_get_action(dev, &action);
+ if (r < 0)
+ return r;
+
event = new(Event, 1);
if (!event)
return -ENOMEM;
@@ -1007,6 +1009,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
.manager = manager,
.dev = sd_device_ref(dev),
.seqnum = seqnum,
+ .action = action,
.state = EVENT_QUEUED,
};

--
2.25.1

Loading