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