ryantimwilson / rpms / systemd

Forked from rpms/systemd a month ago
Clone
Jan Synacek f524b4
From 8ea1f4267bae6b37a4a4d474aec2692a4d211621 Mon Sep 17 00:00:00 2001
Jan Synacek f524b4
From: Fedora systemd team <systemd-maint@redhat.com>
Jan Synacek f524b4
Date: Wed, 7 Jan 2015 13:34:02 +0100
Jan Synacek f524b4
Subject: [PATCH] journald: when we detect the journal file we are about to
Jan Synacek f524b4
 write to has been deleted, rotate
Jan Synacek f524b4
Jan Synacek f524b4
https://bugzilla.redhat.com/show_bug.cgi?id=1171719
Jan Synacek f524b4
Jan Synacek f524b4
(cherry-picked from 2678031a179a9b91fc799f8ef951a548c66c4b49)
Jan Synacek f524b4
---
Jan Synacek f524b4
 src/journal/journal-file.c       | 65 ++++++++++++++++++++++++++++++----------
Jan Synacek f524b4
 src/journal/journal-file.h       |  1 +
Jan Synacek f524b4
 src/journal/journald-server.c    |  6 +++-
Jan Synacek f524b4
 src/journal/test-journal-flush.c |  3 +-
Jan Synacek f524b4
 4 files changed, 57 insertions(+), 18 deletions(-)
Jan Synacek f524b4
Jan Synacek f524b4
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
Jan Synacek f524b4
index c5d2d19..a99265b 100644
Jan Synacek f524b4
--- a/src/journal/journal-file.c
Jan Synacek f524b4
+++ b/src/journal/journal-file.c
Jan Synacek f524b4
@@ -68,6 +68,9 @@
Jan Synacek f524b4
 /* How much to increase the journal file size at once each time we allocate something new. */
Jan Synacek f524b4
 #define FILE_SIZE_INCREASE (8ULL*1024ULL*1024ULL)              /* 8MB */
Jan Synacek f524b4
 
Jan Synacek f524b4
+/* Reread fstat() of the file for detecting deletions at least this often */
Jan Synacek f524b4
+#define LAST_STAT_REFRESH_USEC (5*USEC_PER_SEC)
Jan Synacek f524b4
+
Jan Synacek f524b4
 static int journal_file_set_online(JournalFile *f) {
Jan Synacek f524b4
         assert(f);
Jan Synacek f524b4
 
Jan Synacek f524b4
@@ -312,6 +315,22 @@ static int journal_file_verify_header(JournalFile *f) {
Jan Synacek f524b4
         return 0;
Jan Synacek f524b4
 }
Jan Synacek f524b4
 
Jan Synacek f524b4
+static int journal_file_fstat(JournalFile *f) {
Jan Synacek f524b4
+        assert(f);
Jan Synacek f524b4
+        assert(f->fd >= 0);
Jan Synacek f524b4
+
Jan Synacek f524b4
+        if (fstat(f->fd, &f->last_stat) < 0)
Jan Synacek f524b4
+                return -errno;
Jan Synacek f524b4
+
Jan Synacek f524b4
+        f->last_stat_usec = now(CLOCK_MONOTONIC);
Jan Synacek f524b4
+
Jan Synacek f524b4
+        /* Refuse appending to files that are already deleted */
Jan Synacek f524b4
+        if (f->last_stat.st_nlink <= 0)
Jan Synacek f524b4
+                return -EIDRM;
Jan Synacek f524b4
+
Jan Synacek f524b4
+        return 0;
Jan Synacek f524b4
+}
Jan Synacek f524b4
+
Jan Synacek f524b4
 static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
Jan Synacek f524b4
         uint64_t old_size, new_size;
Jan Synacek f524b4
         int r;
Jan Synacek f524b4
@@ -330,8 +349,21 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
Jan Synacek f524b4
         if (new_size < le64toh(f->header->header_size))
Jan Synacek f524b4
                 new_size = le64toh(f->header->header_size);
Jan Synacek f524b4
 
Jan Synacek f524b4
-        if (new_size <= old_size)
Jan Synacek f524b4
-                return 0;
Jan Synacek f524b4
+        if (new_size <= old_size) {
Jan Synacek f524b4
+
Jan Synacek f524b4
+                /* We already pre-allocated enough space, but before
Jan Synacek f524b4
+                 * we write to it, let's check with fstat() if the
Jan Synacek f524b4
+                 * file got deleted, in order make sure we don't throw
Jan Synacek f524b4
+                 * away the data immediately. Don't check fstat() for
Jan Synacek f524b4
+                 * all writes though, but only once ever 10s. */
Jan Synacek f524b4
+
Jan Synacek f524b4
+                if (f->last_stat_usec + LAST_STAT_REFRESH_USEC > now(CLOCK_MONOTONIC))
Jan Synacek f524b4
+                        return 0;
Jan Synacek f524b4
+
Jan Synacek f524b4
+                return journal_file_fstat(f);
Jan Synacek f524b4
+        }
Jan Synacek f524b4
+
Jan Synacek f524b4
+        /* Allocate more space. */
Jan Synacek f524b4
 
Jan Synacek f524b4
         if (f->metrics.max_size > 0 && new_size > f->metrics.max_size)
Jan Synacek f524b4
                 return -E2BIG;
Jan Synacek f524b4
@@ -366,15 +398,14 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
Jan Synacek f524b4
         if (r != 0)
Jan Synacek f524b4
                 return -r;
Jan Synacek f524b4
 
Jan Synacek f524b4
-        if (fstat(f->fd, &f->last_stat) < 0)
Jan Synacek f524b4
-                return -errno;
Jan Synacek f524b4
-
Jan Synacek f524b4
         f->header->arena_size = htole64(new_size - le64toh(f->header->header_size));
Jan Synacek f524b4
 
Jan Synacek f524b4
-        return 0;
Jan Synacek f524b4
+        return journal_file_fstat(f);
Jan Synacek f524b4
 }
Jan Synacek f524b4
 
Jan Synacek f524b4
 static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
Jan Synacek f524b4
+        int r;
Jan Synacek f524b4
+
Jan Synacek f524b4
         assert(f);
Jan Synacek f524b4
         assert(ret);
Jan Synacek f524b4
 
Jan Synacek f524b4
@@ -386,8 +417,11 @@ static int journal_file_move_to(JournalFile *f, int context, bool keep_always, u
Jan Synacek f524b4
                 /* Hmm, out of range? Let's refresh the fstat() data
Jan Synacek f524b4
                  * first, before we trust that check. */
Jan Synacek f524b4
 
Jan Synacek f524b4
-                if (fstat(f->fd, &f->last_stat) < 0 ||
Jan Synacek f524b4
-                    offset + size > (uint64_t) f->last_stat.st_size)
Jan Synacek f524b4
+                r = journal_file_fstat(f);
Jan Synacek f524b4
+                if (r < 0)
Jan Synacek f524b4
+                        return r;
Jan Synacek f524b4
+
Jan Synacek f524b4
+                if (offset + size > (uint64_t) f->last_stat.st_size)
Jan Synacek f524b4
                         return -EADDRNOTAVAIL;
Jan Synacek f524b4
         }
Jan Synacek f524b4
 
Jan Synacek f524b4
@@ -2511,10 +2545,9 @@ int journal_file_open(
Jan Synacek f524b4
                 goto fail;
Jan Synacek f524b4
         }
Jan Synacek f524b4
 
Jan Synacek f524b4
-        if (fstat(f->fd, &f->last_stat) < 0) {
Jan Synacek f524b4
-                r = -errno;
Jan Synacek f524b4
+        r = journal_file_fstat(f);
Jan Synacek f524b4
+        if (r < 0)
Jan Synacek f524b4
                 goto fail;
Jan Synacek f524b4
-        }
Jan Synacek f524b4
 
Jan Synacek f524b4
         if (f->last_stat.st_size == 0 && f->writable) {
Jan Synacek f524b4
                 uint64_t crtime;
Jan Synacek f524b4
@@ -2546,10 +2579,9 @@ int journal_file_open(
Jan Synacek f524b4
                 if (r < 0)
Jan Synacek f524b4
                         goto fail;
Jan Synacek f524b4
 
Jan Synacek f524b4
-                if (fstat(f->fd, &f->last_stat) < 0) {
Jan Synacek f524b4
-                        r = -errno;
Jan Synacek f524b4
+                r = journal_file_fstat(f);
Jan Synacek f524b4
+                if (r < 0)
Jan Synacek f524b4
                         goto fail;
Jan Synacek f524b4
-                }
Jan Synacek f524b4
 
Jan Synacek f524b4
                 newly_created = true;
Jan Synacek f524b4
         }
Jan Synacek f524b4
@@ -2657,8 +2689,11 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
Jan Synacek f524b4
         if (r < 0)
Jan Synacek f524b4
                 return -ENOMEM;
Jan Synacek f524b4
 
Jan Synacek f524b4
+        /* Try to rename the file to the archived version. If the file
Jan Synacek f524b4
+         * already was deleted, we'll get ENOENT, let's ignore that
Jan Synacek f524b4
+         * case. */
Jan Synacek f524b4
         r = rename(old_file->path, p);
Jan Synacek f524b4
-        if (r < 0)
Jan Synacek f524b4
+        if (r < 0 && errno != ENOENT)
Jan Synacek f524b4
                 return -errno;
Jan Synacek f524b4
 
Jan Synacek f524b4
         old_file->header->state = STATE_ARCHIVED;
Jan Synacek f524b4
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
Jan Synacek f524b4
index 211e121..15f1301 100644
Jan Synacek f524b4
--- a/src/journal/journal-file.h
Jan Synacek f524b4
+++ b/src/journal/journal-file.h
Jan Synacek f524b4
@@ -66,6 +66,7 @@ typedef struct JournalFile {
Jan Synacek f524b4
 
Jan Synacek f524b4
         char *path;
Jan Synacek f524b4
         struct stat last_stat;
Jan Synacek f524b4
+        usec_t last_stat_usec;
Jan Synacek f524b4
 
Jan Synacek f524b4
         Header *header;
Jan Synacek f524b4
         HashItem *data_hash_table;
Jan Synacek f524b4
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
Jan Synacek f524b4
index 80c9736..24c4d3c 100644
Jan Synacek f524b4
--- a/src/journal/journald-server.c
Jan Synacek f524b4
+++ b/src/journal/journald-server.c
Jan Synacek f524b4
@@ -315,6 +315,7 @@ static int do_rotate(Server *s, JournalFile **f, const char* name,
Jan Synacek f524b4
                                         name);
Jan Synacek f524b4
         else
Jan Synacek f524b4
                 server_fix_perms(s, *f, uid);
Jan Synacek f524b4
+
Jan Synacek f524b4
         return r;
Jan Synacek f524b4
 }
Jan Synacek f524b4
 
Jan Synacek f524b4
@@ -457,7 +458,8 @@ bool shall_try_append_again(JournalFile *f, int r) {
Jan Synacek f524b4
            -EPROTONOSUPPORT  Unsupported feature
Jan Synacek f524b4
            -EBADMSG          Corrupted
Jan Synacek f524b4
            -ENODATA          Truncated
Jan Synacek f524b4
-           -ESHUTDOWN        Already archived */
Jan Synacek f524b4
+           -ESHUTDOWN        Already archived
Jan Synacek f524b4
+           -EIDRM            Journal file has been deleted */
Jan Synacek f524b4
 
Jan Synacek f524b4
         if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
Jan Synacek f524b4
                 log_debug("%s: Allocation limit reached, rotating.", f->path);
Jan Synacek f524b4
@@ -469,6 +471,8 @@ bool shall_try_append_again(JournalFile *f, int r) {
Jan Synacek f524b4
                 log_info("%s: Unsupported feature, rotating.", f->path);
Jan Synacek f524b4
         else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
Jan Synacek f524b4
                 log_warning("%s: Journal file corrupted, rotating.", f->path);
Jan Synacek f524b4
+        else if (r == -EIDRM)
Jan Synacek f524b4
+                log_warning("%s: Journal file has been deleted, rotating.", f->path);
Jan Synacek f524b4
         else
Jan Synacek f524b4
                 return false;
Jan Synacek f524b4
 
Jan Synacek f524b4
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
Jan Synacek f524b4
index 0ca24e0..40ede4a 100644
Jan Synacek f524b4
--- a/src/journal/test-journal-flush.c
Jan Synacek f524b4
+++ b/src/journal/test-journal-flush.c
Jan Synacek f524b4
@@ -39,8 +39,6 @@ int main(int argc, char *argv[]) {
Jan Synacek f524b4
         r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal);
Jan Synacek f524b4
         assert_se(r >= 0);
Jan Synacek f524b4
 
Jan Synacek f524b4
-        unlink(fn);
Jan Synacek f524b4
-
Jan Synacek f524b4
         r = sd_journal_open(&j, 0);
Jan Synacek f524b4
         assert_se(r >= 0);
Jan Synacek f524b4
 
Jan Synacek f524b4
@@ -68,6 +66,7 @@ int main(int argc, char *argv[]) {
Jan Synacek f524b4
 
Jan Synacek f524b4
         journal_file_close(new_journal);
Jan Synacek f524b4
 
Jan Synacek f524b4
+        unlink(fn);
Jan Synacek f524b4
         assert_se(rmdir(dn) == 0);
Jan Synacek f524b4
 
Jan Synacek f524b4
         return 0;
Jan Synacek f524b4
-- 
Jan Synacek f524b4
2.2.0
Jan Synacek f524b4