]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredump: Try to write journald coredump metadata to the journal
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 13 Jul 2022 12:46:33 +0000 (14:46 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 15 Jul 2022 18:27:00 +0000 (19:27 +0100)
Currently, if journald coredumps, the coredump is written to
/var/lib/systemd/coredump but the coredump metadata is not written
to  the journal meaning we can't find out about the coredump's
existence via the journal. This means that coredumpctl can't be
used to work with journald coredumps, as well as any other tools
that rely on journald to know about coredumps.

To solve the issue, let's have systemd-coredump try to write
systemd-journald coredump metadata to the journal. We have to be
careful though, since if journald coredumps, there's no active
reader on the receive end of the journal socket, so we have to make
sure we don't deadlock trying to write to the socket. To avoid the
deadlock, we put the socket in nonblocking mode before trying to
write to it.

src/coredump/coredump.c
src/libsystemd/sd-journal/journal-send.c
src/libsystemd/sd-journal/journal-send.h

index 10a96ab568f1d251be9f532403cc0f0c326286aa..3ec41a32c37cc033f7ea910e08bf4eceafbbf47e 100644 (file)
@@ -29,6 +29,7 @@
 #include "fs-util.h"
 #include "io-util.h"
 #include "journal-importer.h"
+#include "journal-send.h"
 #include "log.h"
 #include "macro.h"
 #include "main-func.h"
@@ -842,12 +843,10 @@ log:
 
         core_message = strjoina(core_message, stacktrace ? "\n\n" : NULL, stacktrace);
 
-        if (context->is_journald) {
-                /* We cannot log to the journal, so just print the message.
-                 * The target was set previously to something safe. */
+        if (context->is_journald)
+                /* We might not be able to log to the journal, so let's always print the message to another
+                 * log target. The target was set previously to something safe. */
                 log_dispatch(LOG_ERR, 0, core_message);
-                return 0;
-        }
 
         (void) iovw_put_string_field(iovw, "MESSAGE=", core_message);
 
@@ -903,8 +902,29 @@ log:
                                  coredump_size, arg_journal_size_max);
         }
 
+        /* If journald is coredumping, we have to be careful that we don't deadlock when trying to write the
+         * coredump to the journal, so we put the journal socket in nonblocking mode before trying to write
+         * the coredump to the socket. */
+
+        if (context->is_journald) {
+                r = journal_fd_nonblock(true);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to make journal socket non-blocking: %m");
+        }
+
         r = sd_journal_sendv(iovw->iovec, iovw->count);
-        if (r < 0)
+
+        if (context->is_journald) {
+                int k;
+
+                k = journal_fd_nonblock(false);
+                if (k < 0)
+                        return log_error_errno(k, "Failed to make journal socket blocking: %m");
+        }
+
+        if (r == -EAGAIN && context->is_journald)
+                log_warning_errno(r, "Failed to log journal coredump, ignoring: %m");
+        else if (r < 0)
                 return log_error_errno(r, "Failed to log coredump: %m");
 
         return 0;
index e1c40702d38748a6b80cebf4533f0fdf838b259e..81e3c81a0bb89a1af3a46763aad980278c6d2751 100644 (file)
@@ -66,6 +66,16 @@ retry:
         return fd;
 }
 
+int journal_fd_nonblock(bool nonblock) {
+        int r;
+
+        r = journal_fd();
+        if (r < 0)
+                return r;
+
+        return fd_nonblock(r, nonblock);
+}
+
 #if VALGRIND
 void close_journal_fd(void) {
         /* Be nice to valgrind. This is not atomic. This must be used only in tests. */
@@ -318,7 +328,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
         if (errno == ENOENT)
                 return 0;
 
-        if (!IN_SET(errno, EMSGSIZE, ENOBUFS))
+        if (!IN_SET(errno, EMSGSIZE, ENOBUFS, EAGAIN))
                 return -errno;
 
         /* Message doesn't fit... Let's dump the data in a memfd or
index cf8b199297cf6a24f16a1a7d359dbbf8bc348350..558d39a8c08236a46a8c95b3aaa98090a3571614 100644 (file)
@@ -1,6 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <stdbool.h>
+
+int journal_fd_nonblock(bool nonblock);
+
 #if VALGRIND
 void close_journal_fd(void);
 #else