journal: when iterating through entry arrays and we hit an invalid one keep going
authorLennart Poettering <lennart@poettering.net>
Wed, 12 Oct 2016 10:36:01 +0000 (12:36 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 12 Oct 2016 18:25:20 +0000 (20:25 +0200)
When iterating through partially synced journal files we need to be prepared
for hitting with invalid entries (specifically: non-initialized). Instead of
generated an error and giving up, let's simply try to preceed with the next one
that is valid (and debug log about this).

This reworks the logic introduced with caeab8f626e709569cc492b75eb7e119076059e7
to iteration in both directions, and tries to look for valid entries located
after the invalid one. It also extends the behaviour to both iterating through
the global entry array and per-data object entry arrays.

Fixes: #4088

src/journal/journal-file.c

index 3f1afda..e26c822 100644 (file)
@@ -2555,18 +2555,24 @@ int journal_file_next_entry(
         }
 
         /* And jump to it */
-        r = generic_array_get(f,
-                              le64toh(f->header->entry_array_offset),
-                              i,
-                              ret, &ofs);
-        if (r == -EBADMSG && direction == DIRECTION_DOWN) {
-                /* Special case: when we iterate throught the journal file linearly, and hit an entry we can't read,
-                 * consider this the end of the journal file. */
-                log_debug_errno(r, "Encountered entry we can't read while iterating through journal file. Considering this the end of the file.");
-                return 0;
+        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;
         }
-        if (r <= 0)
-                return r;
 
         /* Ensure our array is properly ordered. */
         if (p > 0 && !check_properly_ordered(ofs, p, direction)) {
@@ -2588,8 +2594,8 @@ int journal_file_next_entry_for_data(
                 Object **ret, uint64_t *offset) {
 
         uint64_t i, n, ofs;
-        int r;
         Object *d;
+        int r;
 
         assert(f);
         assert(p > 0 || !o);
@@ -2626,13 +2632,23 @@ int journal_file_next_entry_for_data(
                         return r;
         }
 
-        r = generic_array_get_plus_one(f,
-                                       le64toh(d->data.entry_offset),
-                                       le64toh(d->data.entry_array_offset),
-                                       i,
-                                       ret, &ofs);
-        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)) {