]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-journal: split out generic_array_bisect_one() from generic_array_bisect() 27553/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 6 May 2023 15:19:24 +0000 (00:19 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 6 May 2023 15:28:19 +0000 (00:28 +0900)
This also makes journal corruption always handled gracefully, and drop
potentially unsatisfied assertion on corrupted journal.

Fixes #27533.

src/libsystemd/sd-journal/journal-file.c

index f594b3eecb36faf3dd8245285389cec4a66b5635..78dc93516162342f183f041537ec8c9aecb09aa4 100644 (file)
@@ -2775,6 +2775,59 @@ enum {
         TEST_RIGHT
 };
 
+static int generic_array_bisect_one(
+                JournalFile *f,
+                uint64_t a, /* offset of entry array object. */
+                uint64_t i, /* index of the entry item we will test. */
+                uint64_t needle,
+                int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
+                direction_t direction,
+                uint64_t *left,
+                uint64_t *right,
+                uint64_t *ret_offset) {
+
+        Object *array;
+        uint64_t p;
+        int r;
+
+        assert(f);
+        assert(test_object);
+        assert(left);
+        assert(right);
+        assert(*left <= i);
+        assert(i <= *right);
+
+        r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array);
+        if (r < 0)
+                return r;
+
+        p = journal_file_entry_array_item(f, array, i);
+        if (p <= 0)
+                r = -EBADMSG;
+        else
+                r = test_object(f, p, needle);
+        if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
+                log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short.");
+                *right = i;
+                return -ENOANO; /* recognizable error */
+        }
+        if (r < 0)
+                return r;
+
+        if (r == TEST_FOUND)
+                r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
+
+        if (r == TEST_RIGHT)
+                *right = i;
+        else
+                *left = i + 1;
+
+        if (ret_offset)
+                *ret_offset = p;
+
+        return r;
+}
+
 static int generic_array_bisect(
                 JournalFile *f,
                 uint64_t first,
@@ -2833,7 +2886,7 @@ static int generic_array_bisect(
         }
 
         while (a > 0) {
-                uint64_t left, right, k, lp;
+                uint64_t left = 0, right, k, lp;
 
                 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array);
                 if (r < 0)
@@ -2844,76 +2897,30 @@ static int generic_array_bisect(
                 if (right <= 0)
                         return 0;
 
-                i = right - 1;
-                lp = p = journal_file_entry_array_item(f, array, i);
-                if (p <= 0)
-                        r = -EBADMSG;
-                else
-                        r = test_object(f, p, needle);
-                if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
-                        log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (1)");
-                        n = i;
+                right--;
+                r = generic_array_bisect_one(f, a, right, needle, test_object, direction, &left, &right, &lp);
+                if (r == -ENOANO) {
+                        n = right;
                         continue;
                 }
                 if (r < 0)
                         return r;
 
-                if (r == TEST_FOUND)
-                        r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
-
                 if (r == TEST_RIGHT) {
-                        left = 0;
-                        right -= 1;
-
-                        if (last_index != UINT64_MAX) {
-                                assert(last_index <= right);
-
-                                /* If we cached the last index we
-                                 * looked at, let's try to not to jump
-                                 * too wildly around and see if we can
-                                 * limit the range to look at early to
-                                 * the immediate neighbors of the last
-                                 * index we looked at. */
-
-                                if (last_index > 0) {
-                                        uint64_t x = last_index - 1;
-
-                                        p = journal_file_entry_array_item(f, array, x);
-                                        if (p <= 0)
-                                                return -EBADMSG;
-
-                                        r = test_object(f, p, needle);
-                                        if (r < 0)
-                                                return r;
-
-                                        if (r == TEST_FOUND)
-                                                r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
+                        /* If we cached the last index we looked at, let's try to not to jump too wildly
+                         * around and see if we can limit the range to look at early to the immediate
+                         * neighbors of the last index we looked at. */
 
-                                        if (r == TEST_RIGHT)
-                                                right = x;
-                                        else
-                                                left = x + 1;
-                                }
-
-                                if (last_index < right) {
-                                        uint64_t y = last_index + 1;
-
-                                        p = journal_file_entry_array_item(f, array, y);
-                                        if (p <= 0)
-                                                return -EBADMSG;
-
-                                        r = test_object(f, p, needle);
-                                        if (r < 0)
-                                                return r;
-
-                                        if (r == TEST_FOUND)
-                                                r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
+                        if (last_index > 0 && last_index - 1 < right) {
+                                r = generic_array_bisect_one(f, a, last_index - 1, needle, test_object, direction, &left, &right, NULL);
+                                if (r < 0 && r != -ENOANO)
+                                        return r;
+                        }
 
-                                        if (r == TEST_RIGHT)
-                                                right = y;
-                                        else
-                                                left = y + 1;
-                                }
+                        if (last_index < right) {
+                                r = generic_array_bisect_one(f, a, last_index + 1, needle, test_object, direction, &left, &right, NULL);
+                                if (r < 0 && r != -ENOANO)
+                                        return r;
                         }
 
                         for (;;) {
@@ -2928,26 +2935,9 @@ static int generic_array_bisect(
                                 assert(left < right);
                                 i = (left + right) / 2;
 
-                                p = journal_file_entry_array_item(f, array, i);
-                                if (p <= 0)
-                                        r = -EBADMSG;
-                                else
-                                        r = test_object(f, p, needle);
-                                if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
-                                        log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (2)");
-                                        right = n = i;
-                                        continue;
-                                }
-                                if (r < 0)
+                                r = generic_array_bisect_one(f, a, i, needle, test_object, direction, &left, &right, NULL);
+                                if (r < 0 && r != -ENOANO)
                                         return r;
-
-                                if (r == TEST_FOUND)
-                                        r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
-
-                                if (r == TEST_RIGHT)
-                                        right = i;
-                                else
-                                        left = i + 1;
                         }
                 }