summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-12-20 02:38:36 +0100
committerLennart Poettering <lennart@poettering.net>2011-12-20 02:38:36 +0100
commitbc85bfee87e11317fbcd1160c9003860dc6edde9 (patch)
treefe6aa27940fc07ca9d74927d0b6474f053698d45 /src
parent466ccd92e2f9ad712332012e1b3643a34b006a45 (diff)
journal: fix space reservation limit enforcement
Diffstat (limited to 'src')
-rw-r--r--src/journal/journal-def.h3
-rw-r--r--src/journal/journal-file.c51
-rw-r--r--src/journal/journal-file.h13
-rw-r--r--src/journal/journald.c79
-rw-r--r--src/journal/sd-journal.h1
5 files changed, 118 insertions, 29 deletions
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 1a63ca1f8d..5f026ee0f6 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -135,9 +135,6 @@ _packed_ struct Header {
sd_id128_t seqnum_id;
uint64_t arena_offset;
uint64_t arena_size;
- uint64_t arena_max_size; /* obsolete */
- uint64_t arena_min_size; /* obsolete */
- uint64_t arena_keep_free; /* obsolete */
uint64_t data_hash_table_offset; /* for looking up data objects */
uint64_t data_hash_table_size;
uint64_t field_hash_table_offset; /* for looking up field objects */
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 8a864cb913..8f9b61bc2f 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -31,12 +31,6 @@
#include "journal-file.h"
#include "lookup3.h"
-#define DEFAULT_ARENA_MAX_SIZE (16ULL*1024ULL*1024ULL*1024ULL)
-#define DEFAULT_ARENA_MIN_SIZE (256ULL*1024ULL)
-#define DEFAULT_ARENA_KEEP_FREE (1ULL*1024ULL*1024ULL)
-
-#define DEFAULT_MAX_USE (16ULL*1024ULL*1024ULL*16ULL)
-
#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*16ULL)
#define DEFAULT_FIELD_HASH_TABLE_SIZE (2047ULL*16ULL)
@@ -76,9 +70,6 @@ static int journal_file_init_header(JournalFile *f, JournalFile *template) {
zero(h);
memcpy(h.signature, signature, 8);
h.arena_offset = htole64(ALIGN64(sizeof(h)));
- h.arena_max_size = htole64(DEFAULT_ARENA_MAX_SIZE);
- h.arena_min_size = htole64(DEFAULT_ARENA_MIN_SIZE);
- h.arena_keep_free = htole64(DEFAULT_ARENA_KEEP_FREE);
r = sd_id128_randomize(&h.file_id);
if (r < 0)
@@ -161,16 +152,10 @@ static int journal_file_verify_header(JournalFile *f) {
}
static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
- uint64_t asize;
uint64_t old_size, new_size;
assert(f);
- if (offset < le64toh(f->header->arena_offset))
- return -EINVAL;
-
- new_size = PAGE_ALIGN(offset + size);
-
/* We assume that this file is not sparse, and we know that
* for sure, since we always call posix_fallocate()
* ourselves */
@@ -179,12 +164,19 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
le64toh(f->header->arena_offset) +
le64toh(f->header->arena_size);
- if (old_size >= new_size)
+ new_size = PAGE_ALIGN(offset + size);
+ if (new_size < le64toh(f->header->arena_offset))
+ new_size = le64toh(f->header->arena_offset);
+
+ if (new_size <= old_size)
return 0;
- asize = new_size - le64toh(f->header->arena_offset);
+ if (f->metrics.max_size > 0 &&
+ new_size > f->metrics.max_size)
+ return -E2BIG;
- if (asize > le64toh(f->header->arena_min_size)) {
+ if (new_size > f->metrics.min_size &&
+ f->metrics.keep_free > 0) {
struct statvfs svfs;
if (fstatvfs(f->fd, &svfs) >= 0) {
@@ -192,8 +184,8 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
available = svfs.f_bfree * svfs.f_bsize;
- if (available >= f->header->arena_keep_free)
- available -= f->header->arena_keep_free;
+ if (available >= f->metrics.keep_free)
+ available -= f->metrics.keep_free;
else
available = 0;
@@ -202,16 +194,16 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
}
}
- if (asize > le64toh(f->header->arena_max_size))
- return -E2BIG;
-
+ /* Note that the glibc fallocate() fallback is very
+ inefficient, hence we try to minimize the allocation area
+ as we can. */
if (posix_fallocate(f->fd, old_size, new_size - old_size) < 0)
return -errno;
if (fstat(f->fd, &f->last_stat) < 0)
return -errno;
- f->header->arena_size = htole64(asize);
+ f->header->arena_size = new_size - htole64(f->header->arena_offset);
return 0;
}
@@ -576,6 +568,9 @@ int journal_file_find_data_object_with_hash(
osize = offsetof(Object, data.payload) + size;
+ if (f->header->data_hash_table_size == 0)
+ return -EBADMSG;
+
h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem));
p = le64toh(f->data_hash_table[h].head_hash_offset);
@@ -816,7 +811,7 @@ static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) {
if (r < 0)
return r;
- log_error("%s %lu", f->path, (unsigned long) f->header->n_entries);
+ log_error("=> %s seqnr=%lu n_entries=%lu", f->path, (unsigned long) o->entry.seqnum, (unsigned long) f->header->n_entries);
if (f->header->head_entry_realtime == 0)
f->header->head_entry_realtime = o->entry.realtime;
@@ -887,6 +882,8 @@ static void journal_file_post_change(JournalFile *f) {
* trigger IN_MODIFY by truncating the journal file to its
* current size which triggers IN_MODIFY. */
+ __sync_synchronize();
+
if (ftruncate(f->fd, f->last_stat.st_size) < 0)
log_error("Failed to to truncate file to its own size: %m");
}
@@ -1626,6 +1623,10 @@ int journal_file_open(
f->writable = (flags & O_ACCMODE) != O_RDONLY;
f->prot = prot_from_flags(flags);
+ f->metrics.max_size = DEFAULT_MAX_SIZE;
+ f->metrics.min_size = DEFAULT_MIN_SIZE;
+ f->metrics.keep_free = DEFAULT_KEEP_FREE;
+
f->path = strdup(fname);
if (!f->path) {
r = -ENOMEM;
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 664f917bb0..20712b5dcc 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -28,6 +28,11 @@
#include "util.h"
#include "sd-id128.h"
+#define DEFAULT_MAX_SIZE (1024ULL*128ULL)
+#define DEFAULT_MIN_SIZE (256ULL*1024ULL)
+#define DEFAULT_KEEP_FREE (1ULL*1024ULL*1024ULL)
+#define DEFAULT_MAX_USE (16ULL*1024ULL*1024ULL*16ULL)
+
typedef struct Window {
void *ptr;
uint64_t offset;
@@ -45,6 +50,12 @@ enum {
_WINDOW_MAX
};
+typedef struct JournalMetrics {
+ uint64_t max_size;
+ uint64_t min_size;
+ uint64_t keep_free;
+} JournalMetrics;
+
typedef struct JournalFile {
int fd;
char *path;
@@ -62,6 +73,8 @@ typedef struct JournalFile {
Window windows[_WINDOW_MAX];
uint64_t current_offset;
+
+ JournalMetrics metrics;
} JournalFile;
typedef enum direction {
diff --git a/src/journal/journald.c b/src/journal/journald.c
index c457d2786b..37f8f16754 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -54,6 +54,9 @@ typedef struct Server {
char *buffer;
size_t buffer_size;
+
+ JournalMetrics metrics;
+ uint64_t max_use;
} Server;
static void fix_perms(JournalFile *f, uid_t uid) {
@@ -153,6 +156,66 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
return f;
}
+static void server_vacuum(Server *s) {
+ Iterator i;
+ void *k;
+ char *p;
+ char ids[33];
+ sd_id128_t machine;
+ int r;
+ JournalFile *f;
+
+ log_info("Rotating...");
+
+ if (s->runtime_journal) {
+ r = journal_file_rotate(&s->runtime_journal);
+ if (r < 0)
+ log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r));
+ }
+
+ if (s->system_journal) {
+ r = journal_file_rotate(&s->system_journal);
+ if (r < 0)
+ log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r));
+ }
+
+ HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
+ r = journal_file_rotate(&f);
+ if (r < 0)
+ log_error("Failed to rotate %s: %s", f->path, strerror(-r));
+ else
+ hashmap_replace(s->user_journals, k, f);
+ }
+
+ log_info("Vacuuming...");
+
+ r = sd_id128_get_machine(&machine);
+ if (r < 0) {
+ log_error("Failed to get machine ID: %s", strerror(-r));
+ return;
+ }
+
+ if (asprintf(&p, "/var/log/journal/%s", sd_id128_to_string(machine, ids)) < 0) {
+ log_error("Out of memory.");
+ return;
+ }
+
+ r = journal_directory_vacuum(p, s->max_use, s->metrics.keep_free);
+ if (r < 0 && r != -ENOENT)
+ log_error("Failed to vacuum %s: %s", p, strerror(-r));
+ free(p);
+
+ if (asprintf(&p, "/run/log/journal/%s", ids) < 0) {
+ log_error("Out of memory.");
+ return;
+ }
+
+ r = journal_directory_vacuum(p, s->max_use, s->metrics.keep_free);
+ if (r < 0 && r != -ENOENT)
+ log_error("Failed to vacuum %s: %s", p, strerror(-r));
+ free(p);
+}
+
static void dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv) {
char *pid = NULL, *uid = NULL, *gid = NULL,
*source_time = NULL, *boot_id = NULL, *machine_id = NULL,
@@ -166,6 +229,7 @@ static void dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigne
char *t;
uid_t loginuid = 0, realuid = 0;
JournalFile *f;
+ bool vacuumed = false;
assert(s);
assert(iovec || n == 0);
@@ -262,12 +326,23 @@ static void dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigne
assert(n <= m);
+retry:
f = find_journal(s, realuid == 0 ? 0 : loginuid);
if (!f)
log_warning("Dropping message, as we can't find a place to store the data.");
else {
r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
+ if (r == -E2BIG && !vacuumed) {
+ log_info("Allocation limit reached.");
+
+ server_vacuum(s);
+ vacuumed = true;
+
+ log_info("Retrying write.");
+ goto retry;
+ }
+
if (r < 0)
log_error("Failed to write entry, ignoring: %s", strerror(-r));
}
@@ -715,6 +790,10 @@ static int server_init(Server *s) {
zero(*s);
s->syslog_fd = s->native_fd = s->signal_fd = -1;
+ s->metrics.max_size = DEFAULT_MAX_SIZE;
+ s->metrics.min_size = DEFAULT_MIN_SIZE;
+ s->metrics.keep_free = DEFAULT_KEEP_FREE;
+ s->max_use = DEFAULT_MAX_USE;
s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (s->epoll_fd < 0) {
diff --git a/src/journal/sd-journal.h b/src/journal/sd-journal.h
index 33e4b78855..ee9813f28c 100644
--- a/src/journal/sd-journal.h
+++ b/src/journal/sd-journal.h
@@ -38,7 +38,6 @@
* - accelerate looking for "all hostnames" and suchlike.
* - throttling
* - cryptographic hash
- * - fix space reservation logic
* - compression
*/