Blame SOURCES/0559-journal-ensure-open-journals-from-find_journal-3973.patch

17b0f1
From b36c31ddc2f3427ea2a1f700db08d8e104e4110a Mon Sep 17 00:00:00 2001
17b0f1
From: Jan Synacek <jsynacek@redhat.com>
17b0f1
Date: Thu, 5 Oct 2017 11:26:21 +0200
17b0f1
Subject: [PATCH] journal: ensure open journals from find_journal() (#3973)
17b0f1
17b0f1
If journals get into a closed state like when rotate fails due to
17b0f1
ENOSPC, when space is made available it currently goes unnoticed leaving
17b0f1
the journals in a closed state indefinitely.
17b0f1
17b0f1
By calling system_journal_open() on entry to find_journal() we ensure
17b0f1
the journal has been opened/created if possible.
17b0f1
17b0f1
Also moved system_journal_open() up to after open_journal(), before
17b0f1
find_journal().
17b0f1
17b0f1
Fixes https://github.com/systemd/systemd/issues/3968
17b0f1
17b0f1
(cherry picked from commit 105bdb46b4ac7eb658a2f27727216591d0bfe267)
17b0f1
17b0f1
Resolves: #1493846
17b0f1
---
17b0f1
 src/journal/journald-server.c | 217 ++++++++++++++++++----------------
17b0f1
 1 file changed, 114 insertions(+), 103 deletions(-)
17b0f1
17b0f1
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
17b0f1
index c1358e1e95..96e7d61565 100644
17b0f1
--- a/src/journal/journald-server.c
17b0f1
+++ b/src/journal/journald-server.c
17b0f1
@@ -239,6 +239,109 @@ finish:
17b0f1
 #endif
17b0f1
 }
17b0f1
 
17b0f1
+static bool flushed_flag_is_set(void) {
17b0f1
+        return access("/run/systemd/journal/flushed", F_OK) >= 0;
17b0f1
+}
17b0f1
+
17b0f1
+static int system_journal_open(Server *s, bool flush_requested) {
17b0f1
+        int r;
17b0f1
+        char *fn;
17b0f1
+        sd_id128_t machine;
17b0f1
+        char ids[33];
17b0f1
+
17b0f1
+        r = sd_id128_get_machine(&machine);
17b0f1
+        if (r < 0)
17b0f1
+                return log_error_errno(r, "Failed to get machine id: %m");
17b0f1
+
17b0f1
+        sd_id128_to_string(machine, ids);
17b0f1
+
17b0f1
+        if (!s->system_journal &&
17b0f1
+            IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
17b0f1
+            (flush_requested || flushed_flag_is_set())) {
17b0f1
+
17b0f1
+                /* If in auto mode: first try to create the machine
17b0f1
+                 * path, but not the prefix.
17b0f1
+                 *
17b0f1
+                 * If in persistent mode: create /var/log/journal and
17b0f1
+                 * the machine path */
17b0f1
+
17b0f1
+                if (s->storage == STORAGE_PERSISTENT)
17b0f1
+                        (void) mkdir_p("/var/log/journal/", 0755);
17b0f1
+
17b0f1
+                fn = strjoina("/var/log/journal/", ids);
17b0f1
+                (void) mkdir(fn, 0755);
17b0f1
+
17b0f1
+                fn = strjoina(fn, "/system.journal");
17b0f1
+                r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
17b0f1
+
17b0f1
+                if (r >= 0)
17b0f1
+                        server_fix_perms(s, s->system_journal, 0);
17b0f1
+                else if (r < 0) {
17b0f1
+                        if (r != -ENOENT && r != -EROFS)
17b0f1
+                                log_warning_errno(r, "Failed to open system journal: %m");
17b0f1
+
17b0f1
+                        r = 0;
17b0f1
+                }
17b0f1
+
17b0f1
+                /* If the runtime journal is open, and we're post-flush, we're
17b0f1
+                 * recovering from a failed system journal rotate (ENOSPC)
17b0f1
+                 * for which the runtime journal was reopened.
17b0f1
+                 *
17b0f1
+                 * Perform an implicit flush to var, leaving the runtime
17b0f1
+                 * journal closed, now that the system journal is back.
17b0f1
+                 */
17b0f1
+                if (!flush_requested)
17b0f1
+                        (void) server_flush_to_var(s, true);
17b0f1
+        }
17b0f1
+
17b0f1
+        if (!s->runtime_journal &&
17b0f1
+            (s->storage != STORAGE_NONE)) {
17b0f1
+
17b0f1
+                fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL);
17b0f1
+                if (!fn)
17b0f1
+                        return -ENOMEM;
17b0f1
+
17b0f1
+                if (s->system_journal) {
17b0f1
+
17b0f1
+                        /* Try to open the runtime journal, but only
17b0f1
+                         * if it already exists, so that we can flush
17b0f1
+                         * it into the system journal */
17b0f1
+
17b0f1
+                        r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
17b0f1
+                        free(fn);
17b0f1
+
17b0f1
+                        if (r < 0) {
17b0f1
+                                if (r != -ENOENT)
17b0f1
+                                        log_warning_errno(r, "Failed to open runtime journal: %m");
17b0f1
+
17b0f1
+                                r = 0;
17b0f1
+                        }
17b0f1
+
17b0f1
+                } else {
17b0f1
+
17b0f1
+                        /* OK, we really need the runtime journal, so create
17b0f1
+                         * it if necessary. */
17b0f1
+
17b0f1
+                        (void) mkdir("/run/log", 0755);
17b0f1
+                        (void) mkdir("/run/log/journal", 0755);
17b0f1
+                        (void) mkdir_parents(fn, 0750);
17b0f1
+
17b0f1
+                        r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
17b0f1
+                        free(fn);
17b0f1
+
17b0f1
+                        if (r < 0)
17b0f1
+                                return log_error_errno(r, "Failed to open runtime journal: %m");
17b0f1
+                }
17b0f1
+
17b0f1
+                if (s->runtime_journal)
17b0f1
+                        server_fix_perms(s, s->runtime_journal, 0);
17b0f1
+        }
17b0f1
+
17b0f1
+        available_space(s, true);
17b0f1
+
17b0f1
+        return r;
17b0f1
+}
17b0f1
+
17b0f1
 static JournalFile* find_journal(Server *s, uid_t uid) {
17b0f1
         _cleanup_free_ char *p = NULL;
17b0f1
         int r;
17b0f1
@@ -247,6 +350,17 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
17b0f1
 
17b0f1
         assert(s);
17b0f1
 
17b0f1
+        /* A rotate that fails to create the new journal (ENOSPC) leaves the
17b0f1
+         * rotated journal as NULL.  Unless we revisit opening, even after
17b0f1
+         * space is made available we'll continue to return NULL indefinitely.
17b0f1
+         *
17b0f1
+         * system_journal_open() is a noop if the journals are already open, so
17b0f1
+         * we can just call it here to recover from failed rotates (or anything
17b0f1
+         * else that's left the journals as NULL).
17b0f1
+         *
17b0f1
+         * Fixes https://github.com/systemd/systemd/issues/3968 */
17b0f1
+        (void) system_journal_open(s, false);
17b0f1
+
17b0f1
         /* We split up user logs only on /var, not on /run. If the
17b0f1
          * runtime file is open, we write to it exclusively, in order
17b0f1
          * to guarantee proper order as soon as we flush /run to
17b0f1
@@ -917,109 +1031,6 @@ finish:
17b0f1
         dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid);
17b0f1
 }
17b0f1
 
17b0f1
-static bool flushed_flag_is_set(void) {
17b0f1
-        return access("/run/systemd/journal/flushed", F_OK) >= 0;
17b0f1
-}
17b0f1
-
17b0f1
-static int system_journal_open(Server *s, bool flush_requested) {
17b0f1
-        int r;
17b0f1
-        char *fn;
17b0f1
-        sd_id128_t machine;
17b0f1
-        char ids[33];
17b0f1
-
17b0f1
-        r = sd_id128_get_machine(&machine);
17b0f1
-        if (r < 0)
17b0f1
-                return log_error_errno(r, "Failed to get machine id: %m");
17b0f1
-
17b0f1
-        sd_id128_to_string(machine, ids);
17b0f1
-
17b0f1
-        if (!s->system_journal &&
17b0f1
-            IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
17b0f1
-            (flush_requested || flushed_flag_is_set())) {
17b0f1
-
17b0f1
-                /* If in auto mode: first try to create the machine
17b0f1
-                 * path, but not the prefix.
17b0f1
-                 *
17b0f1
-                 * If in persistent mode: create /var/log/journal and
17b0f1
-                 * the machine path */
17b0f1
-
17b0f1
-                if (s->storage == STORAGE_PERSISTENT)
17b0f1
-                        (void) mkdir_p("/var/log/journal/", 0755);
17b0f1
-
17b0f1
-                fn = strjoina("/var/log/journal/", ids);
17b0f1
-                (void) mkdir(fn, 0755);
17b0f1
-
17b0f1
-                fn = strjoina(fn, "/system.journal");
17b0f1
-                r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
17b0f1
-
17b0f1
-                if (r >= 0)
17b0f1
-                        server_fix_perms(s, s->system_journal, 0);
17b0f1
-                else if (r < 0) {
17b0f1
-                        if (r != -ENOENT && r != -EROFS)
17b0f1
-                                log_warning_errno(r, "Failed to open system journal: %m");
17b0f1
-
17b0f1
-                        r = 0;
17b0f1
-                }
17b0f1
-
17b0f1
-                /* If the runtime journal is open, and we're post-flush, we're
17b0f1
-                 * recovering from a failed system journal rotate (ENOSPC)
17b0f1
-                 * for which the runtime journal was reopened.
17b0f1
-                 *
17b0f1
-                 * Perform an implicit flush to var, leaving the runtime
17b0f1
-                 * journal closed, now that the system journal is back.
17b0f1
-                 */
17b0f1
-                if (!flush_requested)
17b0f1
-                        (void) server_flush_to_var(s, true);
17b0f1
-        }
17b0f1
-
17b0f1
-        if (!s->runtime_journal &&
17b0f1
-            (s->storage != STORAGE_NONE)) {
17b0f1
-
17b0f1
-                fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL);
17b0f1
-                if (!fn)
17b0f1
-                        return -ENOMEM;
17b0f1
-
17b0f1
-                if (s->system_journal) {
17b0f1
-
17b0f1
-                        /* Try to open the runtime journal, but only
17b0f1
-                         * if it already exists, so that we can flush
17b0f1
-                         * it into the system journal */
17b0f1
-
17b0f1
-                        r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
17b0f1
-                        free(fn);
17b0f1
-
17b0f1
-                        if (r < 0) {
17b0f1
-                                if (r != -ENOENT)
17b0f1
-                                        log_warning_errno(r, "Failed to open runtime journal: %m");
17b0f1
-
17b0f1
-                                r = 0;
17b0f1
-                        }
17b0f1
-
17b0f1
-                } else {
17b0f1
-
17b0f1
-                        /* OK, we really need the runtime journal, so create
17b0f1
-                         * it if necessary. */
17b0f1
-
17b0f1
-                        (void) mkdir("/run/log", 0755);
17b0f1
-                        (void) mkdir("/run/log/journal", 0755);
17b0f1
-                        (void) mkdir_parents(fn, 0750);
17b0f1
-
17b0f1
-                        r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
17b0f1
-                        free(fn);
17b0f1
-
17b0f1
-                        if (r < 0)
17b0f1
-                                return log_error_errno(r, "Failed to open runtime journal: %m");
17b0f1
-                }
17b0f1
-
17b0f1
-                if (s->runtime_journal)
17b0f1
-                        server_fix_perms(s, s->runtime_journal, 0);
17b0f1
-        }
17b0f1
-
17b0f1
-        available_space(s, true);
17b0f1
-
17b0f1
-        return r;
17b0f1
-}
17b0f1
-
17b0f1
 int server_flush_to_var(Server *s, bool require_flag_file) {
17b0f1
         sd_id128_t machine;
17b0f1
         sd_journal *j = NULL;