diff --git a/src/journal/journald-file.c b/src/journal/journald-file.c index fc46aa1963..7f607d4aa6 100644 --- a/src/journal/journald-file.c +++ b/src/journal/journald-file.c @@ -4,6 +4,7 @@ #include #include "chattr-util.h" +#include "copy.h" #include "fd-util.h" #include "format-util.h" #include "journal-authenticate.h" @@ -11,6 +12,7 @@ #include "path-util.h" #include "random-util.h" #include "set.h" +#include "stat-util.h" #include "sync-util.h" static int journald_file_truncate(JournalFile *f) { @@ -120,6 +122,8 @@ static int journald_file_punch_holes(JournalFile *f) { * As a result we use atomic operations on f->offline_state for inter-thread communications with * journal_file_set_offline() and journal_file_set_online(). */ static void journald_file_set_offline_internal(JournaldFile *f) { + int r; + assert(f); assert(f->file->fd >= 0); assert(f->file->header); @@ -154,6 +158,28 @@ static void journald_file_set_offline_internal(JournaldFile *f) { f->file->header->state = f->file->archive ? STATE_ARCHIVED : STATE_OFFLINE; (void) fsync(f->file->fd); + + /* If we've archived the journal file, first try to re-enable COW on the file. If the + * FS_NOCOW_FL flag was never set or we succesfully removed it, continue. If we fail + * to remove the flag on the archived file, rewrite the file without the NOCOW flag. + * We need this fallback because on some filesystems (BTRFS), the NOCOW flag cannot + * be removed after data has been written to a file. The only way to remove it is to + * copy all data to a new file without the NOCOW flag set. */ + + if (f->file->archive) { + r = chattr_fd(f->file->fd, 0, FS_NOCOW_FL, NULL); + if (r >= 0) + continue; + + log_debug_errno(r, "Failed to re-enable copy-on-write for %s: %m, rewriting file", f->file->path); + + r = copy_file_atomic(f->file->path, f->file->path, f->file->mode, 0, FS_NOCOW_FL, COPY_REPLACE | COPY_FSYNC); + if (r < 0) { + log_debug_errno(r, "Failed to rewrite %s: %m", f->file->path); + continue; + } + } + break; case OFFLINE_OFFLINING: diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index bc80a51524..11b9da1cb5 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -220,18 +220,6 @@ JournalFile* journal_file_close(JournalFile *f) { if (f->mmap && f->cache_fd) mmap_cache_fd_free(f->cache_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, 0, FS_NOCOW_FL, NULL); - (void) btrfs_defrag_fd(f->fd); - } - if (f->close_fd) safe_close(f->fd); free(f->path); @@ -3566,16 +3554,11 @@ int journal_file_archive(JournalFile *f, char **ret_previous_path) { * occurs. */ f->archive = true; - /* Currently, btrfs is not very good with out write patterns and fragments heavily. Let's defrag our journal - * files when we archive them */ - f->defrag_on_close = true; - return 0; } int journal_file_dispose(int dir_fd, const char *fname) { _cleanup_free_ char *p = NULL; - _cleanup_close_ int fd = -1; assert(fname); @@ -3596,15 +3579,6 @@ int journal_file_dispose(int dir_fd, const char *fname) { if (renameat(dir_fd, fname, dir_fd, p) < 0) return -errno; - /* btrfs doesn't cope well with our write pattern and fragments heavily. Let's defrag all files we rotate */ - fd = openat(dir_fd, p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - log_debug_errno(errno, "Failed to open file for defragmentation/FS_NOCOW_FL, ignoring: %m"); - else { - (void) chattr_fd(fd, 0, FS_NOCOW_FL, NULL); - (void) btrfs_defrag_fd(fd); - } - return 0; } diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h index 5bcf591337..ecda2b3cc0 100644 --- a/src/libsystemd/sd-journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -68,7 +68,6 @@ typedef struct JournalFile { bool compress_lz4:1; bool compress_zstd:1; bool seal:1; - bool defrag_on_close:1; bool close_fd:1; bool archive:1; bool keyed_hash:1;