b4e205f
From 0983c262c2badca9f9bdcaa8aecc4560dd3589e3 Mon Sep 17 00:00:00 2001
b4e205f
From: Lennart Poettering <lennart@poettering.net>
b4e205f
Date: Fri, 24 Jul 2015 01:55:45 +0200
b4e205f
Subject: [PATCH] journal: avoid mapping empty data and field hash tables
b4e205f
b4e205f
When a new journal file is created we write the header first, then sync
b4e205f
and only then create the data and field hash tables in them. That means
b4e205f
to other processes it might appear that the files have a valid header
b4e205f
but not data and field hash tables. Our reader code should be able to
b4e205f
deal with this.
b4e205f
b4e205f
With this change we'll not map the two hash tables right-away after
b4e205f
opening a file for reading anymore (because that will of course fail if
b4e205f
the objects are missing), but delay this until the first time we access
b4e205f
them. On top of that, when we want to look something up in the hash
b4e205f
tables and we notice they aren't initialized yet, we consider them
b4e205f
empty.
b4e205f
b4e205f
This improves handling of some journal files reported in #487.
b4e205f
b4e205f
(cherry picked from commit dade37d403f1b8c1d7bb2efbe2361f2a3e999613)
b4e205f
---
b4e205f
 src/journal/journal-file.c   | 37 ++++++++++++++++++++++++++-----------
b4e205f
 src/journal/journal-file.h   |  3 +++
b4e205f
 src/journal/journal-verify.c | 14 ++++++++++++++
b4e205f
 3 files changed, 43 insertions(+), 11 deletions(-)
b4e205f
b4e205f
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
b4e205f
index f500568fec..6ccbb35a70 100644
b4e205f
--- a/src/journal/journal-file.c
b4e205f
+++ b/src/journal/journal-file.c
b4e205f
@@ -656,13 +656,16 @@ static int journal_file_setup_field_hash_table(JournalFile *f) {
b4e205f
         return 0;
b4e205f
 }
b4e205f
 
b4e205f
-static int journal_file_map_data_hash_table(JournalFile *f) {
b4e205f
+int journal_file_map_data_hash_table(JournalFile *f) {
b4e205f
         uint64_t s, p;
b4e205f
         void *t;
b4e205f
         int r;
b4e205f
 
b4e205f
         assert(f);
b4e205f
 
b4e205f
+        if (f->data_hash_table)
b4e205f
+                return 0;
b4e205f
+
b4e205f
         p = le64toh(f->header->data_hash_table_offset);
b4e205f
         s = le64toh(f->header->data_hash_table_size);
b4e205f
 
b4e205f
@@ -678,13 +681,16 @@ static int journal_file_map_data_hash_table(JournalFile *f) {
b4e205f
         return 0;
b4e205f
 }
b4e205f
 
b4e205f
-static int journal_file_map_field_hash_table(JournalFile *f) {
b4e205f
+int journal_file_map_field_hash_table(JournalFile *f) {
b4e205f
         uint64_t s, p;
b4e205f
         void *t;
b4e205f
         int r;
b4e205f
 
b4e205f
         assert(f);
b4e205f
 
b4e205f
+        if (f->field_hash_table)
b4e205f
+                return 0;
b4e205f
+
b4e205f
         p = le64toh(f->header->field_hash_table_offset);
b4e205f
         s = le64toh(f->header->field_hash_table_size);
b4e205f
 
b4e205f
@@ -803,10 +809,18 @@ int journal_file_find_field_object_with_hash(
b4e205f
         assert(f);
b4e205f
         assert(field && size > 0);
b4e205f
 
b4e205f
+        /* If the field hash table is empty, we can't find anything */
b4e205f
+        if (le64toh(f->header->field_hash_table_size) <= 0)
b4e205f
+                return 0;
b4e205f
+
b4e205f
+        /* Map the field hash table, if it isn't mapped yet. */
b4e205f
+        r = journal_file_map_field_hash_table(f);
b4e205f
+        if (r < 0)
b4e205f
+                return r;
b4e205f
+
b4e205f
         osize = offsetof(Object, field.payload) + size;
b4e205f
 
b4e205f
         m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
b4e205f
-
b4e205f
         if (m <= 0)
b4e205f
                 return -EBADMSG;
b4e205f
 
b4e205f
@@ -866,6 +880,15 @@ int journal_file_find_data_object_with_hash(
b4e205f
         assert(f);
b4e205f
         assert(data || size == 0);
b4e205f
 
b4e205f
+        /* If there's no data hash table, then there's no entry. */
b4e205f
+        if (le64toh(f->header->data_hash_table_size) <= 0)
b4e205f
+                return 0;
b4e205f
+
b4e205f
+        /* Map the data hash table, if it isn't mapped yet. */
b4e205f
+        r = journal_file_map_data_hash_table(f);
b4e205f
+        if (r < 0)
b4e205f
+                return r;
b4e205f
+
b4e205f
         osize = offsetof(Object, data.payload) + size;
b4e205f
 
b4e205f
         m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
b4e205f
@@ -2705,14 +2728,6 @@ int journal_file_open(
b4e205f
 #endif
b4e205f
         }
b4e205f
 
b4e205f
-        r = journal_file_map_field_hash_table(f);
b4e205f
-        if (r < 0)
b4e205f
-                goto fail;
b4e205f
-
b4e205f
-        r = journal_file_map_data_hash_table(f);
b4e205f
-        if (r < 0)
b4e205f
-                goto fail;
b4e205f
-
b4e205f
         if (mmap_cache_got_sigbus(f->mmap, f->fd)) {
b4e205f
                 r = -EIO;
b4e205f
                 goto fail;
b4e205f
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
b4e205f
index 403c8f760c..e92b75eabe 100644
b4e205f
--- a/src/journal/journal-file.h
b4e205f
+++ b/src/journal/journal-file.h
b4e205f
@@ -229,3 +229,6 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *
b4e205f
 int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
b4e205f
 
b4e205f
 bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
b4e205f
+
b4e205f
+int journal_file_map_data_hash_table(JournalFile *f);
b4e205f
+int journal_file_map_field_hash_table(JournalFile *f);
b4e205f
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
b4e205f
index 983217c1bc..d2d5c400c1 100644
b4e205f
--- a/src/journal/journal-verify.c
b4e205f
+++ b/src/journal/journal-verify.c
b4e205f
@@ -590,6 +590,13 @@ static int verify_hash_table(
b4e205f
         assert(last_usec);
b4e205f
 
b4e205f
         n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
b4e205f
+        if (n <= 0)
b4e205f
+                return 0;
b4e205f
+
b4e205f
+        r = journal_file_map_data_hash_table(f);
b4e205f
+        if (r < 0)
b4e205f
+                return log_error_errno(r, "Failed to map data hash table: %m");
b4e205f
+
b4e205f
         for (i = 0; i < n; i++) {
b4e205f
                 uint64_t last = 0, p;
b4e205f
 
b4e205f
@@ -647,6 +654,13 @@ static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p)
b4e205f
         assert(f);
b4e205f
 
b4e205f
         n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
b4e205f
+        if (n <= 0)
b4e205f
+                return 0;
b4e205f
+
b4e205f
+        r = journal_file_map_data_hash_table(f);
b4e205f
+        if (r < 0)
b4e205f
+                return log_error_errno(r, "Failed to map data hash table: %m");
b4e205f
+
b4e205f
         h = hash % n;
b4e205f
 
b4e205f
         q = le64toh(f->data_hash_table[h].head_hash_offset);