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