diff --git a/man/journald.conf.xml b/man/journald.conf.xml index b362c5de2c..e0796e1cce 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -250,20 +250,35 @@ SystemMaxUse= and RuntimeMaxUse= control how much disk space the - journal may use up at - maximum. Defaults to 10% of the size - of the respective file - system. SystemKeepFree= - and + journal may use up at maximum. + SystemKeepFree= and RuntimeKeepFree= control how much disk space - systemd-journald shall always leave - free for other uses. Defaults to 15% - of the size of the respective file - system. systemd-journald will respect - both limits, i.e. use the smaller of - the two values. - SystemMaxFileSize= + systemd-journald shall leave free for + other uses. + systemd-journald + will respect both limits and use the + smaller of the two values. + + The first pair defaults to 10% + and the second to 15% of the size of + the respective file system. If the + file system is nearly full and either + SystemKeepFree= or + RuntimeKeepFree= is + violated when systemd-journald is + started, the value will be raised to + percentage that is actually free. This + means that if before there was enough + free space and journal files were + created, and subsequently something + else causes the file system to fill + up, journald will stop using more + space, but it'll will not removing + existing files to go reduce footprint + either. + + SystemMaxFileSize= and RuntimeMaxFileSize= control how large individual journal diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 885b3b1df4..50dbe29cc1 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -37,6 +37,7 @@ typedef struct JournalMetrics { uint64_t max_use; + uint64_t use; uint64_t max_size; uint64_t min_size; uint64_t keep_free; diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c index b2b47d69b2..c92c198245 100644 --- a/src/journal/journal-vacuum.c +++ b/src/journal/journal-vacuum.c @@ -150,7 +150,6 @@ static int journal_file_empty(int dir_fd, const char *name) { int journal_directory_vacuum( const char *directory, uint64_t max_use, - uint64_t min_free, usec_t max_retention_usec, usec_t *oldest_usec) { @@ -164,7 +163,7 @@ int journal_directory_vacuum( assert(directory); - if (max_use <= 0 && min_free <= 0 && max_retention_usec <= 0) + if (max_use <= 0 && max_retention_usec <= 0) return 0; if (max_retention_usec > 0) { @@ -309,8 +308,7 @@ int journal_directory_vacuum( } if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) && - (max_use <= 0 || sum <= max_use) && - (min_free <= 0 || (uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free)) + (max_use <= 0 || sum <= max_use)) break; if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) { diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h index f5e3e5291f..bc30c3a140 100644 --- a/src/journal/journal-vacuum.h +++ b/src/journal/journal-vacuum.h @@ -23,4 +23,4 @@ #include -int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free, usec_t max_retention_usec, usec_t *oldest_usec); +int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index a3bacdab66..d3a1c574bd 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -158,9 +158,18 @@ static uint64_t available_space(Server *s, bool verbose) { } ss_avail = ss.f_bsize * ss.f_bavail; - avail = ss_avail > m->keep_free ? ss_avail - m->keep_free : 0; - s->cached_available_space = MIN(m->max_use, avail) > sum ? MIN(m->max_use, avail) - sum : 0; + /* If we reached a high mark, we will always allow this much + * again, unless usage goes above max_use. This watermark + * value is cached so that we don't give up space on pressure, + * but hover below the maximum usage. */ + + if (m->use < sum) + m->use = sum; + + avail = LESS_BY(ss_avail, m->keep_free); + + s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum); s->cached_available_space_timestamp = ts; if (verbose) { @@ -168,13 +177,14 @@ static uint64_t available_space(Server *s, bool verbose) { fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX]; server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE, - "%s journal is using %s (max %s, leaving %s of free %s, current limit %s).", + "%s journal is using %s (max allowed %s, " + "trying to leave %s free of %s available → current limit %s).", s->system_journal ? "Permanent" : "Runtime", format_bytes(fb1, sizeof(fb1), sum), format_bytes(fb2, sizeof(fb2), m->max_use), format_bytes(fb3, sizeof(fb3), m->keep_free), format_bytes(fb4, sizeof(fb4), ss_avail), - format_bytes(fb5, sizeof(fb5), MIN(m->max_use, avail))); + format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum)); } return s->cached_available_space; @@ -379,7 +389,7 @@ void server_vacuum(Server *s) { if (s->system_journal) { char *p = strappenda("/var/log/journal/", ids); - r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec); + r = journal_directory_vacuum(p, s->system_metrics.max_use, s->max_retention_usec, &s->oldest_file_usec); if (r < 0 && r != -ENOENT) log_error("Failed to vacuum %s: %s", p, strerror(-r)); } @@ -387,7 +397,7 @@ void server_vacuum(Server *s) { if (s->runtime_journal) { char *p = strappenda("/run/log/journal/", ids); - r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec); + r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->max_retention_usec, &s->oldest_file_usec); if (r < 0 && r != -ENOENT) log_error("Failed to vacuum %s: %s", p, strerror(-r)); } diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 5b74714782..5c9604472e 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -189,7 +189,7 @@ static void test_skip(void (*setup)(void)) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, 0, NULL); + journal_directory_vacuum(".", 3000000, 0, NULL); assert_se(rm_rf_dangerous(t, false, true, false) >= 0); } @@ -274,7 +274,7 @@ static void test_sequence_numbers(void) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, 0, NULL); + journal_directory_vacuum(".", 3000000, 0, NULL); assert_se(rm_rf_dangerous(t, false, true, false) >= 0); } diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 189fe07b48..85b4cf71ac 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -126,7 +126,7 @@ static void test_non_empty(void) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, 0, NULL); + journal_directory_vacuum(".", 3000000, 0, NULL); assert_se(rm_rf_dangerous(t, false, true, false) >= 0); } @@ -165,7 +165,7 @@ static void test_empty(void) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, 0, NULL); + journal_directory_vacuum(".", 3000000, 0, NULL); assert_se(rm_rf_dangerous(t, false, true, false) >= 0); } diff --git a/src/shared/macro.h b/src/shared/macro.h index 79bee0396c..dfbc20142f 100644 --- a/src/shared/macro.h +++ b/src/shared/macro.h @@ -117,6 +117,13 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { _a < _b ? _a : _b; \ }) +#define LESS_BY(A,B) \ + __extension__ ({ \ + typeof(A) _A = (A); \ + typeof(B) _B = (B); \ + _A > _B ? _A - _B : 0; \ + }) + #ifndef CLAMP #define CLAMP(x, low, high) \ __extension__ ({ \