diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 11647504e9..3afe66db89 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -76,17 +76,17 @@ static void test_non_empty(void) { assert_se(le64toh(o->entry.seqnum) == 1); assert_se(journal_file_find_data_object(f->file, test, strlen(test), NULL, &p) == 1); - assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1); + assert_se(journal_file_next_entry_for_data(f->file, p, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 1); - assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1); + assert_se(journal_file_next_entry_for_data(f->file, p, DIRECTION_UP, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 3); assert_se(journal_file_find_data_object(f->file, test2, strlen(test2), NULL, &p) == 1); - assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1); + assert_se(journal_file_next_entry_for_data(f->file, p, DIRECTION_UP, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 2); - assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1); + assert_se(journal_file_next_entry_for_data(f->file, p, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 2); assert_se(journal_file_find_data_object(f->file, "quux", 4, NULL, &p) == 0); diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 505e4f728d..ef4c261096 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -2099,14 +2099,35 @@ static void chain_cache_put( ci->last_index = last_index; } +static int bump_array_index(uint64_t *i, direction_t direction, uint64_t n) { + assert(i); + + /* Increase or decrease the specified index, in the right direction. */ + + if (direction == DIRECTION_DOWN) { + if (*i >= n - 1) + return 0; + + (*i)++; + } else { + if (*i <= 0) + return 0; + + (*i)--; + } + + return 1; +} + static int generic_array_get( JournalFile *f, uint64_t first, uint64_t i, + direction_t direction, Object **ret, uint64_t *ret_offset) { - Object *o; - uint64_t p = 0, a, t = 0; + Object *o, *e; + uint64_t p = 0, a, t = 0, k; int r; ChainCacheItem *ci; @@ -2123,35 +2144,64 @@ static int generic_array_get( } while (a > 0) { - uint64_t k; - r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); if (r < 0) return r; k = journal_file_entry_array_n_items(o); - if (i < k) { - p = le64toh(o->entry_array.items[i]); - goto found; - } + if (i < k) + break; i -= k; t += k; a = le64toh(o->entry_array.next_entry_array_offset); } + /* If we've found the right location, now look for the first non-corrupt entry object (in the right + * direction). */ + + while (a > 0) { + /* In the first iteration of the while loop, we reuse i, k and o from the previous while + * loop. */ + if (i == UINT64_MAX) { + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + + k = journal_file_entry_array_n_items(o); + if (k == 0) + break; + + i = direction == DIRECTION_DOWN ? 0 : k - 1; + } + + do { + p = le64toh(o->entry_array.items[i]); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &e); + if (r >= 0) + goto found; + if (!IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) + return r; + + /* OK, so this entry is borked. Most likely some entry didn't get synced to + * disk properly, let's see if the next one might work for us instead. */ + log_debug_errno(r, "Entry item %" PRIu64 " is bad, skipping over it.", i); + } while (bump_array_index(&i, direction, k) > 0); + + t += k; + a = le64toh(o->entry_array.next_entry_array_offset); + i = UINT64_MAX; + } + return 0; found: /* Let's cache this item for the next invocation */ chain_cache_put(f->chain_cache, ci, first, a, le64toh(o->entry_array.items[0]), t, i); - r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); - if (r < 0) - return r; - if (ret) - *ret = o; + *ret = e; if (ret_offset) *ret_offset = p; @@ -2164,16 +2214,18 @@ static int generic_array_get_plus_one( uint64_t extra, uint64_t first, uint64_t i, + direction_t direction, Object **ret, uint64_t *ret_offset) { Object *o; + int r; assert(f); if (i == 0) { - int r; - r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o); + if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) + return generic_array_get(f, first, 0, direction, ret, ret_offset); if (r < 0) return r; @@ -2186,7 +2238,7 @@ static int generic_array_get_plus_one( return 1; } - return generic_array_get(f, first, i-1, ret, ret_offset); + return generic_array_get(f, first, i - 1, direction, ret, ret_offset); } enum { @@ -2710,25 +2762,6 @@ int journal_file_compare_locations(JournalFile *af, JournalFile *bf) { return CMP(af->current_xor_hash, bf->current_xor_hash); } -static int bump_array_index(uint64_t *i, direction_t direction, uint64_t n) { - - /* Increase or decrease the specified index, in the right direction. */ - - if (direction == DIRECTION_DOWN) { - if (*i >= n - 1) - return 0; - - (*i) ++; - } else { - if (*i <= 0) - return 0; - - (*i) --; - } - - return 1; -} - static bool check_properly_ordered(uint64_t new_offset, uint64_t old_offset, direction_t direction) { /* Consider it an error if any of the two offsets is uninitialized */ @@ -2777,24 +2810,9 @@ int journal_file_next_entry( } /* And jump to it */ - for (;;) { - r = generic_array_get(f, - le64toh(f->header->entry_array_offset), - i, - ret, &ofs); - if (r > 0) - break; - if (r != -EBADMSG) - return r; - - /* OK, so this entry is borked. Most likely some entry didn't get synced to disk properly, let's see if - * the next one might work for us instead. */ - log_debug_errno(r, "Entry item %" PRIu64 " is bad, skipping over it.", i); - - r = bump_array_index(&i, direction, n); - if (r <= 0) - return r; - } + r = generic_array_get(f, le64toh(f->header->entry_array_offset), i, direction, ret, &ofs); + if (r <= 0) + return r; /* Ensure our array is properly ordered. */ if (p > 0 && !check_properly_ordered(ofs, p, direction)) @@ -2810,7 +2828,6 @@ int journal_file_next_entry( int journal_file_next_entry_for_data( JournalFile *f, - Object *o, uint64_t p, uint64_t data_offset, direction_t direction, Object **ret, uint64_t *ret_offset) { @@ -2820,7 +2837,6 @@ int journal_file_next_entry_for_data( int r; assert(f); - assert(p > 0 || !o); r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d); if (r < 0) @@ -2830,53 +2846,16 @@ int journal_file_next_entry_for_data( if (n <= 0) return n; - if (!o) - i = direction == DIRECTION_DOWN ? 0 : n - 1; - else { - if (o->object.type != OBJECT_ENTRY) - return -EINVAL; + i = direction == DIRECTION_DOWN ? 0 : n - 1; - r = generic_array_bisect_plus_one(f, - le64toh(d->data.entry_offset), - le64toh(d->data.entry_array_offset), - le64toh(d->data.n_entries), - p, - test_object_offset, - DIRECTION_DOWN, - NULL, NULL, - &i); - - if (r <= 0) - return r; - - r = bump_array_index(&i, direction, n); - if (r <= 0) - return r; - } - - for (;;) { - r = generic_array_get_plus_one(f, - le64toh(d->data.entry_offset), - le64toh(d->data.entry_array_offset), - i, - ret, &ofs); - if (r > 0) - break; - if (r != -EBADMSG) - return r; - - log_debug_errno(r, "Data entry item %" PRIu64 " is bad, skipping over it.", i); - - r = bump_array_index(&i, direction, n); - if (r <= 0) - return r; - } - - /* Ensure our array is properly ordered. */ - if (p > 0 && check_properly_ordered(ofs, p, direction)) - return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), - "%s data entry array not properly ordered at entry %" PRIu64, - f->path, i); + r = generic_array_get_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + i, + direction, + ret, &ofs); + if (r <= 0) + return r; if (ret_offset) *ret_offset = ofs; @@ -3819,7 +3798,8 @@ int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, u r = generic_array_get_plus_one(f, le64toh(o->data.entry_offset), le64toh(o->data.entry_array_offset), - le64toh(o->data.n_entries)-1, + le64toh(o->data.n_entries) - 1, + DIRECTION_UP, &o, NULL); if (r <= 0) return r; diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h index b90e3a608a..39e91d71c4 100644 --- a/src/libsystemd/sd-journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -214,7 +214,7 @@ void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset); int journal_file_compare_locations(JournalFile *af, JournalFile *bf); int journal_file_next_entry(JournalFile *f, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); -int journal_file_next_entry_for_data(JournalFile *f, Object *o, uint64_t p, uint64_t data_offset, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_next_entry_for_data(JournalFile *f, uint64_t data_offset, direction_t direction, Object **ret, uint64_t *offset); int journal_file_move_to_entry_by_seqnum(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); int journal_file_move_to_entry_by_realtime(JournalFile *f, uint64_t realtime, direction_t direction, Object **ret, uint64_t *offset); diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index 4a46b7f4fb..7a6cc4aca3 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -611,9 +611,9 @@ static int find_location_for_match( /* FIXME: missing: find by monotonic */ if (j->current_location.type == LOCATION_HEAD) - return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset); + return journal_file_next_entry_for_data(f, dp, DIRECTION_DOWN, ret, offset); if (j->current_location.type == LOCATION_TAIL) - return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset); + return journal_file_next_entry_for_data(f, dp, DIRECTION_UP, ret, offset); if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset); if (j->current_location.monotonic_set) { @@ -624,7 +624,7 @@ static int find_location_for_match( if (j->current_location.realtime_set) return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset); - return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset); + return journal_file_next_entry_for_data(f, dp, direction, ret, offset); } else if (m->type == MATCH_OR_TERM) { uint64_t np = 0;