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