chiark / gitweb /
journald: turn off COW for journal files on btrfs
authorLennart Poettering <lennart@poettering.net>
Thu, 8 Jan 2015 00:22:29 +0000 (01:22 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 8 Jan 2015 00:22:29 +0000 (01:22 +0100)
btrfs' COW logic results in heavily fragment journal files, which is
detrimental for perfomance. Hence, turn off COW for journal files as we
create them.

Turning off COW comes at the cost of data integrity guarantees, but this
should be acceptable, given that we do our own checksumming, and
generally have a pretty conservative write pattern.

Also see discussion on linux-btrfs:

http://www.spinics.net/lists/linux-btrfs/msg41001.html

src/journal/journal-file.c
src/journal/journalctl.c
src/shared/util.c
src/shared/util.h

index c9030c56addb5e7dac5f6d19c23b9b70d9fae234..c20af5d9bfc2f90041776fe2782f1a954fb5af00 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/statvfs.h>
 #include <fcntl.h>
 #include <stddef.h>
 #include <sys/statvfs.h>
 #include <fcntl.h>
 #include <stddef.h>
+#include <linux/fs.h>
 
 #include "btrfs-util.h"
 #include "journal-def.h"
 
 #include "btrfs-util.h"
 #include "journal-def.h"
@@ -141,8 +142,17 @@ void journal_file_close(JournalFile *f) {
         if (f->mmap && f->fd >= 0)
                 mmap_cache_close_fd(f->mmap, f->fd);
 
         if (f->mmap && f->fd >= 0)
                 mmap_cache_close_fd(f->mmap, f->fd);
 
-        if (f->fd >= 0 && f->defrag_on_close)
-                btrfs_defrag_fd(f->fd);
+        if (f->fd >= 0 && f->defrag_on_close) {
+
+                /* Be friendly to btrfs: turn COW back on again now,
+                 * and defragment the file. We won't write to the file
+                 * ever again, hence remove all fragmentation, and
+                 * reenable all the good bits COW usually provides
+                 * (such as data checksumming). */
+
+                (void) chattr_fd(f->fd, false, FS_NOCOW_FL);
+                (void) btrfs_defrag_fd(f->fd);
+        }
 
         safe_close(f->fd);
         free(f->path);
 
         safe_close(f->fd);
         free(f->path);
@@ -2591,6 +2601,18 @@ int journal_file_open(
                 goto fail;
 
         if (f->last_stat.st_size == 0 && f->writable) {
                 goto fail;
 
         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");
+
                 /* Let's attach the creation time to the journal file,
                  * so that the vacuuming code knows the age of this
                  * file even if the file might end up corrupted one
                 /* Let's attach the creation time to the journal file,
                  * so that the vacuuming code knows the age of this
                  * file even if the file might end up corrupted one
@@ -2808,6 +2830,8 @@ int journal_file_open_reliably(
 
         /* btrfs doesn't cope well with our write pattern and
          * fragments heavily. Let's defrag all files we rotate */
 
         /* btrfs doesn't cope well with our write pattern and
          * fragments heavily. Let's defrag all files we rotate */
+
+        (void) chattr_path(p, false, FS_NOCOW_FL);
         (void) btrfs_defrag(p);
 
         log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
         (void) btrfs_defrag(p);
 
         log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
index 386e3505c044ed385f4049e54e126ff16321b86b..62931f14c9bb71d7a886ff6bd66acbdde775b90a 100644 (file)
@@ -1294,7 +1294,7 @@ static int setup_keys(void) {
         size_t mpk_size, seed_size, state_size, i;
         uint8_t *mpk, *seed, *state;
         ssize_t l;
         size_t mpk_size, seed_size, state_size, i;
         uint8_t *mpk, *seed, *state;
         ssize_t l;
-        int fd = -1, r, attr = 0;
+        int fd = -1, r;
         sd_id128_t machine, boot;
         char *p = NULL, *k = NULL;
         struct FSSHeader h;
         sd_id128_t machine, boot;
         char *p = NULL, *k = NULL;
         struct FSSHeader h;
@@ -1389,13 +1389,9 @@ static int setup_keys(void) {
 
         /* Enable secure remove, exclusion from dump, synchronous
          * writing and in-place updating */
 
         /* Enable secure remove, exclusion from dump, synchronous
          * writing and in-place updating */
-        if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
-                log_warning_errno(errno, "FS_IOC_GETFLAGS failed: %m");
-
-        attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
-
-        if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
-                log_warning_errno(errno, "FS_IOC_SETFLAGS failed: %m");
+        r = chattr_fd(fd, true, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
+        if (r < 0)
+                log_warning_errno(errno, "Failed to set file attributes: %m");
 
         zero(h);
         memcpy(h.signature, "KSHHRHLP", 8);
 
         zero(h);
         memcpy(h.signature, "KSHHRHLP", 8);
index 6293e967c8fb4c7c929a14a3578be04efcfe39c6..88fd78ec8d61f5b0de698d085e9e68c2ec83b346 100644 (file)
@@ -62,6 +62,7 @@
 #include <sys/xattr.h>
 #include <libgen.h>
 #include <sys/statvfs.h>
 #include <sys/xattr.h>
 #include <libgen.h>
 #include <sys/statvfs.h>
+#include <linux/fs.h>
 #undef basename
 
 #ifdef HAVE_SYS_AUXV_H
 #undef basename
 
 #ifdef HAVE_SYS_AUXV_H
@@ -7740,3 +7741,35 @@ int same_fd(int a, int b) {
 
         return fa == fb;
 }
 
         return fa == fb;
 }
+
+int chattr_fd(int fd, bool b, int mask) {
+        int old_attr, new_attr;
+
+        assert(fd >= 0);
+
+        if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
+                return -errno;
+
+        if (b)
+                new_attr = old_attr | mask;
+        else
+                new_attr = old_attr & ~mask;
+
+        if (new_attr == old_attr)
+                return 0;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int chattr_path(const char *p, bool b, int mask) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return chattr_fd(fd, b, mask);
+}
index 4b7e12e62838164c93897eb8c28d6842c0b490a1..31103e957f4aa104c613919c48997ef3db05fd48 100644 (file)
@@ -1071,3 +1071,6 @@ int path_getcrtime(const char *p, usec_t *usec);
 int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
 
 int same_fd(int a, int b);
 int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
 
 int same_fd(int a, int b);
+
+int chattr_fd(int fd, bool b, int mask);
+int chattr_path(const char *p, bool b, int mask);