Merge pull request #22098 from DaanDeMeyer/journal-corrupt-2

journal: Fixes for handling of corrupt entry objects
This commit is contained in:
Yu Watanabe
2022-01-14 21:23:32 +09:00
committed by GitHub
4 changed files with 90 additions and 110 deletions
+4 -4
View File
@@ -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);
+82 -102
View File
@@ -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;
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -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;