]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #30263 from msizanoen1/fix-onboot-rotate-2
authorLennart Poettering <lennart@poettering.net>
Fri, 16 Feb 2024 11:02:09 +0000 (12:02 +0100)
committerGitHub <noreply@github.com>
Fri, 16 Feb 2024 11:02:09 +0000 (12:02 +0100)
journal: Reset runtime seqnum data when flushing to system journal

src/journal/journald-server.c
src/libsystemd/sd-journal/journal-internal.h
src/libsystemd/sd-journal/sd-journal.c
test/units/testsuite-09.journal.sh
test/units/testsuite-09.sh

index da73b668b61ae01252258dac1296ed1cd21336b2..bb251be7cc56bf3f63a091da5fbf6b0c042fd667 100644 (file)
@@ -42,6 +42,7 @@
 #include "journald-stream.h"
 #include "journald-syslog.h"
 #include "log.h"
+#include "memory-util.h"
 #include "missing_audit.h"
 #include "mkdir.h"
 #include "parse-util.h"
@@ -1274,6 +1275,10 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
         if (!s->system_journal)
                 return 0;
 
+        /* Reset current seqnum data to avoid unnecessary rotation when switching to system journal.
+         * See issue #30092. */
+        zero(*s->seqnum);
+
         log_debug("Flushing to %s...", s->system_storage.path);
 
         start = now(CLOCK_MONOTONIC);
@@ -1347,12 +1352,29 @@ finish:
         if (s->system_journal)
                 journal_file_post_change(s->system_journal);
 
+        /* Save parent directories of runtime journals before closing runtime journals. */
+        _cleanup_strv_free_ char **dirs = NULL;
+        (void) journal_get_directories(j, &dirs);
+
+        /* First, close all runtime journals opened in the above. */
+        sd_journal_close(j);
+
+        /* Offline and close the 'main' runtime journal file. */
         s->runtime_journal = journal_file_offline_close(s->runtime_journal);
 
-        if (r >= 0)
+        /* Remove the runtime directory if the all entries are successfully flushed to /var/. */
+        if (r >= 0) {
                 (void) rm_rf(s->runtime_storage.path, REMOVE_ROOT);
 
-        sd_journal_close(j);
+                /* The initrd may have a different machine ID from the host's one. Typically, that happens
+                 * when our tests running on qemu, as the host's initrd is picked as is without updating
+                 * the machine ID in the initrd with the one used in the image. Even in such the case, the
+                 * runtime journals in the subdirectory named with the initrd's machine ID are flushed to
+                 * the persistent journal. To make not the runtime journal flushed multiple times, let's
+                 * also remove the runtime directories. */
+                STRV_FOREACH(p, dirs)
+                        (void) rm_rf(*p, REMOVE_ROOT);
+        }
 
         server_driver_message(s, 0, NULL,
                               LOG_MESSAGE("Time spent on flushing to %s is %s for %u entries.",
index 0293389a78a3ffc1f162c461b73c24e87645d67e..cddc2316af495ed7a4adf51bd0af12d5224af093 100644 (file)
@@ -138,6 +138,7 @@ struct sd_journal {
 
 char *journal_make_match_string(sd_journal *j);
 void journal_print_header(sd_journal *j);
+int journal_get_directories(sd_journal *j, char ***ret);
 
 #define JOURNAL_FOREACH_DATA_RETVAL(j, data, l, retval)                     \
         for (sd_journal_restart_data(j); ((retval) = sd_journal_enumerate_data((j), &(data), &(l))) > 0; )
index 1c2e273841dd688714faf8fe2141f5bd0b1fba63..fba436fbe3f0e1afadb3b86f45c2d3cb7c371989 100644 (file)
@@ -1594,6 +1594,41 @@ error:
         return r;
 }
 
+int journal_get_directories(sd_journal *j, char ***ret) {
+        _cleanup_strv_free_ char **paths = NULL;
+        JournalFile *f;
+        const char *p;
+        size_t n = SIZE_MAX;
+        int r;
+
+        assert(j);
+        assert(ret);
+
+        /* This returns parent directories of opened journal files. */
+
+        ORDERED_HASHMAP_FOREACH_KEY(f, p, j->files) {
+                _cleanup_free_ char *d = NULL;
+
+                /* Ignore paths generated from fd. */
+                if (path_startswith(p, "/proc/"))
+                        continue;
+
+                r = path_extract_directory(p, &d);
+                if (r < 0)
+                        return r;
+
+                if (path_strv_contains(paths, d))
+                        continue;
+
+                r = strv_extend_with_size(&paths, &n, d);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(paths);
+        return 0;
+}
+
 static int add_file_by_name(
                 sd_journal *j,
                 const char *prefix,
index 2ef192c7a87b429ef5151afe75b85b2674dbaa1c..136d905ab9310a010717e7638c0ccb09483d5587 100755 (executable)
@@ -70,3 +70,47 @@ journalctl --list-boots -o json | jq -r '.[] | [.index, .boot_id, .first_entry,
             assert_eq "$entry_ts" "$last_ts"
         fi
     done
+
+verify_seqnum() {
+    if [[ "$REBOOT_COUNT" -ne "$NUM_REBOOT" ]]; then
+        return 0
+    fi
+
+    journalctl --flush
+    journalctl --sync
+
+    ls -lR /var/log/journal/
+    ls -lR /run/log/journal/
+
+    journalctl --system --header
+
+    (! journalctl --system -q -o short-monotonic -u systemd-journald.service --grep 'rotating')
+
+    set +x
+    previous_seqnum=0
+    previous_seqnum_id=
+    previous_boot_id=
+    journalctl --system -q -o json | jq -r '[.__SEQNUM, .__SEQNUM_ID, ._BOOT_ID] | @tsv' |
+        while read -r seqnum seqnum_id boot_id; do
+
+            if [[ -n "$previous_seqnum_id" ]]; then
+                if ! test "$seqnum" -gt "$previous_seqnum"; then
+                    echo "seqnum=$seqnum is not greater than previous_seqnum=$previous_seqnum"
+                    echo "seqnum_id=$seqnum_id, previous_seqnum_id=$previous_seqnum_id"
+                    echo "boot_id=$boot_id, previous_boot_id=$previous_boot_id"
+                    return 1
+                fi
+
+                assert_eq "$seqnum_id" "$previous_seqnum_id"
+            fi
+
+            previous_seqnum="$seqnum"
+            previous_seqnum_id="$seqnum_id"
+            previous_boot_id="$boot_id"
+        done
+    set -x
+
+    return 0
+}
+
+verify_seqnum
index cd95660021152bdf5af206bf5a2571c7b10b410a..85630b618bcfef74e0c2d6c43204610a52e0fc21 100755 (executable)
@@ -3,7 +3,7 @@
 set -eux
 set -o pipefail
 
-NUM_REBOOT=4
+export NUM_REBOOT=4
 
 # shellcheck source=test/units/test-control.sh
 . "$(dirname "$0")"/test-control.sh