diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index d31da2d129..dceb4cddb6 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -278,7 +278,10 @@ static int open_journal( assert(fname); assert(ret); - file_flags = (s->compress.enabled ? JOURNAL_COMPRESS : 0) | (seal ? JOURNAL_SEAL : 0); + file_flags = + (s->compress.enabled ? JOURNAL_COMPRESS : 0) | + (seal ? JOURNAL_SEAL : 0) | + JOURNAL_STRICT_ORDER; if (reliably) r = managed_journal_file_open_reliably( @@ -290,11 +293,11 @@ static int open_journal( metrics, s->mmap, s->deferred_closes, - NULL, + /* template= */ NULL, &f); else r = managed_journal_file_open( - -1, + /* fd= */ -1, fname, open_flags, file_flags, @@ -303,9 +306,8 @@ static int open_journal( metrics, s->mmap, s->deferred_closes, - NULL, + /* template= */ NULL, &f); - if (r < 0) return r; @@ -350,7 +352,14 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_ (void) mkdir(s->system_storage.path, 0755); fn = strjoina(s->system_storage.path, "/system.journal"); - r = open_journal(s, true, fn, O_RDWR|O_CREAT, s->seal, &s->system_storage.metrics, &s->system_journal); + r = open_journal( + s, + /* reliably= */ true, + fn, + O_RDWR|O_CREAT, + s->seal, + &s->system_storage.metrics, + &s->system_journal); if (r >= 0) { server_add_acls(s->system_journal, 0); (void) cache_space_refresh(s, &s->system_storage); @@ -380,11 +389,17 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_ if (s->system_journal && !relinquish_requested) { - /* Try to open the runtime journal, but only - * if it already exists, so that we can flush - * it into the system journal */ + /* Try to open the runtime journal, but only if it already exists, so that we can + * flush it into the system journal */ - r = open_journal(s, false, fn, O_RDWR, false, &s->runtime_storage.metrics, &s->runtime_journal); + r = open_journal( + s, + /* reliably= */ false, + fn, + O_RDWR, + /* seal= */ false, + &s->runtime_storage.metrics, + &s->runtime_journal); if (r < 0) { if (r != -ENOENT) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, @@ -400,7 +415,14 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_ (void) mkdir_parents(s->runtime_storage.path, 0755); (void) mkdir(s->runtime_storage.path, 0750); - r = open_journal(s, true, fn, O_RDWR|O_CREAT, false, &s->runtime_storage.metrics, &s->runtime_journal); + r = open_journal( + s, + /* reliably= */ true, + fn, + O_RDWR|O_CREAT, + /* seal= */ false, + &s->runtime_storage.metrics, + &s->runtime_journal); if (r < 0) return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to open runtime journal: %m"); @@ -438,7 +460,14 @@ static int find_user_journal(Server *s, uid_t uid, ManagedJournalFile **ret) { (void) managed_journal_file_close(first); } - r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_storage.metrics, &f); + r = open_journal( + s, + /* reliably= */ true, + p, + O_RDWR|O_CREAT, + s->seal, + &s->system_storage.metrics, + &f); if (r < 0) return r; @@ -511,7 +540,8 @@ static int do_rotate( file_flags = (s->compress.enabled ? JOURNAL_COMPRESS : 0)| - (seal ? JOURNAL_SEAL : 0); + (seal ? JOURNAL_SEAL : 0) | + JOURNAL_STRICT_ORDER; r = managed_journal_file_rotate(f, s->mmap, file_flags, s->compress.threshold_bytes, s->deferred_closes); if (r < 0) { @@ -624,13 +654,13 @@ static int server_archive_offline_user_journals(Server *s) { full, O_RDWR, (s->compress.enabled ? JOURNAL_COMPRESS : 0) | - (s->seal ? JOURNAL_SEAL : 0), + (s->seal ? JOURNAL_SEAL : 0), /* strict order does not matter here */ 0640, s->compress.threshold_bytes, &s->system_storage.metrics, s->mmap, s->deferred_closes, - NULL, + /* template= */ NULL, &f); if (r < 0) { log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, @@ -844,8 +874,16 @@ static bool shall_try_append_again(JournalFile *f, int r) { log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Journal file is from the future, rotating.", f->path); return true; - case -EREMCHG: /* Time jumped backwards relative to last journal entry */ - log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Time jumped backwards relative to last journal entry, rotating.", f->path); + case -EREMCHG: /* Wallclock time (CLOCK_REALTIME) jumped backwards relative to last journal entry */ + log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Realtime clock jumped backwards relative to last journal entry, rotating.", f->path); + return true; + + case -EREMOTE: /* Boot ID different from the one of the last entry */ + log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Boot ID changed since last record, rotating.", f->path); + return true; + + case -ENOTNAM: /* Monotonic time (CLOCK_MONOTONIC) jumped backwards relative to last journal entry */ + log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Montonic clock jumped backwards relative to last journal entry, rotating.", f->path); return true; case -EAFNOSUPPORT: diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index d46d4914d4..cde0298262 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -334,7 +334,11 @@ static bool compact_mode_requested(void) { return true; } -static int journal_file_init_header(JournalFile *f, JournalFileFlags file_flags, JournalFile *template) { +static int journal_file_init_header( + JournalFile *f, + JournalFileFlags file_flags, + JournalFile *template) { + bool seal = false; ssize_t k; int r; @@ -2092,11 +2096,37 @@ static int journal_file_append_entry_internal( assert(ts); assert(items || n_items == 0); - if (ts->realtime < le64toh(f->header->tail_entry_realtime)) - return log_debug_errno(SYNTHETIC_ERRNO(EREMCHG), - "Realtime timestamp %" PRIu64 " smaller than previous realtime " - "timestamp %" PRIu64 ", refusing entry.", - ts->realtime, le64toh(f->header->tail_entry_realtime)); + if (f->strict_order) { + /* If requested be stricter with ordering in this journal file, to make searching via + * bisection fully deterministic. This is an optional feature, so that if desired journal + * files can be written where the ordering is not strictly enforced (in which case bisection + * will yield *a* result, but not the *only* result, when searching for points in + * time). Strict ordering mode is enabled when journald originally writes the files, but + * might not necessarily be if other tools (the remoting tools for example) write journal + * files from combined sources. + * + * Typically, if any of the errors generated here are seen journald will just rotate the + * journal files and start anew. */ + + if (ts->realtime < le64toh(f->header->tail_entry_realtime)) + return log_debug_errno(SYNTHETIC_ERRNO(EREMCHG), + "Realtime timestamp %" PRIu64 " smaller than previous realtime " + "timestamp %" PRIu64 ", refusing entry.", + ts->realtime, le64toh(f->header->tail_entry_realtime)); + + if (!sd_id128_is_null(f->header->boot_id) && boot_id) { + + if (!sd_id128_equal(f->header->boot_id, *boot_id)) + return log_debug_errno(SYNTHETIC_ERRNO(EREMOTE), + "Boot ID to write is different from previous boot id, refusing entry."); + + if (ts->monotonic < le64toh(f->header->tail_entry_monotonic)) + return log_debug_errno(SYNTHETIC_ERRNO(ENOTNAM), + "Monotonic timestamp %" PRIu64 " smaller than previous monotonic " + "timestamp %" PRIu64 ", refusing entry.", + ts->monotonic, le64toh(f->header->tail_entry_monotonic)); + } + } osize = offsetof(Object, entry.items) + (n_items * journal_file_entry_item_size(f)); @@ -3719,6 +3749,8 @@ int journal_file_open( int r; assert(fd >= 0 || fname); + assert(file_flags >= 0); + assert(file_flags <= _JOURNAL_FILE_FLAGS_MAX); assert(mmap_cache); assert(ret); @@ -3742,6 +3774,7 @@ int journal_file_open( .compress_threshold_bytes = compress_threshold_bytes == UINT64_MAX ? DEFAULT_COMPRESS_THRESHOLD : MAX(MIN_COMPRESS_THRESHOLD, compress_threshold_bytes), + .strict_order = FLAGS_SET(file_flags, JOURNAL_STRICT_ORDER), }; if (fname) { diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h index a35aa5daef..8c809ed4b9 100644 --- a/src/libsystemd/sd-journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -67,6 +67,7 @@ typedef struct JournalFile { int open_flags; bool close_fd:1; bool archive:1; + bool strict_order:1; direction_t last_direction; LocationType location_type; @@ -123,8 +124,10 @@ typedef struct JournalFile { } JournalFile; typedef enum JournalFileFlags { - JOURNAL_COMPRESS = 1 << 0, - JOURNAL_SEAL = 1 << 1, + JOURNAL_COMPRESS = 1 << 0, + JOURNAL_SEAL = 1 << 1, + JOURNAL_STRICT_ORDER = 1 << 2, + _JOURNAL_FILE_FLAGS_MAX = JOURNAL_COMPRESS|JOURNAL_SEAL|JOURNAL_STRICT_ORDER, } JournalFileFlags; typedef struct {