Merge pull request #22098 from DaanDeMeyer/journal-corrupt-2
journal: Fixes for handling of corrupt entry objects
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user