Zbigniew Jędrzejewski-Szmek 126222
From 96dc1b72f3fb5d344538984121e11e5804905145 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 126222
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Zbigniew Jędrzejewski-Szmek 126222
Date: Wed, 13 Nov 2013 00:42:22 -0500
Zbigniew Jędrzejewski-Szmek 126222
Subject: [PATCH] journald: do not free space when disk space runs low
Zbigniew Jędrzejewski-Szmek 126222
Zbigniew Jędrzejewski-Szmek 126222
Before, journald would remove journal files until both MaxUse= and
Zbigniew Jędrzejewski-Szmek 126222
KeepFree= settings would be satisfied. The first one depends (if set
Zbigniew Jędrzejewski-Szmek 126222
automatically) on the size of the file system and is constant.  But
Zbigniew Jędrzejewski-Szmek 126222
the second one depends on current use of the file system, and a spike
Zbigniew Jędrzejewski-Szmek 126222
in disk usage would cause journald to delete journal files, trying to
Zbigniew Jędrzejewski-Szmek 126222
reach usage which would leave 15% of the disk free. This behaviour is
Zbigniew Jędrzejewski-Szmek 126222
surprising for the user who doesn't expect his logs to be purged when
Zbigniew Jędrzejewski-Szmek 126222
disk usage goes above 85%, which on a large disk could be some
Zbigniew Jędrzejewski-Szmek 126222
gigabytes from being full. In addition attempting to keep 15% free
Zbigniew Jędrzejewski-Szmek 126222
provides an attack vector where filling the disk sufficiently disposes
Zbigniew Jędrzejewski-Szmek 126222
of almost all logs.
Zbigniew Jędrzejewski-Szmek 126222
Zbigniew Jędrzejewski-Szmek 126222
Instead, obey KeepFree= only as a limit on adding additional files.
Zbigniew Jędrzejewski-Szmek 126222
When replacing old files with new, ignore KeepFree=. This means that
Zbigniew Jędrzejewski-Szmek 126222
if journal disk usage reached some high point that at some later point
Zbigniew Jędrzejewski-Szmek 126222
start to violate the KeepFree= constraint, journald will not add files
Zbigniew Jędrzejewski-Szmek 126222
to go above this point, but it will stay (slightly) below it. When
Zbigniew Jędrzejewski-Szmek 126222
journald is restarted, it forgets the previous maximum usage value,
Zbigniew Jędrzejewski-Szmek 126222
and sets the limit based on the current usage, so if disk remains to
Zbigniew Jędrzejewski-Szmek 126222
be filled, journald might use one journal-file-size less on each
Zbigniew Jędrzejewski-Szmek 126222
restart, if restarts happen just after rotation. This seems like a
Zbigniew Jędrzejewski-Szmek 126222
reasonable compromise between implementation complexity and robustness.
Zbigniew Jędrzejewski-Szmek 126222
---
Zbigniew Jędrzejewski-Szmek 126222
 man/journald.conf.xml                   | 39 +++++++++++++++++++++++----------
Zbigniew Jędrzejewski-Szmek 126222
 src/journal/journal-file.h              |  1 +
Zbigniew Jędrzejewski-Szmek 126222
 src/journal/journal-vacuum.c            |  6 ++---
Zbigniew Jędrzejewski-Szmek 126222
 src/journal/journal-vacuum.h            |  2 +-
Zbigniew Jędrzejewski-Szmek 126222
 src/journal/journald-server.c           | 22 ++++++++++++++-----
Zbigniew Jędrzejewski-Szmek 126222
 src/journal/test-journal-interleaving.c |  4 ++--
Zbigniew Jędrzejewski-Szmek 126222
 src/journal/test-journal.c              |  4 ++--
Zbigniew Jędrzejewski-Szmek 126222
 src/shared/macro.h                      |  7 ++++++
Zbigniew Jędrzejewski-Szmek 126222
 8 files changed, 58 insertions(+), 27 deletions(-)
Zbigniew Jędrzejewski-Szmek 126222
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/man/journald.conf.xml b/man/journald.conf.xml
Zbigniew Jędrzejewski-Szmek 126222
index b362c5d..e0796e1 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/man/journald.conf.xml
Zbigniew Jędrzejewski-Szmek 126222
+++ b/man/journald.conf.xml
Zbigniew Jędrzejewski-Szmek 126222
@@ -250,20 +250,35 @@
Zbigniew Jędrzejewski-Szmek 126222
                                 <para><varname>SystemMaxUse=</varname>
Zbigniew Jędrzejewski-Szmek 126222
                                 and <varname>RuntimeMaxUse=</varname>
Zbigniew Jędrzejewski-Szmek 126222
                                 control how much disk space the
Zbigniew Jędrzejewski-Szmek 126222
-                                journal may use up at
Zbigniew Jędrzejewski-Szmek 126222
-                                maximum. Defaults to 10% of the size
Zbigniew Jędrzejewski-Szmek 126222
-                                of the respective file
Zbigniew Jędrzejewski-Szmek 126222
-                                system. <varname>SystemKeepFree=</varname>
Zbigniew Jędrzejewski-Szmek 126222
-                                and
Zbigniew Jędrzejewski-Szmek 126222
+                                journal may use up at maximum.
Zbigniew Jędrzejewski-Szmek 126222
+                                <varname>SystemKeepFree=</varname> and
Zbigniew Jędrzejewski-Szmek 126222
                                 <varname>RuntimeKeepFree=</varname>
Zbigniew Jędrzejewski-Szmek 126222
                                 control how much disk space
Zbigniew Jędrzejewski-Szmek 126222
-                                systemd-journald shall always leave
Zbigniew Jędrzejewski-Szmek 126222
-                                free for other uses. Defaults to 15%
Zbigniew Jędrzejewski-Szmek 126222
-                                of the size of the respective file
Zbigniew Jędrzejewski-Szmek 126222
-                                system. systemd-journald will respect
Zbigniew Jędrzejewski-Szmek 126222
-                                both limits, i.e. use the smaller of
Zbigniew Jędrzejewski-Szmek 126222
-                                the two values.
Zbigniew Jędrzejewski-Szmek 126222
-                                <varname>SystemMaxFileSize=</varname>
Zbigniew Jędrzejewski-Szmek 126222
+                                systemd-journald shall leave free for
Zbigniew Jędrzejewski-Szmek 126222
+                                other uses.
Zbigniew Jędrzejewski-Szmek 126222
+                                <command>systemd-journald</command>
Zbigniew Jędrzejewski-Szmek 126222
+                                will respect both limits and use the
Zbigniew Jędrzejewski-Szmek 126222
+                                smaller of the two values.</para>
Zbigniew Jędrzejewski-Szmek 126222
+
Zbigniew Jędrzejewski-Szmek 126222
+                                <para>The first pair defaults to 10%
Zbigniew Jędrzejewski-Szmek 126222
+                                and the second to 15% of the size of
Zbigniew Jędrzejewski-Szmek 126222
+                                the respective file system. If the
Zbigniew Jędrzejewski-Szmek 126222
+                                file system is nearly full and either
Zbigniew Jędrzejewski-Szmek 126222
+                                <varname>SystemKeepFree=</varname> or
Zbigniew Jędrzejewski-Szmek 126222
+                                <varname>RuntimeKeepFree=</varname> is
Zbigniew Jędrzejewski-Szmek 126222
+                                violated when systemd-journald is
Zbigniew Jędrzejewski-Szmek 126222
+                                started, the value will be raised to
Zbigniew Jędrzejewski-Szmek 126222
+                                percentage that is actually free. This
Zbigniew Jędrzejewski-Szmek 126222
+                                means that if before there was enough
Zbigniew Jędrzejewski-Szmek 126222
+                                free space and journal files were
Zbigniew Jędrzejewski-Szmek 126222
+                                created, and subsequently something
Zbigniew Jędrzejewski-Szmek 126222
+                                else causes the file system to fill
Zbigniew Jędrzejewski-Szmek 126222
+                                up, journald will stop using more
Zbigniew Jędrzejewski-Szmek 126222
+                                space, but it'll will not removing
Zbigniew Jędrzejewski-Szmek 126222
+                                existing files to go reduce footprint
Zbigniew Jędrzejewski-Szmek 126222
+                                either.</para>
Zbigniew Jędrzejewski-Szmek 126222
+
Zbigniew Jędrzejewski-Szmek 126222
+                                <para><varname>SystemMaxFileSize=</varname>
Zbigniew Jędrzejewski-Szmek 126222
                                 and
Zbigniew Jędrzejewski-Szmek 126222
                                 <varname>RuntimeMaxFileSize=</varname>
Zbigniew Jędrzejewski-Szmek 126222
                                 control how large individual journal
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
Zbigniew Jędrzejewski-Szmek 126222
index 0bd23f7..2e06b57 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/journal/journal-file.h
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/journal/journal-file.h
Zbigniew Jędrzejewski-Szmek 126222
@@ -37,6 +37,7 @@
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
 typedef struct JournalMetrics {
Zbigniew Jędrzejewski-Szmek 126222
         uint64_t max_use;
Zbigniew Jędrzejewski-Szmek 126222
+        uint64_t use;
Zbigniew Jędrzejewski-Szmek 126222
         uint64_t max_size;
Zbigniew Jędrzejewski-Szmek 126222
         uint64_t min_size;
Zbigniew Jędrzejewski-Szmek 126222
         uint64_t keep_free;
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
Zbigniew Jędrzejewski-Szmek 126222
index d4a1c6c..8b07f65 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/journal/journal-vacuum.c
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/journal/journal-vacuum.c
Zbigniew Jędrzejewski-Szmek 126222
@@ -150,7 +150,6 @@ static int journal_file_empty(int dir_fd, const char *name) {
Zbigniew Jędrzejewski-Szmek 126222
 int journal_directory_vacuum(
Zbigniew Jędrzejewski-Szmek 126222
                 const char *directory,
Zbigniew Jędrzejewski-Szmek 126222
                 uint64_t max_use,
Zbigniew Jędrzejewski-Szmek 126222
-                uint64_t min_free,
Zbigniew Jędrzejewski-Szmek 126222
                 usec_t max_retention_usec,
Zbigniew Jędrzejewski-Szmek 126222
                 usec_t *oldest_usec) {
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
@@ -164,7 +163,7 @@ int journal_directory_vacuum(
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
         assert(directory);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
-        if (max_use <= 0 && min_free <= 0 && max_retention_usec <= 0)
Zbigniew Jędrzejewski-Szmek 126222
+        if (max_use <= 0 && max_retention_usec <= 0)
Zbigniew Jędrzejewski-Szmek 126222
                 return 0;
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
         if (max_retention_usec > 0) {
Zbigniew Jędrzejewski-Szmek 126222
@@ -310,8 +309,7 @@ int journal_directory_vacuum(
Zbigniew Jędrzejewski-Szmek 126222
                 }
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
Zbigniew Jędrzejewski-Szmek 126222
-                    (max_use <= 0 || sum <= max_use) &&
Zbigniew Jędrzejewski-Szmek 126222
-                    (min_free <= 0 || (uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free))
Zbigniew Jędrzejewski-Szmek 126222
+                    (max_use <= 0 || sum <= max_use))
Zbigniew Jędrzejewski-Szmek 126222
                         break;
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h
Zbigniew Jędrzejewski-Szmek 126222
index f5e3e52..bc30c3a 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/journal/journal-vacuum.h
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/journal/journal-vacuum.h
Zbigniew Jędrzejewski-Szmek 126222
@@ -23,4 +23,4 @@
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
 #include <inttypes.h>
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
-int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free, usec_t max_retention_usec, usec_t *oldest_usec);
Zbigniew Jędrzejewski-Szmek 126222
+int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec);
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
Zbigniew Jędrzejewski-Szmek 126222
index 1fcb3d5..cd2cfe9 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/journal/journald-server.c
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/journal/journald-server.c
Zbigniew Jędrzejewski-Szmek 126222
@@ -158,9 +158,18 @@ static uint64_t available_space(Server *s, bool verbose) {
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
         ss_avail = ss.f_bsize * ss.f_bavail;
Zbigniew Jędrzejewski-Szmek 126222
-        avail = ss_avail > m->keep_free ? ss_avail - m->keep_free : 0;
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
-        s->cached_available_space = MIN(m->max_use, avail) > sum ? MIN(m->max_use, avail) - sum : 0;
Zbigniew Jędrzejewski-Szmek 126222
+        /* If we reached a high mark, we will always allow this much
Zbigniew Jędrzejewski-Szmek 126222
+         * again, unless usage goes above max_use. This watermark
Zbigniew Jędrzejewski-Szmek 126222
+         * value is cached so that we don't give up space on pressure,
Zbigniew Jędrzejewski-Szmek 126222
+         * but hover below the maximum usage. */
Zbigniew Jędrzejewski-Szmek 126222
+
Zbigniew Jędrzejewski-Szmek 126222
+        if (m->use < sum)
Zbigniew Jędrzejewski-Szmek 126222
+                m->use = sum;
Zbigniew Jędrzejewski-Szmek 126222
+
Zbigniew Jędrzejewski-Szmek 126222
+        avail = LESS_BY(ss_avail, m->keep_free);
Zbigniew Jędrzejewski-Szmek 126222
+
Zbigniew Jędrzejewski-Szmek 126222
+        s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
Zbigniew Jędrzejewski-Szmek 126222
         s->cached_available_space_timestamp = ts;
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
         if (verbose) {
Zbigniew Jędrzejewski-Szmek 126222
@@ -168,13 +177,14 @@ static uint64_t available_space(Server *s, bool verbose) {
Zbigniew Jędrzejewski-Szmek 126222
                         fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX];
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
Zbigniew Jędrzejewski-Szmek 126222
-                                      "%s journal is using %s (max %s, leaving %s of free %s, current limit %s).",
Zbigniew Jędrzejewski-Szmek 126222
+                                      "%s journal is using %s (max allowed %s, "
Zbigniew Jędrzejewski-Szmek 126222
+                                      "trying to leave %s free of %s available → current limit %s).",
Zbigniew Jędrzejewski-Szmek 126222
                                       s->system_journal ? "Permanent" : "Runtime",
Zbigniew Jędrzejewski-Szmek 126222
                                       format_bytes(fb1, sizeof(fb1), sum),
Zbigniew Jędrzejewski-Szmek 126222
                                       format_bytes(fb2, sizeof(fb2), m->max_use),
Zbigniew Jędrzejewski-Szmek 126222
                                       format_bytes(fb3, sizeof(fb3), m->keep_free),
Zbigniew Jędrzejewski-Szmek 126222
                                       format_bytes(fb4, sizeof(fb4), ss_avail),
Zbigniew Jędrzejewski-Szmek 126222
-                                      format_bytes(fb5, sizeof(fb5), MIN(m->max_use, avail)));
Zbigniew Jędrzejewski-Szmek 126222
+                                      format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
         return s->cached_available_space;
Zbigniew Jędrzejewski-Szmek 126222
@@ -378,7 +388,7 @@ void server_vacuum(Server *s) {
Zbigniew Jędrzejewski-Szmek 126222
         if (s->system_journal) {
Zbigniew Jędrzejewski-Szmek 126222
                 char *p = strappenda("/var/log/journal/", ids);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
-                r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
Zbigniew Jędrzejewski-Szmek 126222
+                r = journal_directory_vacuum(p, s->system_metrics.max_use, s->max_retention_usec, &s->oldest_file_usec);
Zbigniew Jędrzejewski-Szmek 126222
                 if (r < 0 && r != -ENOENT)
Zbigniew Jędrzejewski-Szmek 126222
                         log_error("Failed to vacuum %s: %s", p, strerror(-r));
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
@@ -386,7 +396,7 @@ void server_vacuum(Server *s) {
Zbigniew Jędrzejewski-Szmek 126222
         if (s->runtime_journal) {
Zbigniew Jędrzejewski-Szmek 126222
                 char *p = strappenda("/run/log/journal/", ids);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
-                r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
Zbigniew Jędrzejewski-Szmek 126222
+                r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->max_retention_usec, &s->oldest_file_usec);
Zbigniew Jędrzejewski-Szmek 126222
                 if (r < 0 && r != -ENOENT)
Zbigniew Jędrzejewski-Szmek 126222
                         log_error("Failed to vacuum %s: %s", p, strerror(-r));
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
Zbigniew Jędrzejewski-Szmek 126222
index 1a058ea..974fa3b 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/journal/test-journal-interleaving.c
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/journal/test-journal-interleaving.c
Zbigniew Jędrzejewski-Szmek 126222
@@ -194,7 +194,7 @@ static void test_skip(void (*setup)(void))
Zbigniew Jędrzejewski-Szmek 126222
         if (arg_keep)
Zbigniew Jędrzejewski-Szmek 126222
                 log_info("Not removing %s", t);
Zbigniew Jędrzejewski-Szmek 126222
         else {
Zbigniew Jędrzejewski-Szmek 126222
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
+                journal_directory_vacuum(".", 3000000, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
@@ -279,7 +279,7 @@ static void test_sequence_numbers(void) {
Zbigniew Jędrzejewski-Szmek 126222
         if (arg_keep)
Zbigniew Jędrzejewski-Szmek 126222
                 log_info("Not removing %s", t);
Zbigniew Jędrzejewski-Szmek 126222
         else {
Zbigniew Jędrzejewski-Szmek 126222
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
+                journal_directory_vacuum(".", 3000000, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
Zbigniew Jędrzejewski-Szmek 126222
index 190c426..3b8778d 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/journal/test-journal.c
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/journal/test-journal.c
Zbigniew Jędrzejewski-Szmek 126222
@@ -126,7 +126,7 @@ static void test_non_empty(void) {
Zbigniew Jędrzejewski-Szmek 126222
         if (arg_keep)
Zbigniew Jędrzejewski-Szmek 126222
                 log_info("Not removing %s", t);
Zbigniew Jędrzejewski-Szmek 126222
         else {
Zbigniew Jędrzejewski-Szmek 126222
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
+                journal_directory_vacuum(".", 3000000, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
@@ -165,7 +165,7 @@ static void test_empty(void) {
Zbigniew Jędrzejewski-Szmek 126222
         if (arg_keep)
Zbigniew Jędrzejewski-Szmek 126222
                 log_info("Not removing %s", t);
Zbigniew Jędrzejewski-Szmek 126222
         else {
Zbigniew Jędrzejewski-Szmek 126222
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
+                journal_directory_vacuum(".", 3000000, 0, NULL);
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
                 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
Zbigniew Jędrzejewski-Szmek 126222
         }
Zbigniew Jędrzejewski-Szmek 126222
diff --git a/src/shared/macro.h b/src/shared/macro.h
Zbigniew Jędrzejewski-Szmek 126222
index d4f92b6..bc5b3c1 100644
Zbigniew Jędrzejewski-Szmek 126222
--- a/src/shared/macro.h
Zbigniew Jędrzejewski-Szmek 126222
+++ b/src/shared/macro.h
Zbigniew Jędrzejewski-Szmek 126222
@@ -114,6 +114,13 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
Zbigniew Jędrzejewski-Szmek 126222
                         _a < _b ? _a : _b;      \
Zbigniew Jędrzejewski-Szmek 126222
                 })
Zbigniew Jędrzejewski-Szmek 126222
 
Zbigniew Jędrzejewski-Szmek 126222
+#define LESS_BY(A,B)                            \
Zbigniew Jędrzejewski-Szmek 126222
+        __extension__ ({                        \
Zbigniew Jędrzejewski-Szmek 126222
+                        typeof(A) _A = (A);     \
Zbigniew Jędrzejewski-Szmek 126222
+                        typeof(B) _B = (B);     \
Zbigniew Jędrzejewski-Szmek 126222
+                        _A > _B ? _A - _B : 0;  \
Zbigniew Jędrzejewski-Szmek 126222
+                })
Zbigniew Jędrzejewski-Szmek 126222
+
Zbigniew Jędrzejewski-Szmek 126222
 #ifndef CLAMP
Zbigniew Jędrzejewski-Szmek 126222
 #define CLAMP(x, low, high)                                             \
Zbigniew Jędrzejewski-Szmek 126222
         __extension__ ({                                                \