Blame SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch

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