[systemd-devel] [PATCH 1/4] Add BTRFS COW journal option

Goffredo Baroncelli kreijack at libero.it
Thu Mar 5 12:39:11 PST 2015


From: Goffredo Baroncelli <kreijack at inwind.it>

The commit 11689d2a force the NOCOW flag of the journal files. This was needed
because systemd-journald has very poor perfomance when the filesytem is
BTRFS due to its the COW behavior.

However removing the COW behavior, the journal file also lost  the
btrfs checksum protection, and this disables the BTRFS capability to rebuild a
corrupted file [1] in a RAID filesystem.

This patch adds the option "CowJournal" to the journald.conf to disable/enable
the NOCOW flag for the journal file.

[1] http://en.wikipedia.org/wiki/Data_scrubbing#Btrfs

Signed-off-by: Goffredo Baroncelli <kreijack at inwind.it>
---
 src/journal/journal-file.c       | 34 +++++++++++++++++++++-------------
 src/journal/journal-file.h       |  3 +++
 src/journal/journald-gperf.gperf |  1 +
 src/journal/journald-server.c    |  8 ++++----
 src/journal/journald-server.h    |  2 ++
 src/journal/journald.conf        |  1 +
 src/journal/sd-journal.c         |  2 +-
 7 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 2845e05..db0fa35 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2529,6 +2529,7 @@ int journal_file_open(
                 mode_t mode,
                 bool compress,
                 bool seal,
+                bool allow_cow_journal,
                 JournalMetrics *metrics,
                 MMapCache *mmap_cache,
                 JournalFile *template,
@@ -2558,6 +2559,7 @@ int journal_file_open(
         f->mode = mode;
 
         f->flags = flags;
+        f->allow_cow_journal = allow_cow_journal;
         f->prot = prot_from_flags(flags);
         f->writable = (flags & O_ACCMODE) != O_RDONLY;
 #if defined(HAVE_LZ4)
@@ -2603,16 +2605,19 @@ int journal_file_open(
 
         if (f->last_stat.st_size == 0 && f->writable) {
 
-                /* Before we write anything, turn off COW logic. Given
-                 * our write pattern that is quite unfriendly to COW
-                 * file systems this should greatly improve
-                 * performance on COW file systems, such as btrfs, at
-                 * the expense of data integrity features (which
-                 * shouldn't be too bad, given that we do our own
-                 * checksumming). */
-                r = chattr_fd(f->fd, true, FS_NOCOW_FL);
-                if (r < 0)
-                        log_warning_errno(errno, "Failed to set file attributes: %m");
+                if (!f->allow_cow_journal) {
+                        /* Before we write anything, turn off COW logic. Given
+                         * our write pattern that is quite unfriendly to COW
+                         * file systems this should greatly improve
+                         * performance on COW file systems, such as btrfs, at
+                         * the expense of data integrity features (which
+                         * shouldn't be too bad, given that we do our own
+                         * checksumming). */
+                        r = chattr_fd(f->fd, true, FS_NOCOW_FL);
+                        if (r < 0)
+                                log_warning_errno(errno,
+                                        "Failed to set file attributes: %m");
+                }
 
                 /* Let's attach the creation time to the journal file,
                  * so that the vacuuming code knows the age of this
@@ -2773,7 +2778,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
          * we archive them */
         old_file->defrag_on_close = true;
 
-        r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
+        r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, old_file->allow_cow_journal, NULL, old_file->mmap, old_file, &new_file);
         journal_file_close(old_file);
 
         *f = new_file;
@@ -2786,6 +2791,7 @@ int journal_file_open_reliably(
                 mode_t mode,
                 bool compress,
                 bool seal,
+                bool allow_cow_journal,
                 JournalMetrics *metrics,
                 MMapCache *mmap_cache,
                 JournalFile *template,
@@ -2796,7 +2802,8 @@ int journal_file_open_reliably(
         _cleanup_free_ char *p = NULL;
 
         r = journal_file_open(fname, flags, mode, compress, seal,
-                              metrics, mmap_cache, template, ret);
+                              allow_cow_journal, metrics, mmap_cache,
+                              template, ret);
         if (r != -EBADMSG && /* corrupted */
             r != -ENODATA && /* truncated */
             r != -EHOSTDOWN && /* other machine */
@@ -2838,7 +2845,8 @@ int journal_file_open_reliably(
         log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
 
         return journal_file_open(fname, flags, mode, compress, seal,
-                                 metrics, mmap_cache, template, ret);
+                                 allow_cow_journal, metrics, mmap_cache,
+                                 template, ret);
 }
 
 int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 2526e14..7591430 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -74,6 +74,7 @@ typedef struct JournalFile {
         bool compress_lz4:1;
         bool seal:1;
         bool defrag_on_close:1;
+        bool allow_cow_journal:1;
 
         bool tail_entry_monotonic_valid:1;
 
@@ -130,6 +131,7 @@ int journal_file_open(
                 mode_t mode,
                 bool compress,
                 bool seal,
+                bool allow_cow_journal,
                 JournalMetrics *metrics,
                 MMapCache *mmap_cache,
                 JournalFile *template,
@@ -144,6 +146,7 @@ int journal_file_open_reliably(
                 mode_t mode,
                 bool compress,
                 bool seal,
+                bool allow_cow_journal,
                 JournalMetrics *metrics,
                 MMapCache *mmap_cache,
                 JournalFile *template,
diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf
index 74554c1..bffb169 100644
--- a/src/journal/journald-gperf.gperf
+++ b/src/journal/journald-gperf.gperf
@@ -40,3 +40,4 @@ Journal.MaxLevelKMsg,       config_parse_log_level,  0, offsetof(Server, max_lev
 Journal.MaxLevelConsole,    config_parse_log_level,  0, offsetof(Server, max_level_console)
 Journal.MaxLevelWall,       config_parse_log_level,  0, offsetof(Server, max_level_wall)
 Journal.SplitMode,          config_parse_split_mode, 0, offsetof(Server, split_mode)
+Journal.CowJournal,         config_parse_bool,       0, offsetof(Server, allow_cow_journal)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 7ee8174..894d07d 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -277,7 +277,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
                 journal_file_close(f);
         }
 
-        r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
+        r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, s->allow_cow_journal, &s->system_metrics, s->mmap, NULL, &f);
         if (r < 0)
                 return s->system_journal;
 
@@ -948,7 +948,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
                 (void) mkdir(fn, 0755);
 
                 fn = strjoina(fn, "/system.journal");
-                r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
+                r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, s->allow_cow_journal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
 
                 if (r >= 0)
                         server_fix_perms(s, s->system_journal, 0);
@@ -973,7 +973,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
                          * if it already exists, so that we can flush
                          * it into the system journal */
 
-                        r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
+                        r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, s->allow_cow_journal, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
                         free(fn);
 
                         if (r < 0) {
@@ -992,7 +992,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
                         (void) mkdir("/run/log/journal", 0755);
                         (void) mkdir_parents(fn, 0750);
 
-                        r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
+                        r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, s->allow_cow_journal, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
                         free(fn);
 
                         if (r < 0)
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index c96877c..4be0b48 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -143,6 +143,8 @@ typedef struct Server {
 
         /* Cached cgroup root, so that we don't have to query that all the time */
         char *cgroup_root;
+
+        bool allow_cow_journal;
 } Server;
 
 #define N_IOVEC_META_FIELDS 20
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 29bdf8f..73de66f 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -36,3 +36,4 @@
 #MaxLevelKMsg=notice
 #MaxLevelConsole=info
 #MaxLevelWall=emerg
+#CowJournal=no
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 94891cd..20c2e5f 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -1202,7 +1202,7 @@ static int add_any_file(sd_journal *j, const char *path) {
                 return set_put_error(j, -ETOOMANYREFS);
         }
 
-        r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
+        r = journal_file_open(path, O_RDONLY, 0, false, false, false, NULL, j->mmap, NULL, &f);
         if (r < 0)
                 return r;
 
-- 
2.1.0



More information about the systemd-devel mailing list