]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: make sure our container PID 1 keeps logging to the original stderr as long... 9068/head
authorLennart Poettering <lennart@poettering.net>
Tue, 22 May 2018 14:52:50 +0000 (16:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 22 May 2018 14:52:50 +0000 (16:52 +0200)
If we log to the pty that is configured as stdin/stdout/stderr of the
container too early we risk filling it up in full before we start
processing the pty from the parent process, resulting in deadlocks.
Let's hence keep a copy of the original tty we were started on before
setting up stdin/stdout/stderr, so that we can log to it, and keep using
it as long as we can.

Since the kernel's pty internal buffer is pretty small this actually
triggered deadlocks when we debug logged at lot from nspawn's child
processes, see: https://github.com/systemd/systemd/pull/9024#issuecomment-390403674

With this change we won't use the pty at all, only the actual payload we
start will, and hence we won't deadlock on it, ever.

src/basic/log.c
src/basic/log.h
src/nspawn/nspawn.c

index 6f4424201105cbcaaf519b382f39bdb11011fa8a..5db65f276f75c3f28ce0224087a60029e9f81a0b 100644 (file)
@@ -1330,3 +1330,20 @@ int log_emergency_level(void) {
 
         return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
 }
+
+int log_dup_console(void) {
+        int copy;
+
+        /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
+         * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
+
+        if (console_fd >= 3)
+                return 0;
+
+        copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3);
+        if (copy < 0)
+                return -errno;
+
+        console_fd = copy;
+        return 0;
+}
index 63cfd298ec17338b6c57bafed0c554062884988e..6a8cf6375f11926e4355968c40d57cc35339ab5f 100644 (file)
@@ -284,6 +284,8 @@ void log_set_open_when_needed(bool b);
  * stderr, the console or kmsg */
 void log_set_prohibit_ipc(bool b);
 
+int log_dup_console(void);
+
 int log_syntax_internal(
                 const char *unit,
                 int level,
index b1add0f1590b567362bc550d9602e4ab52dd7881..cc1f4c2da0b767fe892652f05df0a7718c580e6c 100644 (file)
@@ -2720,6 +2720,11 @@ static int outer_child(
                 if (terminal < 0)
                         return log_error_errno(terminal, "Failed to open console: %m");
 
+                /* Make sure we can continue logging to the original stderr, even if stderr points elsewhere now */
+                r = log_dup_console();
+                if (r < 0)
+                        return log_error_errno(r, "Failed to duplicate stderr: %m");
+
                 r = rearrange_stdio(terminal, terminal, terminal); /* invalidates 'terminal' on success and failure */
                 if (r < 0)
                         return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");