Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:Update
systemd.16890
0001-logind-unmount-runtime-path-in-a-dedicated...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-logind-unmount-runtime-path-in-a-dedicated-process.patch of Package systemd.16890
From af4eb5b0bafecde8e8366f5632d5676cd74e108d Mon Sep 17 00:00:00 2001 From: Franck Bui <fbui@suse.com> Date: Wed, 6 Mar 2019 08:55:15 +0100 Subject: [PATCH] logind: unmount runtime path in a dedicated process While unmounting user's runtime directory the kernel can take unexpected long delay in some corner cases (see bsc#1104902). As a workaround, we unmount it asynchronously but before we need to move it out of the way so it's still safe if the user decices to log in right after logging out and the asynchronous unmount has still not finished. Workaround for bsc#1104902 --- src/login/logind-user.c | 74 +++++++++++++++++++++++++++++++++++++++++++------ src/login/logind.c | 8 ++++++ 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index e320a58481..bdbc364984 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -45,6 +45,7 @@ #include "path-util.h" #include "rm-rf.h" #include "smack-util.h" +#include "signal-util.h" #include "special.h" #include "stdio-util.h" #include "string-table.h" @@ -546,29 +547,86 @@ static int user_stop_service(User *u) { return r; } -static int user_remove_runtime_path(User *u) { +static int user_unmount_runtime_path(const char *runtime_path) { int r; - assert(u); + log_debug("unmounting runtime path %s" , runtime_path); - r = rm_rf(u->runtime_path, 0); + r = rm_rf(runtime_path, 0); if (r < 0) - log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path); + log_error_errno(r, "Failed to remove runtime directory %s: %m", runtime_path); /* Ignore cases where the directory isn't mounted, as that's * quite possible, if we lacked the permissions to mount * something */ - r = umount2(u->runtime_path, MNT_DETACH); + r = umount2(runtime_path, MNT_DETACH); if (r < 0 && errno != EINVAL && errno != ENOENT) - log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path); + log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", runtime_path); - r = rm_rf(u->runtime_path, REMOVE_ROOT); + r = rm_rf(runtime_path, REMOVE_ROOT); if (r < 0) - log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path); + log_error_errno(r, "Failed to remove runtime directory %s (after unmounting): %m", runtime_path); return r; } +static int user_remove_runtime_path(User *u) { + char tmpdir_template[] = "/run/systemd/users/deported-user-runtime-directory-XXXXXX"; + char *tmpdir; + pid_t pid; + int r; + + assert(u); + + /* SUSE: unmounting user's runtime directory can cause + * unexpected long delay in some corner cases (see + * bsc#1127557). As a workaround, we unmount it asynchronously + * but we need to move it out of the way before so it's still + * safe if the user decices to log in right after logging out + * and the asynchronous unmount has still not finished. */ + + /* First bind mount the user runtime path into another + * place. If for some reasons it hasn't been mounted + * initially, this is pretty pointless but should be harmless + * too. If that fails for any reason then fallback to a + * synchronous unmount like it was originally done .*/ + tmpdir = mkdtemp(tmpdir_template); + if (tmpdir) { + r = mount(u->runtime_path, tmpdir, NULL, MS_BIND, NULL); + if (r < 0) + log_error_errno(errno, "Failed to bind user runtime directory to %s: %m", tmpdir); + } else + log_error_errno(errno, "Failed to create temporary dir %s: %m", tmpdir_template); + + /* Unmount the original user runtime path: this shouldn't + * cause unexpected long delay since the user runtime dir is + * accessible in two places now: the kernel shouldn't try to + * clean up all related internal data on the first unmount. */ + r = user_unmount_runtime_path(u->runtime_path); + if (r < 0) + log_error_errno(r, "Failed to unmount user runtime path %s: %m", u->runtime_path); + + if (tmpdir) { + pid = fork(); + if (pid < 0) + return log_error_errno(errno, "Failed to fork: %m"); + if (pid == 0) { + (void) reset_all_signal_handlers(); + (void) reset_signal_mask(); + + close_all_fds(NULL, 0); + log_forget_fds(); + log_open(); + + /* Now the runtime path should really be unmounted */ + r = user_unmount_runtime_path(tmpdir); + _exit(r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE); + } + } + + return 0; +} + int user_stop(User *u, bool force) { Session *s; int r = 0, k; diff --git a/src/login/logind.c b/src/login/logind.c index b0db5e62f4..c906e3d4ba 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1159,6 +1159,14 @@ int main(int argc, char *argv[]) { mkdir_label("/run/systemd/users", 0755); mkdir_label("/run/systemd/sessions", 0755); + /* SUSE: let the kernel reap our children for us. It's needed + * because we added a hack to unmount user's runtime directory + * asynchrounously to workaround a kernel issue (see + * bsc#1127557). Fortunately it's not needed by recent systemd + * (v239 an later) since it is done by + * user-runtime-dir@.service. */ + assert_se(ignore_signals(SIGCHLD, -1) >= 0); + m = manager_new(); if (!m) { r = log_oom(); -- 2.16.4
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor