From ce18c396231cb9090fec0c44707211c64685688e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Mar 2023 12:35:38 +0100 Subject: [PATCH 1/6] unit: add ordering dep relative to credentials dir See: #25527 --- src/core/execute.c | 2 +- src/core/execute.h | 1 + src/core/unit.c | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/core/execute.c b/src/core/execute.c index ca89e3b003..6595931809 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1539,7 +1539,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) { context_has_syscall_logs(c); } -static bool exec_context_has_credentials(const ExecContext *context) { +bool exec_context_has_credentials(const ExecContext *context) { assert(context); diff --git a/src/core/execute.h b/src/core/execute.h index c2c983d0c3..e46f31037e 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -476,6 +476,7 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index); bool exec_context_may_touch_console(const ExecContext *c); bool exec_context_maintains_privileges(const ExecContext *c); bool exec_context_has_encrypted_credentials(ExecContext *c); +bool exec_context_has_credentials(const ExecContext *context); int exec_context_get_effective_ioprio(const ExecContext *c); bool exec_context_get_effective_mount_apivfs(const ExecContext *c); diff --git a/src/core/unit.c b/src/core/unit.c index 3393138bac..fa1474db8d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1411,6 +1411,26 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { if (r < 0) return r; + if (exec_context_has_credentials(c) && u->manager->prefix[EXEC_DIRECTORY_RUNTIME]) { + _cleanup_free_ char *p = NULL, *m = NULL; + + /* Let's make sure the credentials directory of this service is unmounted *after* the service + * itself shuts down. This only matters if mount namespacing is not used for the service, and + * hence the credentials mount appears on the host. */ + + p = path_join(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], "credentials", u->id); + if (!p) + return -ENOMEM; + + r = unit_name_from_path(p, ".mount", &m); + if (r < 0) + return r; + + r = unit_add_dependency_by_name(u, UNIT_AFTER, m, /* add_reference= */ true, UNIT_DEPENDENCY_FILE); + if (r < 0) + return r; + } + return 0; } From 92e64e9ae93fa96e23bc07e95e223e92e03ea238 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Mar 2023 13:59:45 +0100 Subject: [PATCH 2/6] core: suppress various defaults deps for credentials mounts The per-unit credentials mounts might show up for any kind of service, including very very early ones. Hence let's not order them after local-fs-pre.target, because otherwise we might trigger cyclic deps of services that want to plug before that but still use credentials. --- src/core/mount.c | 51 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/core/mount.c b/src/core/mount.c index f25188681d..007d865fee 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -473,6 +473,22 @@ static bool mount_is_extrinsic(Unit *u) { return false; } +static bool mount_is_credentials(Mount *m) { + const char *e; + + assert(m); + + /* Returns true if this is a credentials mount. We don't want automatic dependencies on credential + * mounts, since they are managed by us for even the earliest services, and we never want anything to + * be ordered before them hence. */ + + e = path_startswith(m->where, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]); + if (!e) + return false; + + return !isempty(path_startswith(e, "credentials")); +} + static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, UnitDependencyMask mask) { const char *after, *before, *e; int r; @@ -495,7 +511,10 @@ static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, after = SPECIAL_LOCAL_FS_PRE_TARGET; before = SPECIAL_INITRD_USR_FS_TARGET; - } else if (mount_is_network(p)) { + } else if (mount_is_credentials(m)) + after = before = NULL; + + else if (mount_is_network(p)) { after = SPECIAL_REMOTE_FS_PRE_TARGET; before = SPECIAL_REMOTE_FS_TARGET; @@ -504,18 +523,32 @@ static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, before = SPECIAL_LOCAL_FS_TARGET; } - if (!mount_is_nofail(m)) { + if (before && !mount_is_nofail(m)) { r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, /* add_reference= */ true, mask); if (r < 0) return r; } - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, /* add_reference= */ true, mask); + if (after) { + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, /* add_reference= */ true, mask); + if (r < 0) + return r; + } + + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, + /* add_reference= */ true, mask); if (r < 0) return r; - return unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, - /* add_reference= */ true, mask); + /* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */ + if (streq_ptr(p->fstype, "tmpfs") && !mount_is_credentials(m)) { + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, + /* add_reference= */ true, mask); + if (r < 0) + return r; + } + + return 0; } static int mount_add_default_dependencies(Mount *m) { @@ -567,14 +600,6 @@ static int mount_add_default_dependencies(Mount *m) { return r; } - /* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */ - if (streq_ptr(p->fstype, "tmpfs")) { - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, - /* add_reference= */ true, mask); - if (r < 0) - return r; - } - return exec_context_add_default_dependencies(UNIT(m), &m->exec_context); } From 75b09529824340da05b912d68065049a0ef3a465 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Mar 2023 14:03:47 +0100 Subject: [PATCH 3/6] core: split out default network dep generation into own function Just some simple refactoring: let's split out network dep generation into its own function mount_add_default_network_dependencies(). This way mount_add_default_dependencies() only does preparatory stuff, and then calls both mount_add_default_network_dependencies() and mount_add_default_ordering_dependencies() with that, making things nicely symmetric. --- src/core/mount.c | 49 +++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/core/mount.c b/src/core/mount.c index 007d865fee..4a0dc7ebac 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -551,6 +551,31 @@ static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, return 0; } +static int mount_add_default_network_dependencies(Mount *m, MountParameters *p, UnitDependencyMask mask) { + int r; + + assert(m); + + if (!mount_is_network(p)) + return 0; + + /* We order ourselves after network.target. This is primarily useful at shutdown: services that take + * down the network should order themselves before network.target, so that they are shut down only + * after this mount unit is stopped. */ + + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, + /* add_reference= */ true, mask); + if (r < 0) + return r; + + /* We pull in network-online.target, and order ourselves after it. This is useful at start-up to + * actively pull in tools that want to be started before we start mounting network file systems, and + * whose purpose it is to delay this until the network is "up". */ + + return unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, + /* add_reference= */ true, mask); +} + static int mount_add_default_dependencies(Mount *m) { UnitDependencyMask mask; MountParameters *p; @@ -578,27 +603,9 @@ static int mount_add_default_dependencies(Mount *m) { if (r < 0) return r; - if (mount_is_network(p)) { - /* We order ourselves after network.target. This is primarily useful at shutdown: - * services that take down the network should order themselves before - * network.target, so that they are shut down only after this mount unit is - * stopped. */ - - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, - /* add_reference= */ true, mask); - if (r < 0) - return r; - - /* We pull in network-online.target, and order ourselves after it. This is useful - * at start-up to actively pull in tools that want to be started before we start - * mounting network file systems, and whose purpose it is to delay this until the - * network is "up". */ - - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, - /* add_reference= */ true, mask); - if (r < 0) - return r; - } + r = mount_add_default_network_dependencies(m, p, mask); + if (r < 0) + return r; return exec_context_add_default_dependencies(UNIT(m), &m->exec_context); } From 2fdc274c66b6735114ddc00df7f537bcc5372e41 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Mar 2023 23:16:43 +0100 Subject: [PATCH 4/6] sd-event: add an explicit API for leaving the ratelimit state Sometimes, it might make sense to end the ratelimit window early. --- man/rules/meson.build | 1 + man/sd_event_source_set_ratelimit.xml | 21 ++++++-- src/libsystemd/libsystemd.sym | 1 + src/libsystemd/sd-event/sd-event.c | 21 ++++++++ src/libsystemd/sd-event/test-event.c | 71 +++++++++++++++++++++++++++ src/systemd/sd-event.h | 1 + 6 files changed, 111 insertions(+), 5 deletions(-) diff --git a/man/rules/meson.build b/man/rules/meson.build index 6bd54739af..d496ebc747 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -633,6 +633,7 @@ manpages = [ '3', ['sd_event_source_get_ratelimit', 'sd_event_source_is_ratelimited', + 'sd_event_source_leave_ratelimit', 'sd_event_source_set_ratelimit_expire_callback'], ''], ['sd_event_source_set_userdata', '3', ['sd_event_source_get_userdata'], ''], diff --git a/man/sd_event_source_set_ratelimit.xml b/man/sd_event_source_set_ratelimit.xml index 07ac18b791..89eb34fa9b 100644 --- a/man/sd_event_source_set_ratelimit.xml +++ b/man/sd_event_source_set_ratelimit.xml @@ -20,6 +20,7 @@ sd_event_source_get_ratelimit sd_event_source_is_ratelimited sd_event_source_set_ratelimit_expire_callback + sd_event_source_leave_ratelimit Configure rate limiting on event sources @@ -53,6 +54,10 @@ sd_event_handler_tcallback + + int sd_event_source_leave_ratelimit + sd_event_source *source + @@ -85,10 +90,14 @@ is currently affected by rate limiting, i.e. it has recently hit the rate limit and is currently temporarily disabled due to that. - sd_event_source_set_ratelimit_expire_callback may be used to set a callback + sd_event_source_set_ratelimit_expire_callback() may be used to set a callback function that is invoked every time the event source leaves rate limited state. Note that function is called in the same event loop iteration in which state transition occurred. + sd_event_source_leave_ratelimit() may be used to immediately reenable an event + source that was temporarily disabled due to rate limiting. This will reset the ratelimit counters for the + current time interval. + Rate limiting is currently implemented for I/O, timer, signal, defer and inotify event sources. @@ -98,10 +107,12 @@ On success, sd_event_source_set_ratelimit(), sd_event_source_set_ratelimit_expire_callback and - sd_event_source_get_ratelimit() return a non-negative integer. On failure, they return - a negative errno-style error code. sd_event_source_is_ratelimited returns zero if rate - limiting is currently not in effect and greater than zero if it is in effect; it returns a negative - errno-style error code on failure. + sd_event_source_get_ratelimit() return a non-negative integer. On failure, they + return a negative errno-style error code. sd_event_source_is_ratelimited() returns + zero if rate limiting is currently not in effect and greater than zero if it is in effect; it returns a + negative errno-style error code on failure. sd_event_source_leave_ratelimit() + returns zero if rate limiting wasn't in effect on the specified event source, and positive if it was and + rate limiting is now turned off again; it returns a negative errno-style error code on failure. Errors diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 8b99d0a7aa..35352dc832 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -824,4 +824,5 @@ global: sd_event_source_set_memory_pressure_period; sd_event_trim_memory; sd_pid_notify_barrier; + sd_event_source_leave_ratelimit; } LIBSYSTEMD_253; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f4ede985de..9c624ab56f 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -5193,6 +5193,27 @@ _public_ int sd_event_source_is_ratelimited(sd_event_source *s) { return s->ratelimited; } +_public_ int sd_event_source_leave_ratelimit(sd_event_source *s) { + int r; + + assert_return(s, -EINVAL); + + if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) + return 0; + + if (!ratelimit_configured(&s->rate_limit)) + return 0; + + if (!s->ratelimited) + return 0; + + r = event_source_leave_ratelimit(s, /* run_callback */ false); + if (r < 0) + return r; + + return 1; /* tell caller that we indeed just left the ratelimit state */ +} + _public_ int sd_event_set_signal_exit(sd_event *e, int b) { bool change = false; int r; diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 7892f2bc2e..c5497e5148 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -828,4 +828,75 @@ TEST(fork) { assert_se(r >= 0); } +static int hup_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + unsigned *c = userdata; + + assert_se(revents == EPOLLHUP); + + (*c)++; + return 0; +} + +TEST(leave_ratelimit) { + bool expect_ratelimit = false, manually_left_ratelimit = false; + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_(close_pairp) int pfd[2] = PIPE_EBADF; + unsigned c = 0; + int r; + + assert_se(sd_event_default(&e) >= 0); + + /* Create an event source that will continously fire by creating a pipe whose write side is closed, + * and which hence will only see EOF and constant EPOLLHUP */ + assert_se(pipe2(pfd, O_CLOEXEC) >= 0); + assert_se(sd_event_add_io(e, &s, pfd[0], EPOLLIN, hup_callback, &c) >= 0); + assert_se(sd_event_source_set_io_fd_own(s, true) >= 0); + assert_se(sd_event_source_set_ratelimit(s, 5*USEC_PER_MINUTE, 5) >= 0); + + pfd[0] = -EBADF; + pfd[1] = safe_close(pfd[1]); /* Trigger continous EOF */ + + for (;;) { + r = sd_event_prepare(e); + assert_se(r >= 0); + + if (r == 0) { + r = sd_event_wait(e, UINT64_MAX); + assert_se(r > 0); + } + + r = sd_event_dispatch(e); + assert_se(r > 0); + + r = sd_event_source_is_ratelimited(s); + assert_se(r >= 0); + + if (c < 5) + /* First four dispatches should just work */ + assert_se(!r); + else if (c == 5) { + /* The fifth dispatch should still work, but we now expect the ratelimit to be hit subsequently */ + if (!expect_ratelimit) { + assert_se(!r); + assert_se(sd_event_source_leave_ratelimit(s) == 0); /* this should be a NOP, and return 0 hence */ + expect_ratelimit = true; + } else { + /* We expected the ratelimit, let's leave it manually, and verify it */ + assert_se(r); + assert_se(sd_event_source_leave_ratelimit(s) > 0); /* we are ratelimited, hence should return > 0 */ + assert_se(sd_event_source_is_ratelimited(s) == 0); + + manually_left_ratelimit = true; + } + + } else if (c == 6) + /* On the sixth iteration let's just exit */ + break; + } + + /* Verify we definitely hit the ratelimit and left it manually again */ + assert_se(manually_left_ratelimit); +} + DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 5ca8528895..49d6975967 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -173,6 +173,7 @@ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, un int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); int sd_event_source_is_ratelimited(sd_event_source *s); int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback); +int sd_event_source_leave_ratelimit(sd_event_source *s); int sd_event_trim_memory(void); From 1483892a421ca34bc841a8e8b1f385744c0407ed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Mar 2023 19:05:30 +0100 Subject: [PATCH 5/6] mount: check right before invoking /bin/umount if it makes sense Notifications from /proc/self/mountinfo are async, so if we stop a service (and while doing so get rid of the credentials mount point of it), then it will take a while until the notification reaches us and we actually scan the table again. In particular as we nowadays ratelimit notifications on the table, since it's so inefficient. And as I learnt the ratelimiting is actually quite regularly hit during shutdown, where a flurry of umount events are genreated. Hence, let's check if a mount point is actually a mountpoint before trying to unmount it. And if it isn't let's wait for the notification to come in. (This race might be triggred not just by us on ourselves btw: there are other daemons that unmount stuff when stopping where the race also exists, but might simply be harder to trigger: if during service shutdown these services remove some mount then they might collide with us doing the same. After all, we have the rule to unmount everything mounted automatically for you during shutdown.) In the long run we should also start making us of this when it becomes available: https://github.com/util-linux/util-linux/issues/2132 With that we can make issues like this go away entirely from our side of things at least. Fixes: #25527 --- src/basic/unit-def.c | 1 + src/basic/unit-def.h | 1 + src/core/mount.c | 53 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index 86b66e2be0..bfd748ada4 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -152,6 +152,7 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = { [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", + [MOUNT_UNMOUNTING_CATCHUP] = "unmounting-catchup", [MOUNT_FAILED] = "failed", [MOUNT_CLEANING] = "cleaning", }; diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index 169e1f719e..7bd86cb1d2 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -97,6 +97,7 @@ typedef enum MountState { MOUNT_REMOUNTING_SIGKILL, MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_CATCHUP, MOUNT_FAILED, MOUNT_CLEANING, _MOUNT_STATE_MAX, diff --git a/src/core/mount.c b/src/core/mount.c index 4a0dc7ebac..295e4c66c7 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -48,6 +48,7 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING, [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING, [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING, + [MOUNT_UNMOUNTING_CATCHUP] = UNIT_DEACTIVATING, [MOUNT_FAILED] = UNIT_FAILED, [MOUNT_CLEANING] = UNIT_MAINTENANCE, }; @@ -1070,11 +1071,37 @@ static void mount_enter_unmounting(Mount *m) { assert(m); + r = path_is_mount_point(m->where, NULL, 0); + if (IN_SET(r, 0, -ENOENT)) { + /* Not a mount point anymore ? Then we raced against something else which unmounted it? Let's + * handle this gracefully, and wait until we get the kernel notification about it. */ + + log_unit_debug(UNIT(m), "Path '%s' is not a mount point anymore, waiting for mount table refresh.", m->where); + + /* Apparently our idea of the kernel mount table is out of date. Make sure we re-read it + * again, soon, so that we don't delay mount handling unnecessarily. */ + (void) sd_event_source_leave_ratelimit(UNIT(m)->manager->mount_event_source); + + m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + mount_unwatch_control_pid(m); + + r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec)); + if (r < 0) + goto fail; + + /* Let's enter a distinct state where we just wait for the mount table to catch up */ + mount_set_state(m, MOUNT_UNMOUNTING_CATCHUP); + return; + } + if (r < 0) + log_unit_debug_errno(UNIT(m), r, "Unable to determine if '%s' is a mount point, ignoring: %m", m->where); + /* Start counting our attempts */ if (!IN_SET(m->state, MOUNT_UNMOUNTING, MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL)) + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_CATCHUP)) m->n_retry_umount = 0; m->control_command_id = MOUNT_EXEC_UNMOUNT; @@ -1095,7 +1122,6 @@ static void mount_enter_unmounting(Mount *m) { goto fail; mount_set_state(m, MOUNT_UNMOUNTING); - return; fail: @@ -1268,6 +1294,7 @@ static int mount_start(Unit *u) { MOUNT_UNMOUNTING, MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_CATCHUP, MOUNT_CLEANING)) return -EAGAIN; @@ -1297,6 +1324,7 @@ static int mount_stop(Unit *u) { case MOUNT_UNMOUNTING: case MOUNT_UNMOUNTING_SIGKILL: case MOUNT_UNMOUNTING_SIGTERM: + case MOUNT_UNMOUNTING_CATCHUP: /* Already on it */ return 0; @@ -1562,6 +1590,10 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { mount_enter_dead_or_mounted(m, f); break; + case MOUNT_UNMOUNTING_CATCHUP: + log_unit_debug(u, "Was notified about control process death, but wasn't expecting it. Ignoring."); + break; + case MOUNT_CLEANING: if (m->clean_result == MOUNT_SUCCESS) m->clean_result = f; @@ -1636,6 +1668,11 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT); break; + case MOUNT_UNMOUNTING_CATCHUP: + log_unit_warning(UNIT(m), "Waiting for unmount notification timed out. Giving up."); + mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT); + break; + case MOUNT_CLEANING: log_unit_warning(UNIT(m), "Cleaning timed out. killing."); @@ -2077,8 +2114,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) { if (!mount_is_mounted(mount)) { - /* A mount point is not around right now. It - * might be gone, or might never have + /* A mount point is not around right now. It might be gone, or might never have * existed. */ if (mount->from_proc_self_mountinfo && @@ -2093,6 +2129,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) { switch (mount->state) { case MOUNT_MOUNTED: + case MOUNT_UNMOUNTING_CATCHUP: /* This has just been unmounted by somebody else, follow the state change. */ mount_enter_dead(mount, MOUNT_SUCCESS); break; @@ -2131,11 +2168,9 @@ static int mount_process_proc_self_mountinfo(Manager *m) { break; default: - /* Nothing really changed, but let's - * issue an notification call - * nonetheless, in case somebody is - * waiting for this. (e.g. file system - * ro/rw remounts.) */ + /* Nothing really changed, but let's issue an notification call nonetheless, + * in case somebody is waiting for this. (e.g. file system ro/rw + * remounts.) */ mount_set_state(mount, mount->state); break; } From 00078fb3096d8a117f4c4322f1804bb7d95bcbc4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 3 May 2023 21:54:29 +0200 Subject: [PATCH 6/6] execute: add missing NULL handling --- src/core/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/execute.c b/src/core/execute.c index 6595931809..5e327465da 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2787,7 +2787,7 @@ static char **credential_search_path( if (DEBUG_LOGGING) { _cleanup_free_ char *t = strv_join(l, ":"); - log_debug("Credential search path is: %s", t); + log_debug("Credential search path is: %s", strempty(t)); } return TAKE_PTR(l);