1ab4435
From 909a0337de322578679728231807683e666295c2 Mon Sep 17 00:00:00 2001
1ab4435
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
1ab4435
Date: Mon, 24 Jun 2013 21:00:28 -0400
1ab4435
Subject: [PATCH] journald: always vacuum empty offline files
1ab4435
1ab4435
Corrupted empty files are relatively common. I think they are created
1ab4435
when a coredump for a user who never logged anything before is
1ab4435
attempted to be written, but the write does not succeed because the
1ab4435
coredump is too big, but there are probably other ways to create
1ab4435
those, especially if the machine crashes at the right time.
1ab4435
Non-corrupted empty files can also happen, e.g. if a journal file is
1ab4435
opened, but nothing is ever successfully written to it and it is
1ab4435
rotated because of MaxFileSec=. Either way, each "empty" journal file
1ab4435
costs around 3 MB, and there's little point in keeping them around.
1ab4435
---
1ab4435
 src/journal/journal-vacuum.c | 29 +++++++++++++++++++++++++++++
1ab4435
 1 file changed, 29 insertions(+)
1ab4435
1ab4435
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
674ca7d
index 1ddb043e2c..79572f1fb6 100644
1ab4435
--- a/src/journal/journal-vacuum.c
1ab4435
+++ b/src/journal/journal-vacuum.c
1ab4435
@@ -128,6 +128,24 @@ static void patch_realtime(
1ab4435
 #endif
1ab4435
 }
1ab4435
 
1ab4435
+static int journal_file_empty(int dir_fd, const char *name) {
1ab4435
+        int fd, r;
1ab4435
+        le64_t n_entries;
1ab4435
+
1ab4435
+        fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
1ab4435
+        if (fd < 0)
1ab4435
+                return -errno;
1ab4435
+
1ab4435
+        if (lseek(fd, offsetof(Header, n_entries), SEEK_SET) < 0)
1ab4435
+                return -errno;
1ab4435
+
1ab4435
+        r = read(fd, &n_entries, sizeof(n_entries));
1ab4435
+        if (r != sizeof(n_entries))
1ab4435
+                return r == 0 ? -EINVAL : -errno;
1ab4435
+
1ab4435
+        return le64toh(n_entries) == 0;
1ab4435
+}
1ab4435
+
1ab4435
 int journal_directory_vacuum(
1ab4435
                 const char *directory,
1ab4435
                 uint64_t max_use,
1ab4435
@@ -247,6 +265,17 @@ int journal_directory_vacuum(
1ab4435
                         /* We do not vacuum active files or unknown files! */
1ab4435
                         continue;
1ab4435
 
1ab4435
+                if (journal_file_empty(dirfd(d), de->d_name)) {
1ab4435
+
1ab4435
+                        /* Always vacuum empty non-online files. */
1ab4435
+
1ab4435
+                        if (unlinkat(dirfd(d), de->d_name, 0) >= 0)
1ab4435
+                                log_debug("Deleted empty journal %s/%s.", directory, de->d_name);
1ab4435
+                        else if (errno != ENOENT)
1ab4435
+                                log_warning("Failed to delete %s/%s: %m", directory, de->d_name);
1ab4435
+                        continue;
1ab4435
+                }
1ab4435
+
1ab4435
                 patch_realtime(directory, de->d_name, &st, &realtime);
1ab4435
 
1ab4435
                 GREEDY_REALLOC(list, n_allocated, n_list + 1);