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;
}
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;
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;
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 {
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 */
}
/* 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))
i = direction == DIRECTION_DOWN ? 0 : n - 1;
- 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;
- }
+ 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;
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;