]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal-file-util: Prefer punching holes instead of truncating
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 4 Oct 2023 07:27:18 +0000 (09:27 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 5 Oct 2023 10:15:55 +0000 (19:15 +0900)
It seems truncating might cause SIGBUS (#24320). Let's play it safe
and always prefer punching holes over truncating.

src/shared/journal-file-util.c

index ff32a1aac83d630ab55c09890a457ef2eca4eb13..44bf292a69ec936ca7f409f663acef29122c4a75 100644 (file)
 #define PAYLOAD_BUFFER_SIZE (16U * 1024U)
 #define MINIMUM_HOLE_SIZE (1U * 1024U * 1024U / 2U)
 
-static int journal_file_truncate(JournalFile *f) {
-        uint64_t p;
+static int journal_file_end_punch_hole(JournalFile *f) {
+        uint64_t p, sz;
         int r;
 
-        /* truncate excess from the end of archives */
         r = journal_file_tail_end_by_pread(f, &p);
         if (r < 0)
                 return log_debug_errno(r, "Failed to determine end of tail object: %m");
 
-        /* arena_size can't exceed the file size, ensure it's updated before truncating */
-        f->header->arena_size = htole64(p - le64toh(f->header->header_size));
+        assert(p <= (uint64_t) f->last_stat.st_size);
+
+        sz = ((uint64_t) f->last_stat.st_size) - p;
+        if (sz < MINIMUM_HOLE_SIZE)
+                return 0;
+
+        if (fallocate(f->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, p, sz) < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), /* Make recognizable */
+                                               "Hole punching not supported by backing file system, skipping.");
 
-        if (ftruncate(f->fd, p) < 0)
-                return log_debug_errno(errno, "Failed to truncate %s: %m", f->path);
+                return log_debug_errno(errno, "Failed to punch hole at end of journal file %s: %m", f->path);
+        }
 
-        return journal_file_fstat(f);
+        return 0;
 }
 
 static int journal_file_entry_array_punch_hole(JournalFile *f, uint64_t p, uint64_t n_entries) {
@@ -73,25 +80,6 @@ static int journal_file_entry_array_punch_hole(JournalFile *f, uint64_t p, uint6
         if (sz < MINIMUM_HOLE_SIZE)
                 return 0;
 
-        if (p == le64toh(f->header->tail_object_offset) && !JOURNAL_HEADER_SEALED(f->header)) {
-                ssize_t n;
-
-                o.object.size = htole64(offset - p);
-
-                n = pwrite(f->fd, &o, sizeof(EntryArrayObject), p);
-                if (n < 0)
-                        return log_debug_errno(errno, "Failed to modify entry array object size: %m");
-                if ((size_t) n != sizeof(EntryArrayObject))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Short pwrite() while modifying entry array object size.");
-
-                f->header->arena_size = htole64(ALIGN64(offset) - le64toh(f->header->header_size));
-
-                if (ftruncate(f->fd, ALIGN64(offset)) < 0)
-                        return log_debug_errno(errno, "Failed to truncate %s: %m", f->path);
-
-                return 0;
-        }
-
         if (fallocate(f->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, sz) < 0) {
                 if (ERRNO_IS_NOT_SUPPORTED(errno))
                         return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), /* Make recognizable */
@@ -192,7 +180,7 @@ static void journal_file_set_offline_internal(JournalFile *f) {
 
                 case OFFLINE_SYNCING:
                         if (f->archive) {
-                                (void) journal_file_truncate(f);
+                                (void) journal_file_end_punch_hole(f);
                                 (void) journal_file_punch_holes(f);
                         }