summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-02-19 14:22:10 +0900
committerGitHub <noreply@github.com>2021-02-19 14:22:10 +0900
commit5be5d1f2a162ab80ef7d851dceea080f5e84acf4 (patch)
tree281183448ba5051012a2878acb0eb9bb00d090d3 /src
parent09db71a4a3fb9cee19f89cb75ad453caa46209b8 (diff)
parentd06e7fb53233bac014d1c3c9899ee291dcda1f71 (diff)
downloadsystemd-5be5d1f2a162ab80ef7d851dceea080f5e84acf4.tar.gz
Merge pull request #18659 from poettering/permyriadification
use scaling relative to UINT32_MAX instead of percentages/permyriads wherever we can
Diffstat (limited to 'src')
-rw-r--r--src/basic/limits-util.c27
-rw-r--r--src/basic/meson.build2
-rw-r--r--src/basic/parse-util.c140
-rw-r--r--src/basic/parse-util.h9
-rw-r--r--src/basic/percent-util.c157
-rw-r--r--src/basic/percent-util.h64
-rw-r--r--src/core/cgroup.c5
-rw-r--r--src/core/cgroup.h2
-rw-r--r--src/core/core-varlink.c2
-rw-r--r--src/core/dbus-cgroup.c20
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c19
-rw-r--r--src/core/main.c4
-rw-r--r--src/home/homectl.c7
-rw-r--r--src/import/importd.c1
-rw-r--r--src/login/logind-user.c9
-rw-r--r--src/login/pam_systemd.c5
-rw-r--r--src/network/tc/tc-util.c9
-rw-r--r--src/oom/oomd-manager.c53
-rw-r--r--src/oom/oomd-manager.h6
-rw-r--r--src/oom/oomd-util.c6
-rw-r--r--src/oom/oomd-util.h4
-rw-r--r--src/oom/oomd.c11
-rw-r--r--src/oom/oomd.conf2
-rw-r--r--src/oom/test-oomd-util.c6
-rw-r--r--src/shared/bus-unit-util.c16
-rw-r--r--src/shared/conf-parser.c1
-rw-r--r--src/test/meson.build2
-rw-r--r--src/test/test-parse-util.c144
-rw-r--r--src/test/test-percent-util.c211
30 files changed, 562 insertions, 384 deletions
diff --git a/src/basic/limits-util.c b/src/basic/limits-util.c
index 259c311a67..9f8e26d46a 100644
--- a/src/basic/limits-util.c
+++ b/src/basic/limits-util.c
@@ -77,7 +77,13 @@ uint64_t physical_memory(void) {
}
uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
- uint64_t p, m, ps, r;
+ uint64_t p, m, ps;
+
+ /* Shortcut two special cases */
+ if (v == 0)
+ return 0;
+ if (v == max)
+ return physical_memory();
assert(max > 0);
@@ -90,17 +96,16 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
p = physical_memory() / ps;
assert(p > 0);
- m = p * v;
- if (m / p != v)
+ if (v > UINT64_MAX / p)
return UINT64_MAX;
+ m = p * v;
m /= max;
- r = m * ps;
- if (r / ps != m)
+ if (m > UINT64_MAX / ps)
return UINT64_MAX;
- return r;
+ return m * ps;
}
uint64_t system_tasks_max(void) {
@@ -138,6 +143,12 @@ uint64_t system_tasks_max(void) {
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
uint64_t t, m;
+ /* Shortcut two special cases */
+ if (v == 0)
+ return 0;
+ if (v == max)
+ return system_tasks_max();
+
assert(max > 0);
/* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
@@ -146,9 +157,9 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
t = system_tasks_max();
assert(t > 0);
- m = t * v;
- if (m / t != v) /* overflow? */
+ if (v > UINT64_MAX / t) /* overflow? */
return UINT64_MAX;
+ m = t * v;
return m / max;
}
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 0b0982d543..88639bc9b5 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -176,6 +176,8 @@ basic_sources = files('''
path-lookup.h
path-util.c
path-util.h
+ percent-util.c
+ percent-util.h
prioq.c
prioq.h
proc-cmdline.c
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 97d224f165..b79c885dfd 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -627,146 +627,6 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
return 0;
}
-static int parse_parts_value_whole(const char *p, const char *symbol) {
- const char *pc, *n;
- int r, v;
-
- pc = endswith(p, symbol);
- if (!pc)
- return -EINVAL;
-
- n = strndupa(p, pc - p);
- r = safe_atoi(n, &v);
- if (r < 0)
- return r;
- if (v < 0)
- return -ERANGE;
-
- return v;
-}
-
-static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) {
- const char *pc, *dot, *n;
- int r, q, v;
-
- pc = endswith(p, symbol);
- if (!pc)
- return -EINVAL;
-
- dot = memchr(p, '.', pc - p);
- if (dot) {
- if (dot + 2 != pc)
- return -EINVAL;
- if (dot[1] < '0' || dot[1] > '9')
- return -EINVAL;
- q = dot[1] - '0';
- n = strndupa(p, dot - p);
- } else {
- q = 0;
- n = strndupa(p, pc - p);
- }
- r = safe_atoi(n, &v);
- if (r < 0)
- return r;
- if (v < 0)
- return -ERANGE;
- if (v > (INT_MAX - q) / 10)
- return -ERANGE;
-
- v = v * 10 + q;
- return v;
-}
-
-static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) {
- const char *pc, *dot, *n;
- int r, q, v;
-
- pc = endswith(p, symbol);
- if (!pc)
- return -EINVAL;
-
- dot = memchr(p, '.', pc - p);
- if (dot) {
- if (dot + 3 != pc)
- return -EINVAL;
- if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9')
- return -EINVAL;
- q = (dot[1] - '0') * 10 + (dot[2] - '0');
- n = strndupa(p, dot - p);
- } else {
- q = 0;
- n = strndupa(p, pc - p);
- }
- r = safe_atoi(n, &v);
- if (r < 0)
- return r;
- if (v < 0)
- return -ERANGE;
- if (v > (INT_MAX - q) / 100)
- return -ERANGE;
-
- v = v * 100 + q;
- return v;
-}
-
-int parse_percent_unbounded(const char *p) {
- return parse_parts_value_whole(p, "%");
-}
-
-int parse_percent(const char *p) {
- int v;
-
- v = parse_percent_unbounded(p);
- if (v > 100)
- return -ERANGE;
-
- return v;
-}
-
-int parse_permille_unbounded(const char *p) {
- const char *pm;
-
- pm = endswith(p, "‰");
- if (pm)
- return parse_parts_value_whole(p, "‰");
-
- return parse_parts_value_with_tenths_place(p, "%");
-}
-
-int parse_permille(const char *p) {
- int v;
-
- v = parse_permille_unbounded(p);
- if (v > 1000)
- return -ERANGE;
-
- return v;
-}
-
-int parse_permyriad_unbounded(const char *p) {
- const char *pm;
-
- pm = endswith(p, "‱");
- if (pm)
- return parse_parts_value_whole(p, "‱");
-
- pm = endswith(p, "‰");
- if (pm)
- return parse_parts_value_with_tenths_place(p, "‰");
-
- return parse_parts_value_with_hundredths_place(p, "%");
-}
-
-int parse_permyriad(const char *p) {
- int v;
-
- v = parse_permyriad_unbounded(p);
- if (v > 10000)
- return -ERANGE;
-
- return v;
-}
-
int parse_nice(const char *p, int *ret) {
int n, r;
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 29e04cf562..908202dafd 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -127,15 +127,6 @@ int safe_atod(const char *s, double *ret_d);
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
-int parse_percent_unbounded(const char *p);
-int parse_percent(const char *p);
-
-int parse_permille_unbounded(const char *p);
-int parse_permille(const char *p);
-
-int parse_permyriad_unbounded(const char *p);
-int parse_permyriad(const char *p);
-
int parse_nice(const char *p, int *ret);
int parse_ip_port(const char *s, uint16_t *ret);
diff --git a/src/basic/percent-util.c b/src/basic/percent-util.c
new file mode 100644
index 0000000000..06f20fd61e
--- /dev/null
+++ b/src/basic/percent-util.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "percent-util.h"
+#include "string-util.h"
+#include "parse-util.h"
+
+static int parse_parts_value_whole(const char *p, const char *symbol) {
+ const char *pc, *n;
+ int r, v;
+
+ pc = endswith(p, symbol);
+ if (!pc)
+ return -EINVAL;
+
+ n = strndupa(p, pc - p);
+ r = safe_atoi(n, &v);
+ if (r < 0)
+ return r;
+ if (v < 0)
+ return -ERANGE;
+
+ return v;
+}
+
+static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) {
+ const char *pc, *dot, *n;
+ int r, q, v;
+
+ pc = endswith(p, symbol);
+ if (!pc)
+ return -EINVAL;
+
+ dot = memchr(p, '.', pc - p);
+ if (dot) {
+ if (dot + 2 != pc)
+ return -EINVAL;
+ if (dot[1] < '0' || dot[1] > '9')
+ return -EINVAL;
+ q = dot[1] - '0';
+ n = strndupa(p, dot - p);
+ } else {
+ q = 0;
+ n = strndupa(p, pc - p);
+ }
+ r = safe_atoi(n, &v);
+ if (r < 0)
+ return r;
+ if (v < 0)
+ return -ERANGE;
+ if (v > (INT_MAX - q) / 10)
+ return -ERANGE;
+
+ v = v * 10 + q;
+ return v;
+}
+
+static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) {
+ const char *pc, *dot, *n;
+ int r, q, v;
+
+ pc = endswith(p, symbol);
+ if (!pc)
+ return -EINVAL;
+
+ dot = memchr(p, '.', pc - p);
+ if (dot) {
+ if (dot + 3 == pc) {
+ /* Support two places after the dot */
+
+ if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9')
+ return -EINVAL;
+ q = (dot[1] - '0') * 10 + (dot[2] - '0');
+
+ } else if (dot + 2 == pc) {
+ /* Support one place after the dot */
+
+ if (dot[1] < '0' || dot[1] > '9')
+ return -EINVAL;
+ q = (dot[1] - '0') * 10;
+ } else
+ /* We do not support zero or more than two places */
+ return -EINVAL;
+
+ n = strndupa(p, dot - p);
+ } else {
+ q = 0;
+ n = strndupa(p, pc - p);
+ }
+ r = safe_atoi(n, &v);
+ if (r < 0)
+ return r;
+ if (v < 0)
+ return -ERANGE;
+ if (v > (INT_MAX - q) / 100)
+ return -ERANGE;
+
+ v = v * 100 + q;
+ return v;
+}
+
+int parse_percent_unbounded(const char *p) {
+ return parse_parts_value_whole(p, "%");
+}
+
+int parse_percent(const char *p) {
+ int v;
+
+ v = parse_percent_unbounded(p);
+ if (v > 100)
+ return -ERANGE;
+
+ return v;
+}
+
+int parse_permille_unbounded(const char *p) {
+ const char *pm;
+
+ pm = endswith(p, "‰");
+ if (pm)
+ return parse_parts_value_whole(p, "‰");
+
+ return parse_parts_value_with_tenths_place(p, "%");
+}
+
+int parse_permille(const char *p) {
+ int v;
+
+ v = parse_permille_unbounded(p);
+ if (v > 1000)
+ return -ERANGE;
+
+ return v;
+}
+
+int parse_permyriad_unbounded(const char *p) {
+ const char *pm;
+
+ pm = endswith(p, "‱");
+ if (pm)
+ return parse_parts_value_whole(p, "‱");
+
+ pm = endswith(p, "‰");
+ if (pm)
+ return parse_parts_value_with_tenths_place(p, "‰");
+
+ return parse_parts_value_with_hundredths_place(p, "%");
+}
+
+int parse_permyriad(const char *p) {
+ int v;
+
+ v = parse_permyriad_unbounded(p);
+ if (v > 10000)
+ return -ERANGE;
+
+ return v;
+}
diff --git a/src/basic/percent-util.h b/src/basic/percent-util.h
new file mode 100644
index 0000000000..24f4c3bdef
--- /dev/null
+++ b/src/basic/percent-util.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include "macro.h"
+
+int parse_percent_unbounded(const char *p);
+int parse_percent(const char *p);
+
+int parse_permille_unbounded(const char *p);
+int parse_permille(const char *p);
+
+int parse_permyriad_unbounded(const char *p);
+int parse_permyriad(const char *p);
+
+/* Some macro-like helpers that convert a percent/permille/permyriad value (as parsed by parse_percent()) to
+ * a value relative to 100% == 2^32-1. Rounds to closest. */
+static inline uint32_t UINT32_SCALE_FROM_PERCENT(int percent) {
+ assert_cc(INT_MAX <= UINT32_MAX);
+ return (uint32_t) (((uint64_t) percent * UINT32_MAX + 50) / 100U);
+}
+
+static inline uint32_t UINT32_SCALE_FROM_PERMILLE(int permille) {
+ return (uint32_t) (((uint64_t) permille * UINT32_MAX + 500) / 1000U);
+}
+
+static inline uint32_t UINT32_SCALE_FROM_PERMYRIAD(int permyriad) {
+ return (uint32_t) (((uint64_t) permyriad * UINT32_MAX + 5000) / 10000U);
+}
+
+static inline int UINT32_SCALE_TO_PERCENT(uint32_t scale) {
+ uint32_t u;
+
+ u = (uint32_t) ((((uint64_t) scale) * 100U + UINT32_MAX/2) / UINT32_MAX);
+ if (u > INT_MAX)
+ return -ERANGE;
+
+ return (int) u;
+}
+
+static inline int UINT32_SCALE_TO_PERMILLE(uint32_t scale) {
+ uint32_t u;
+
+ u = (uint32_t) ((((uint64_t) scale) * 1000U + UINT32_MAX/2) / UINT32_MAX);
+ if (u > INT_MAX)
+ return -ERANGE;
+
+ return (int) u;
+}
+
+static inline int UINT32_SCALE_TO_PERMYRIAD(uint32_t scale) {
+ uint32_t u;
+
+ u = (uint32_t) ((((uint64_t) scale) * 10000U + UINT32_MAX/2) / UINT32_MAX);
+ if (u > INT_MAX)
+ return -ERANGE;
+
+ return (int) u;
+}
+
+#define PERMYRIAD_AS_PERCENT_FORMAT_STR "%i.%02i%%"
+#define PERMYRIAD_AS_PERCENT_FORMAT_VAL(x) ((x)/100), ((x)%100)
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index b0fc67a125..1f74cb393f 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -21,6 +21,7 @@
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#include "procfs-util.h"
#include "special.h"
@@ -418,7 +419,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
"%sDelegate: %s\n"
"%sManagedOOMSwap: %s\n"
"%sManagedOOMMemoryPressure: %s\n"
- "%sManagedOOMMemoryPressureLimit: %" PRIu32 ".%02" PRIu32 "%%\n"
+ "%sManagedOOMMemoryPressureLimit: " PERMYRIAD_AS_PERCENT_FORMAT_STR "\n"
"%sManagedOOMPreference: %s%%\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->io_accounting),
@@ -452,7 +453,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
prefix, yes_no(c->delegate),
prefix, managed_oom_mode_to_string(c->moom_swap),
prefix, managed_oom_mode_to_string(c->moom_mem_pressure),
- prefix, c->moom_mem_pressure_limit_permyriad / 100, c->moom_mem_pressure_limit_permyriad % 100,
+ prefix, PERMYRIAD_AS_PERCENT_FORMAT_VAL(UINT32_SCALE_TO_PERMYRIAD(c->moom_mem_pressure_limit)),
prefix, managed_oom_preference_to_string(c->moom_preference));
if (c->delegate) {
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 8183551420..fa79ba1523 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -163,7 +163,7 @@ struct CGroupContext {
/* Settings for systemd-oomd */
ManagedOOMMode moom_swap;
ManagedOOMMode moom_mem_pressure;
- uint32_t moom_mem_pressure_limit_permyriad;
+ uint32_t moom_mem_pressure_limit; /* Normalized to 2^32-1 == 100% */
ManagedOOMPreference moom_preference;
};
diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c
index df542e82d1..d695106658 100644
--- a/src/core/core-varlink.c
+++ b/src/core/core-varlink.c
@@ -83,7 +83,7 @@ static int build_managed_oom_json_array_element(Unit *u, const char *property, J
JSON_BUILD_PAIR("mode", JSON_BUILD_STRING(mode)),
JSON_BUILD_PAIR("path", JSON_BUILD_STRING(u->cgroup_path)),
JSON_BUILD_PAIR("property", JSON_BUILD_STRING(property)),
- JSON_BUILD_PAIR_CONDITION(use_limit, "limit", JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit_permyriad))));
+ JSON_BUILD_PAIR_CONDITION(use_limit, "limit", JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit))));
}
int manager_varlink_send_managed_oom_update(Unit *u) {
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 6652c212f1..04d2ba34f3 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -16,6 +16,7 @@
#include "fileio.h"
#include "limits-util.h"
#include "path-util.h"
+#include "percent-util.h"
BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", TasksMax, tasks_max_resolve);
@@ -395,7 +396,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("DisableControllers", "as", property_get_cgroup_mask, offsetof(CGroupContext, disable_controllers), 0),
SD_BUS_PROPERTY("ManagedOOMSwap", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_swap), 0),
SD_BUS_PROPERTY("ManagedOOMMemoryPressure", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_mem_pressure), 0),
- SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimitPermyriad", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit_permyriad), 0),
+ SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimit", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit), 0),
SD_BUS_PROPERTY("ManagedOOMPreference", "s", property_get_managed_oom_preference, offsetof(CGroupContext, moom_preference), 0),
SD_BUS_VTABLE_END
};
@@ -704,10 +705,10 @@ static int bus_cgroup_set_boolean(
/* Prepare to chop off suffix */ \
assert_se(endswith(name, "Scale")); \
\
- uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
- unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
+ int scaled = UINT32_SCALE_TO_PERMYRIAD(raw); \
+ unit_write_settingf(u, flags, name, "%.*s=" PERMYRIAD_AS_PERCENT_FORMAT_STR, \
(int)(strlen(name) - strlen("Scale")), name, \
- scaled / 10, scaled % 10); \
+ PERMYRIAD_AS_PERCENT_FORMAT_VAL(scaled)); \
} \
\
return 1; \
@@ -1698,7 +1699,7 @@ int bus_cgroup_set_property(
return 1;
}
- if (streq(name, "ManagedOOMMemoryPressureLimitPermyriad")) {
+ if (streq(name, "ManagedOOMMemoryPressureLimit")) {
uint32_t v;
if (!UNIT_VTABLE(u)->can_set_managed_oom)
@@ -1708,12 +1709,11 @@ int bus_cgroup_set_property(
if (r < 0)
return r;
- if (v > 10000)
- return -ERANGE;
-
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- c->moom_mem_pressure_limit_permyriad = v;
- unit_write_settingf(u, flags, name, "ManagedOOMMemoryPressureLimit=%" PRIu32 ".%02" PRIu32 "%%", v / 100, v % 100);
+ c->moom_mem_pressure_limit = v;
+ unit_write_settingf(u, flags, name,
+ "ManagedOOMMemoryPressureLimit=" PERMYRIAD_AS_PERCENT_FORMAT_STR,
+ PERMYRIAD_AS_PERCENT_FORMAT_VAL(UINT32_SCALE_TO_PERMYRIAD(v)));
}
if (c->moom_mem_pressure == MANAGED_OOM_KILL)
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index b0460e2764..6ed6b07db2 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -229,7 +229,7 @@ $1.IPIngressFilterPath, config_parse_ip_filter_bpf_progs,
$1.IPEgressFilterPath, config_parse_ip_filter_bpf_progs, 0, offsetof($1, cgroup_context.ip_filters_egress)
$1.ManagedOOMSwap, config_parse_managed_oom_mode, 0, offsetof($1, cgroup_context.moom_swap)
$1.ManagedOOMMemoryPressure, config_parse_managed_oom_mode, 0, offsetof($1, cgroup_context.moom_mem_pressure)
-$1.ManagedOOMMemoryPressureLimit, config_parse_managed_oom_mem_pressure_limit, 0, offsetof($1, cgroup_context.moom_mem_pressure_limit_permyriad)
+$1.ManagedOOMMemoryPressureLimit, config_parse_managed_oom_mem_pressure_limit, 0, offsetof($1, cgroup_context.moom_mem_pressure_limit)
$1.ManagedOOMPreference, config_parse_managed_oom_preference, 0, offsetof($1, cgroup_context.moom_preference)
$1.NetClass, config_parse_warn_compat, DISABLED_LEGACY, 0'
)m4_dnl
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 11836c0938..b9fc450ac7 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -46,6 +46,7 @@
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#if HAVE_SECCOMP
#include "seccomp-util.h"
@@ -3593,13 +3594,13 @@ int config_parse_cpu_quota(
return 0;
}
- r = parse_permille_unbounded(rvalue);
+ r = parse_permyriad_unbounded(rvalue);
if (r <= 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
return 0;
}
- c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U;
+ c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 10000U;
return 0;
}
@@ -3664,7 +3665,7 @@ int config_parse_memory_limit(
bytes = CGROUP_LIMIT_MIN;
else if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
- r = parse_permille(rvalue);
+ r = parse_permyriad(rvalue);
if (r < 0) {
r = parse_size(rvalue, 1024, &bytes);
if (r < 0) {
@@ -3672,7 +3673,7 @@ int config_parse_memory_limit(
return 0;
}
} else
- bytes = physical_memory_scale(r, 1000U);
+ bytes = physical_memory_scale(r, 10000U);
if (bytes >= UINT64_MAX ||
(bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) {
@@ -3734,9 +3735,9 @@ int config_parse_tasks_max(
return 0;
}
- r = parse_permille(rvalue);
+ r = parse_permyriad(rvalue);
if (r >= 0)
- *tasks_max = (TasksMax) { r, 1000U }; /* r‰ */
+ *tasks_max = (TasksMax) { r, 10000U }; /* r‱ */
else {
r = safe_atou64(rvalue, &v);
if (r < 0) {
@@ -3842,6 +3843,7 @@ int config_parse_managed_oom_mode(
const char *rvalue,
void *data,
void *userdata) {
+
ManagedOOMMode *mode = data, m;
UnitType t;
@@ -3861,6 +3863,7 @@ int config_parse_managed_oom_mode(
log_syntax(unit, LOG_WARNING, filename, line, m, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
+
*mode = m;
return 0;
}
@@ -3876,6 +3879,7 @@ int config_parse_managed_oom_mem_pressure_limit(
const char *rvalue,
void *data,
void *userdata) {
+
uint32_t *limit = data;
UnitType t;
int r;
@@ -3897,7 +3901,8 @@ int config_parse_managed_oom_mem_pressure_limit(
return 0;
}
- *limit = r;
+ /* Normalize to 2^32-1 == 100% */
+ *limit = UINT32_SCALE_FROM_PERMYRIAD(r);
return 0;
}
diff --git a/src/core/main.c b/src/core/main.c
index f29449d691..67189fef6d 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1256,8 +1256,8 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
* must be unsigned, hence this is a given, but let's make this clear here. */
assert_cc(RLIM_INFINITY > 0);
- mm = physical_memory() / 8; /* Let's scale how much we allow to be locked by the amount of physical
- * RAM. We allow an eighth to be locked by us, just to pick a value. */
+ mm = physical_memory_scale(1, 8); /* Let's scale how much we allow to be locked by the amount of physical
+ * RAM. We allow an eighth to be locked by us, just to pick a value. */
new_rlimit = (struct rlimit) {
.rlim_cur = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur, mm),
diff --git a/src/home/homectl.c b/src/home/homectl.c
index fa9d11e69d..d59dfb1f60 100644
--- a/src/home/homectl.c
+++ b/src/home/homectl.c
@@ -26,6 +26,7 @@
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "pkcs11-util.h"
#include "pretty-print.h"
#include "process-util.h"
@@ -1567,7 +1568,7 @@ static int resize_home(int argc, char *argv[], void *userdata) {
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
if (arg_disk_size_relative != UINT64_MAX ||
- (argc > 2 && parse_percent(argv[2]) >= 0))
+ (argc > 2 && parse_permyriad(argv[2]) >= 0))
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Relative disk size specification currently not supported when resizing.");
@@ -2653,7 +2654,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
- r = parse_permille(optarg);
+ r = parse_permyriad(optarg);
if (r < 0) {
r = parse_size(optarg, 1024, &arg_disk_size);
if (r < 0)
@@ -2670,7 +2671,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_disk_size_relative = UINT64_MAX;
} else {
/* Normalize to UINT32_MAX == 100% */
- arg_disk_size_relative = (uint64_t) r * UINT32_MAX / 1000U;
+ arg_disk_size_relative = UINT32_SCALE_FROM_PERMYRIAD(r);
r = drop_from_identity("diskSize");
if (r < 0)
diff --git a/src/import/importd.c b/src/import/importd.c
index 9ac2f8dcfe..f9e8481a6d 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -22,6 +22,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#include "service-util.h"
#include "signal-util.h"
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 9b3ec07906..a2c468e8dd 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -19,11 +19,12 @@
#include "label.h"
#include "limits-util.h"
#include "logind-dbus.h"
-#include "logind-user.h"
#include "logind-user-dbus.h"
+#include "logind-user.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "rm-rf.h"
#include "serialize.h"
#include "special.h"
@@ -907,9 +908,9 @@ int config_parse_tmpfs_size(
assert(data);
/* First, try to parse as percentage */
- r = parse_permille(rvalue);
- if (r > 0 && r < 1000)
- *sz = physical_memory_scale(r, 1000U);
+ r = parse_permyriad(rvalue);
+ if (r > 0)
+ *sz = physical_memory_scale(r, 10000U);
else {
uint64_t k;
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 8e7a94db55..a23200b3b5 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -34,6 +34,7 @@
#include "pam-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "socket-util.h"
@@ -334,9 +335,9 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co
return PAM_SUCCESS;
}
- r = parse_permille(limit);
+ r = parse_permyriad(limit);
if (r >= 0) {
- r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
+ r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return pam_bus_log_create_error(handle, r);
diff --git a/src/network/tc/tc-util.c b/src/network/tc/tc-util.c
index 3e10b50c96..3781182946 100644
--- a/src/network/tc/tc-util.c
+++ b/src/network/tc/tc-util.c
@@ -5,6 +5,7 @@
#include "extract-word.h"
#include "fileio.h"
#include "parse-util.h"
+#include "percent-util.h"
#include "tc-util.h"
#include "time-util.h"
@@ -57,17 +58,17 @@ int tc_time_to_tick(usec_t t, uint32_t *ret) {
return 0;
}
-int parse_tc_percent(const char *s, uint32_t *percent) {
+int parse_tc_percent(const char *s, uint32_t *ret_fraction) {
int r;
assert(s);
- assert(percent);
+ assert(ret_fraction);
- r = parse_permille(s);
+ r = parse_permyriad(s);
if (r < 0)
return r;
- *percent = (double) r / 1000 * UINT32_MAX;
+ *ret_fraction = (double) r / 10000 * UINT32_MAX;
return 0;
}
diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c
index bdf41807b2..fad1fb0d45 100644
--- a/src/oom/oomd-manager.c
+++ b/src/oom/oomd-manager.c
@@ -10,12 +10,13 @@
#include "oomd-manager-bus.h"
#include "oomd-manager.h"
#include "path-util.h"
+#include "percent-util.h"
typedef struct ManagedOOMReply {
ManagedOOMMode mode;
char *path;
char *property;
- unsigned limit;
+ uint32_t limit;
} ManagedOOMReply;
static void managed_oom_reply_destroy(ManagedOOMReply *reply) {
@@ -52,10 +53,10 @@ static int process_managed_oom_reply(
assert(m);
static const JsonDispatch dispatch_table[] = {
- { "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMReply, mode), JSON_MANDATORY },
- { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, path), JSON_MANDATORY },
- { "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, property), JSON_MANDATORY },
- { "limit", JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(ManagedOOMReply, limit), 0 },
+ { "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMReply, mode), JSON_MANDATORY },
+ { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, path), JSON_MANDATORY },
+ { "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, property), JSON_MANDATORY },
+ { "limit", JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(ManagedOOMReply, limit), 0 },
{},
};
@@ -86,7 +87,8 @@ static int process_managed_oom_reply(
if (ret == -ENOMEM) {
r = ret;
goto finish;
- } else if (ret < 0)
+ }
+ if (ret < 0)
continue;
monitor_hm = streq(reply.property, "ManagedOOMSwap") ?
@@ -99,14 +101,15 @@ static int process_managed_oom_reply(
limit = m->default_mem_pressure_limit;
- if (streq(reply.property, "ManagedOOMMemoryPressure")) {
- if (reply.limit > 10000)
+ if (streq(reply.property, "ManagedOOMMemoryPressure") && reply.limit > 0) {
+ int permyriad = UINT32_SCALE_TO_PERMYRIAD(reply.limit);
+
+ ret = store_loadavg_fixed_point(
+ (unsigned long) permyriad / 100,
+ (unsigned long) permyriad % 100,
+ &limit);
+ if (ret < 0)
continue;
- else if (reply.limit != 0) {
- ret = store_loadavg_fixed_point((unsigned long) reply.limit / 100, (unsigned long) reply.limit % 100, &limit);
- if (ret < 0)
- continue;
- }
}
ret = oomd_insert_cgroup_context(NULL, monitor_hm, empty_to_root(reply.path));
@@ -348,11 +351,11 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo
}
}
- if (oomd_swap_free_below(&m->system_context, (100 - m->swap_used_limit))) {
+ if (oomd_swap_free_below(&m->system_context, 10000 - m->swap_used_limit_permyriad)) {
_cleanup_hashmap_free_ Hashmap *candidates = NULL;
- log_notice("Swap used (%"PRIu64") / total (%"PRIu64") is more than %u%%",
- m->system_context.swap_used, m->system_context.swap_total, m->swap_used_limit);
+ log_notice("Swap used (%"PRIu64") / total (%"PRIu64") is more than " PERMYRIAD_AS_PERCENT_FORMAT_STR,
+ m->system_context.swap_used, m->system_context.swap_total, PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad));
r = get_monitored_cgroup_contexts_candidates(m->monitored_swap_cgroup_contexts, &candidates);
if (r == -ENOMEM)
@@ -478,7 +481,13 @@ static int manager_connect_bus(Manager *m) {
return 0;
}
-int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec) {
+int manager_start(
+ Manager *m,
+ bool dry_run,
+ int swap_used_limit_permyriad,
+ int mem_pressure_limit_permyriad,
+ usec_t mem_pressure_usec) {
+
unsigned long l, f;
int r;
@@ -486,10 +495,10 @@ int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressur
m->dry_run = dry_run;
- m->swap_used_limit = swap_used_limit != -1 ? swap_used_limit : DEFAULT_SWAP_USED_LIMIT;
- assert(m->swap_used_limit <= 100);
+ m->swap_used_limit_permyriad = swap_used_limit_permyriad >= 0 ? swap_used_limit_permyriad : DEFAULT_SWAP_USED_LIMIT_PERCENT * 100;
+ assert(m->swap_used_limit_permyriad <= 10000);
- if (mem_pressure_limit_permyriad != -1) {
+ if (mem_pressure_limit_permyriad >= 0) {
assert(mem_pressure_limit_permyriad <= 10000);
l = mem_pressure_limit_permyriad / 100;
@@ -537,12 +546,12 @@ int manager_get_dump_string(Manager *m, char **ret) {
fprintf(f,
"Dry Run: %s\n"
- "Swap Used Limit: %u%%\n"
+ "Swap Used Limit: " PERMYRIAD_AS_PERCENT_FORMAT_STR "\n"
"Default Memory Pressure Limit: %lu.%02lu%%\n"
"Default Memory Pressure Duration: %s\n"
"System Context:\n",
yes_no(m->dry_run),
- m->swap_used_limit,
+ PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad),
LOAD_INT(m->default_mem_pressure_limit), LOAD_FRAC(m->default_mem_pressure_limit),
format_timespan(buf, sizeof(buf), m->default_mem_pressure_duration_usec, USEC_PER_SEC));
oomd_dump_system_context(&m->system_context, f, "\t");
diff --git a/src/oom/oomd-manager.h b/src/oom/oomd-manager.h
index 50f10021c7..9ab8494c6d 100644
--- a/src/oom/oomd-manager.h
+++ b/src/oom/oomd-manager.h
@@ -18,7 +18,7 @@
* system.slice are assumed to be less latency sensitive. */
#define DEFAULT_MEM_PRESSURE_DURATION_USEC (30 * USEC_PER_SEC)
#define DEFAULT_MEM_PRESSURE_LIMIT_PERCENT 60
-#define DEFAULT_SWAP_USED_LIMIT 90
+#define DEFAULT_SWAP_USED_LIMIT_PERCENT 90
#define RECLAIM_DURATION_USEC (30 * USEC_PER_SEC)
#define POST_ACTION_DELAY_USEC (15 * USEC_PER_SEC)
@@ -32,7 +32,7 @@ struct Manager {
Hashmap *polkit_registry;
bool dry_run;
- unsigned swap_used_limit;
+ int swap_used_limit_permyriad;
loadavg_t default_mem_pressure_limit;
usec_t default_mem_pressure_duration_usec;
@@ -56,7 +56,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
int manager_new(Manager **ret);
-int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec);
+int manager_start(Manager *m, bool dry_run, int swap_used_limit_permyriad, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec);
int manager_get_dump_string(Manager *m, char **ret);
diff --git a/src/oom/oomd-util.c b/src/oom/oomd-util.c
index 9dd9b17c6d..b054ccacc4 100644
--- a/src/oom/oomd-util.c
+++ b/src/oom/oomd-util.c
@@ -134,13 +134,13 @@ bool oomd_memory_reclaim(Hashmap *h) {
return pgscan_of > last_pgscan_of;
}
-bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent) {
+bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad) {
uint64_t swap_threshold;
assert(ctx);
- assert(threshold_percent <= 100);
+ assert(threshold_permyriad <= 10000);
- swap_threshold = ctx->swap_total * threshold_percent / ((uint64_t) 100);
+ swap_threshold = ctx->swap_total * threshold_permyriad / (uint64_t) 10000;
return (ctx->swap_total - ctx->swap_used) < swap_threshold;
}
diff --git a/src/oom/oomd-util.h b/src/oom/oomd-util.h
index bffccf75da..181443ae7a 100644
--- a/src/oom/oomd-util.h
+++ b/src/oom/oomd-util.h
@@ -61,8 +61,8 @@ int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret);
* current sum is higher than the last interval's sum (there was some reclaim activity). */
bool oomd_memory_reclaim(Hashmap *h);
-/* Returns true if the amount of swap free is below the percentage of swap specified by `threshold_percent`. */
-bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent);
+/* Returns true if the amount of swap free is below the permyriad of swap specified by `threshold_permyriad`. */
+bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad);
/* The compare functions will sort from largest to smallest, putting all the contexts with "avoid" at the end
* (after the smallest values). */
diff --git a/src/oom/oomd.c b/src/oom/oomd.c
index 2e331e267f..674d53fdcf 100644
--- a/src/oom/oomd.c
+++ b/src/oom/oomd.c
@@ -17,13 +17,13 @@
#include "signal-util.h"
static bool arg_dry_run = false;
-static int arg_swap_used_limit = -1;
+static int arg_swap_used_limit_permyriad = -1;
static int arg_mem_pressure_limit_permyriad = -1;
static usec_t arg_mem_pressure_usec = 0;
static int parse_config(void) {
static const ConfigTableItem items[] = {
- { "OOM", "SwapUsedLimitPercent", config_parse_percent, 0, &arg_swap_used_limit },
+ { "OOM", "SwapUsedLimit", config_parse_permyriad, 0, &arg_swap_used_limit_permyriad },
{ "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad },
{ "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec, 0, &arg_mem_pressure_usec },
{}
@@ -159,7 +159,12 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to create manager: %m");
- r = manager_start(m, arg_dry_run, arg_swap_used_limit, arg_mem_pressure_limit_permyriad, arg_mem_pressure_usec);
+ r = manager_start(
+ m,
+ arg_dry_run,
+ arg_swap_used_limit_permyriad,
+ arg_mem_pressure_limit_permyriad,
+ arg_mem_pressure_usec);
if (r < 0)
return log_error_errno(r, "Failed to start up daemon: %m");
diff --git a/src/oom/oomd.conf b/src/oom/oomd.conf
index 59e3416bf3..f1bef9de6f 100644
--- a/src/oom/oomd.conf
+++ b/src/oom/oomd.conf
@@ -13,6 +13,6 @@
# See oomd.conf(5) for details
[OOM]
-#SwapUsedLimitPercent=90%
+#SwapUsedLimit=90%
#DefaultMemoryPressureLimit=60%
#DefaultMemoryPressureDurationSec=30s
diff --git a/src/oom/test-oomd-util.c b/src/oom/test-oomd-util.c
index 49a02f9424..a0e583ac6b 100644
--- a/src/oom/test-oomd-util.c
+++ b/src/oom/test-oomd-util.c
@@ -302,19 +302,19 @@ static void test_oomd_swap_free_below(void) {
.swap_total = 20971512 * 1024U,
.swap_used = 20971440 * 1024U,
};
- assert_se(oomd_swap_free_below(&ctx, 20) == true);
+ assert_se(oomd_swap_free_below(&ctx, 2000) == true);
ctx = (OomdSystemContext) {
.swap_total = 20971512 * 1024U,
.swap_used = 3310136 * 1024U,
};
- assert_se(oomd_swap_free_below(&ctx, 20) == false);
+ assert_se(oomd_swap_free_below(&ctx, 2000) == false);
ctx = (OomdSystemContext) {
.swap_total = 0,
.swap_used = 0,
};
- assert_se(oomd_swap_free_below(&ctx, 20) == false);
+ assert_se(oomd_swap_free_below(&ctx, 2000) == false);
}
static void test_oomd_sort_cgroups(void) {
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 548dc57e3c..83130db2fa 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -28,6 +28,7 @@
#include "numa-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#if HAVE_SECCOMP
@@ -440,15 +441,12 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
- char *n;
-
r = parse_permyriad(eq);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
- n = strjoina(field, "Permyriad");
-
- r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) r);
+ /* Pass around scaled to 2^32-1 == 100% */
+ r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return bus_log_create_error(r);
@@ -539,7 +537,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return 1;
}
- r = parse_permille(eq);
+ r = parse_permyriad(eq);
if (r >= 0) {
char *n;
@@ -548,7 +546,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
* size can be determined server-side. */
n = strjoina(field, "Scale");
- r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
+ r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return bus_log_create_error(r);
@@ -565,14 +563,14 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
if (isempty(eq))
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
else {
- r = parse_permille_unbounded(eq);
+ r = parse_permyriad_unbounded(eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"CPU quota too small.");
if (r < 0)
return log_error_errno(r, "CPU quota '%s' invalid.", eq);
- r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
+ r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
}
if (r < 0)
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index c3d7e536ec..df6472d4be 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -22,6 +22,7 @@
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "sd-id128.h"
diff --git a/src/test/meson.build b/src/test/meson.build
index 5bf1ca3490..c567a4cfcb 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -547,6 +547,8 @@ tests += [
[['src/test/test-bus-util.c']],
+ [['src/test/test-percent-util.c']],
+
[['src/test/test-sd-hwdb.c']],
[['src/test/test-sd-path.c']],
diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
index 6e23efe134..756934acad 100644
--- a/src/test/test-parse-util.c
+++ b/src/test/test-parse-util.c
@@ -718,144 +718,6 @@ static void test_safe_atod(void) {
assert_se(r == -EINVAL);
}
-static void test_parse_percent(void) {
- assert_se(parse_percent("") == -EINVAL);
- assert_se(parse_percent("foo") == -EINVAL);
- assert_se(parse_percent("0") == -EINVAL);
- assert_se(parse_percent("50") == -EINVAL);
- assert_se(parse_percent("100") == -EINVAL);
- assert_se(parse_percent("-1") == -EINVAL);
- assert_se(parse_percent("0%") == 0);
- assert_se(parse_percent("55%") == 55);
- assert_se(parse_percent("100%") == 100);
- assert_se(parse_percent("-7%") == -ERANGE);
- assert_se(parse_percent("107%") == -ERANGE);
- assert_se(parse_percent("%") == -EINVAL);
- assert_se(parse_percent("%%") == -EINVAL);
- assert_se(parse_percent("%1") == -EINVAL);
- assert_se(parse_percent("1%%") == -EINVAL);
- assert_se(parse_percent("3.2%") == -EINVAL);
-}
-
-static void test_parse_percent_unbounded(void) {
- assert_se(parse_percent_unbounded("101%") == 101);
- assert_se(parse_percent_unbounded("400%") == 400);
-}
-
-static void test_parse_permille(void) {
- assert_se(parse_permille("") == -EINVAL);
- assert_se(parse_permille("foo") == -EINVAL);
- assert_se(parse_permille("0") == -EINVAL);
- assert_se(parse_permille("50") == -EINVAL);
- assert_se(parse_permille("100") == -EINVAL);
- assert_se(parse_permille("-1") == -EINVAL);
-
- assert_se(parse_permille("0‰") == 0);
- assert_se(parse_permille("555‰") == 555);
- assert_se(parse_permille("1000‰") == 1000);
- assert_se(parse_permille("-7‰") == -ERANGE);
- assert_se(parse_permille("1007‰") == -ERANGE);
- assert_se(parse_permille("‰") == -EINVAL);
- assert_se(parse_permille("‰‰") == -EINVAL);
- assert_se(parse_permille("‰1") == -EINVAL);
- assert_se(parse_permille("1‰‰") == -EINVAL);
- assert_se(parse_permille("3.2‰") == -EINVAL);
-
- assert_se(parse_permille("0%") == 0);
- assert_se(parse_permille("55%") == 550);
- assert_se(parse_permille("55.5%") == 555);
- assert_se(parse_permille("100%") == 1000);
- assert_se(parse_permille("-7%") == -ERANGE);
- assert_se(parse_permille("107%") == -ERANGE);
- assert_se(parse_permille("%") == -EINVAL);
- assert_se(parse_permille("%%") == -EINVAL);
- assert_se(parse_permille("%1") == -EINVAL);
- assert_se(parse_permille("1%%") == -EINVAL);
- assert_se(parse_permille("3.21%") == -EINVAL);
-}
-
-static void test_parse_permille_unbounded(void) {
- assert_se(parse_permille_unbounded("1001‰") == 1001);
- assert_se(parse_permille_unbounded("4000‰") == 4000);
- assert_se(parse_permille_unbounded("2147483647‰") == 2147483647);
- assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE);
- assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE);
- assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE);
-
- assert_se(parse_permille_unbounded("101%") == 1010);
- assert_se(parse_permille_unbounded("400%") == 4000);
- assert_se(parse_permille_unbounded("214748364.7%") == 2147483647);
- assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE);
- assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE);
- assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE);
-}
-
-static void test_parse_permyriad(void) {
- assert_se(parse_permyriad("") == -EINVAL);
- assert_se(parse_permyriad("foo") == -EINVAL);
- assert_se(parse_permyriad("0") == -EINVAL);
- assert_se(parse_permyriad("50") == -EINVAL);
- assert_se(parse_permyriad("100") == -EINVAL);
- assert_se(parse_permyriad("-1") == -EINVAL);
-
- assert_se(parse_permyriad("0‱") == 0);
- assert_se(parse_permyriad("555‱") == 555);
- assert_se(parse_permyriad("1000‱") == 1000);
- assert_se(parse_permyriad("-7‱") == -ERANGE);
- assert_se(parse_permyriad("10007‱") == -ERANGE);
- assert_se(parse_permyriad("‱") == -EINVAL);
- assert_se(parse_permyriad("‱‱") == -EINVAL);
- assert_se(parse_permyriad("‱1") == -EINVAL);
- assert_se(parse_permyriad("1‱‱") == -EINVAL);
- assert_se(parse_permyriad("3.2‱") == -EINVAL);
-
- assert_se(parse_permyriad("0‰") == 0);
- assert_se(parse_permyriad("555.5‰") == 5555);
- assert_se(parse_permyriad("1000.0‰") == 10000);
- assert_se(parse_permyriad("-7‰") == -ERANGE);
- assert_se(parse_permyriad("1007‰") == -ERANGE);
- assert_se(parse_permyriad("‰") == -EINVAL);
- assert_se(parse_permyriad("‰‰") == -EINVAL);
- assert_se(parse_permyriad("‰1") == -EINVAL);
- assert_se(parse_permyriad("1‰‰") == -EINVAL);
- assert_se(parse_permyriad("3.22‰") == -EINVAL);
-
- assert_se(parse_permyriad("0%") == 0);
- assert_se(parse_permyriad("55%") == 5500);
- assert_se(parse_permyriad("55.53%") == 5553);
- assert_se(parse_permyriad("100%") == 10000);
- assert_se(parse_permyriad("-7%") == -ERANGE);
- assert_se(parse_permyriad("107%") == -ERANGE);
- assert_se(parse_permyriad("%") == -EINVAL);
- assert_se(parse_permyriad("%%") == -EINVAL);
- assert_se(parse_permyriad("%1") == -EINVAL);
- assert_se(parse_permyriad("1%%") == -EINVAL);
- assert_se(parse_permyriad("3.212%") == -EINVAL);
-}
-
-static void test_parse_permyriad_unbounded(void) {
- assert_se(parse_permyriad_unbounded("1001‱") == 1001);
- assert_se(parse_permyriad_unbounded("4000‱") == 4000);
- assert_se(parse_permyriad_unbounded("2147483647‱") == 2147483647);
- assert_se(parse_permyriad_unbounded("2147483648‱") == -ERANGE);
- assert_se(parse_permyriad_unbounded("4294967295‱") == -ERANGE);
- assert_se(parse_permyriad_unbounded("4294967296‱") == -ERANGE);
-
- assert_se(parse_permyriad_unbounded("101‰") == 1010);
- assert_se(parse_permyriad_unbounded("400‰") == 4000);
- assert_se(parse_permyriad_unbounded("214748364.7‰") == 2147483647);
- assert_se(parse_permyriad_unbounded("214748364.8‰") == -ERANGE);
- assert_se(parse_permyriad_unbounded("429496729.5‰") == -ERANGE);
- assert_se(parse_permyriad_unbounded("429496729.6‰") == -ERANGE);
-
- assert_se(parse_permyriad_unbounded("99%") == 9900);
- assert_se(parse_permyriad_unbounded("40%") == 4000);
- assert_se(parse_permyriad_unbounded("21474836.47%") == 2147483647);
- assert_se(parse_permyriad_unbounded("21474836.48%") == -ERANGE);
- assert_se(parse_permyriad_unbounded("42949672.95%") == -ERANGE);
- assert_se(parse_permyriad_unbounded("42949672.96%") == -ERANGE);
-}
-
static void test_parse_nice(void) {
int n;
@@ -1049,12 +911,6 @@ int main(int argc, char *argv[]) {
test_safe_atoi64();
test_safe_atoux64();
test_safe_atod();
- test_parse_percent();
- test_parse_percent_unbounded();
- test_parse_permille();
- test_parse_permille_unbounded();
- test_parse_permyriad();
- test_parse_permyriad_unbounded();
test_parse_nice();
test_parse_dev();
test_parse_errno();
diff --git a/src/test/test-percent-util.c b/src/test/test-percent-util.c
new file mode 100644
index 0000000000..b8801438a7
--- /dev/null
+++ b/src/test/test-percent-util.c
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "percent-util.h"
+#include "tests.h"
+#include "time-util.h"
+
+static void test_parse_percent(void) {
+ assert_se(parse_percent("") == -EINVAL);
+ assert_se(parse_percent("foo") == -EINVAL);
+ assert_se(parse_percent("0") == -EINVAL);
+ assert_se(parse_percent("0.1") == -EINVAL);
+ assert_se(parse_percent("50") == -EINVAL);
+ assert_se(parse_percent("100") == -EINVAL);
+ assert_se(parse_percent("-1") == -EINVAL);
+ assert_se(parse_percent("0%") == 0);
+ assert_se(parse_percent("55%") == 55);
+ assert_se(parse_percent("100%") == 100);
+ assert_se(parse_percent("-7%") == -ERANGE);
+ assert_se(parse_percent("107%") == -ERANGE);
+ assert_se(parse_percent("%") == -EINVAL);
+ assert_se(parse_percent("%%") == -EINVAL);
+ assert_se(parse_percent("%1") == -EINVAL);
+ assert_se(parse_percent("1%%") == -EINVAL);
+ assert_se(parse_percent("3.2%") == -EINVAL);
+}
+
+static void test_parse_percent_unbounded(void) {
+ assert_se(parse_percent_unbounded("101%") == 101);
+ assert_se(parse_percent_unbounded("400%") == 400);
+}
+
+static void test_parse_permille(void) {
+ assert_se(parse_permille("") == -EINVAL);
+ assert_se(parse_permille("foo") == -EINVAL);
+ assert_se(parse_permille("0") == -EINVAL);
+ assert_se(parse_permille("50") == -EINVAL);
+ assert_se(parse_permille("100") == -EINVAL);
+ assert_se(parse_permille("-1") == -EINVAL);
+ assert_se(parse_permille("0.1") == -EINVAL);
+ assert_se(parse_permille("5%") == 50);
+ assert_se(parse_permille("5.5%") == 55);
+ assert_se(parse_permille("5.12%") == -EINVAL);
+
+ assert_se(parse_permille("0‰") == 0);
+ assert_se(parse_permille("555‰") == 555);
+ assert_se(parse_permille("1000‰") == 1000);
+ assert_se(parse_permille("-7‰") == -ERANGE);
+ assert_se(parse_permille("1007‰") == -ERANGE);
+ assert_se(parse_permille("‰") == -EINVAL);
+ assert_se(parse_permille("‰‰") == -EINVAL);
+ assert_se(parse_permille("‰1") == -EINVAL);
+ assert_se(parse_permille("1‰‰") == -EINVAL);
+ assert_se(parse_permille("3.2‰") == -EINVAL);
+ assert_se(parse_permille("0.1‰") == -EINVAL);
+
+ assert_se(parse_permille("0%") == 0);
+ assert_se(parse_permille("55%") == 550);
+ assert_se(parse_permille("55.5%") == 555);
+ assert_se(parse_permille("100%") == 1000);
+ assert_se(parse_permille("-7%") == -ERANGE);
+ assert_se(parse_permille("107%") == -ERANGE);
+ assert_se(parse_permille("%") == -EINVAL);
+ assert_se(parse_permille("%%") == -EINVAL);
+ assert_se(parse_permille("%1") == -EINVAL);
+ assert_se(parse_permille("1%%") == -EINVAL);
+ assert_se(parse_permille("3.21%") == -EINVAL);
+ assert_se(parse_permille("0.1%") == 1);
+}
+
+static void test_parse_permille_unbounded(void) {
+ assert_se(parse_permille_unbounded("1001‰") == 1001);
+ assert_se(parse_permille_unbounded("4000‰") == 4000);
+ assert_se(parse_permille_unbounded("2147483647‰") == 2147483647);
+ assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE);
+ assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE);
+ assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE);
+
+ assert_se(parse_permille_unbounded("101%") == 1010);
+ assert_se(parse_permille_unbounded("400%") == 4000);
+ assert_se(parse_permille_unbounded("214748364.7%") == 2147483647);
+ assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE);
+ assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE);
+ assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE);
+}
+
+static void test_parse_permyriad(void) {
+ assert_se(parse_permyriad("") == -EINVAL);
+ assert_se(parse_permyriad("foo") == -EINVAL);
+ assert_se(parse_permyriad("0") == -EINVAL);
+ assert_se(parse_permyriad("50") == -EINVAL);
+ assert_se(parse_permyriad("100") == -EINVAL);
+ assert_se(parse_permyriad("-1") == -EINVAL);
+
+ assert_se(parse_permyriad("0‱") == 0);
+ assert_se(parse_permyriad("555‱") == 555);
+ assert_se(parse_permyriad("1000‱") == 1000);
+ assert_se(parse_permyriad("-7‱") == -ERANGE);
+ assert_se(parse_permyriad("10007‱") == -ERANGE);
+ assert_se(parse_permyriad("‱") == -EINVAL);
+ assert_se(parse_permyriad("‱‱") == -EINVAL);
+ assert_se(parse_permyriad("‱1") == -EINVAL);
+ assert_se(parse_permyriad("1‱‱") == -EINVAL);
+ assert_se(parse_permyriad("3.2‱") == -EINVAL);
+
+ assert_se(parse_permyriad("0‰") == 0);
+ assert_se(parse_permyriad("555.5‰") == 5555);
+ assert_se(parse_permyriad("1000.0‰") == 10000);
+ assert_se(parse_permyriad("-7‰") == -ERANGE);
+ assert_se(parse_permyriad("1007‰") == -ERANGE);
+ assert_se(parse_permyriad("‰") == -EINVAL);
+ assert_se(parse_permyriad("‰‰") == -EINVAL);
+ assert_se(parse_permyriad("‰1") == -EINVAL);
+ assert_se(parse_permyriad("1‰‰") == -EINVAL);
+ assert_se(parse_permyriad("3.22‰") == -EINVAL);
+
+ assert_se(parse_permyriad("0%") == 0);
+ assert_se(parse_permyriad("55%") == 5500);
+ assert_se(parse_permyriad("55.5%") == 5550);
+ assert_se(parse_permyriad("55.50%") == 5550);
+ assert_se(parse_permyriad("55.53%") == 5553);
+ assert_se(parse_permyriad("100%") == 10000);
+ assert_se(parse_permyriad("-7%") == -ERANGE);
+ assert_se(parse_permyriad("107%") == -ERANGE);
+ assert_se(parse_permyriad("%") == -EINVAL);
+ assert_se(parse_permyriad("%%") == -EINVAL);
+ assert_se(parse_permyriad("%1") == -EINVAL);
+ assert_se(parse_permyriad("1%%") == -EINVAL);
+ assert_se(parse_permyriad("3.212%") == -EINVAL);
+}
+
+static void test_parse_permyriad_unbounded(void) {
+ assert_se(parse_permyriad_unbounded("1001‱") == 1001);
+ assert_se(parse_permyriad_unbounded("4000‱") == 4000);
+ assert_se(parse_permyriad_unbounded("2147483647‱") == 2147483647);
+ assert_se(parse_permyriad_unbounded("2147483648‱") == -ERANGE);
+ assert_se(parse_permyriad_unbounded("4294967295‱") == -ERANGE);
+ assert_se(parse_permyriad_unbounded("4294967296‱") == -ERANGE);
+
+ assert_se(parse_permyriad_unbounded("101‰") == 1010);
+ assert_se(parse_permyriad_unbounded("400‰") == 4000);
+ assert_se(parse_permyriad_unbounded("214748364.7‰") == 2147483647);
+ assert_se(parse_permyriad_unbounded("214748364.8‰") == -ERANGE);
+ assert_se(parse_permyriad_unbounded("429496729.5‰") == -ERANGE);
+ assert_se(parse_permyriad_unbounded("429496729.6‰") == -ERANGE);
+
+ assert_se(parse_permyriad_unbounded("99%") == 9900);
+ assert_se(parse_permyriad_unbounded("40%") == 4000);
+ assert_se(parse_permyriad_unbounded("21474836.47%") == 2147483647);
+ assert_se(parse_permyriad_unbounded("21474836.48%") == -ERANGE);
+ assert_se(parse_permyriad_unbounded("42949672.95%") == -ERANGE);
+ assert_se(parse_permyriad_unbounded("42949672.96%") == -ERANGE);
+}
+
+static void test_scale(void) {
+ /* Check some fixed values */
+ assert_se(UINT32_SCALE_FROM_PERCENT(0) == 0);
+ assert_se(UINT32_SCALE_FROM_PERCENT(50) == UINT32_MAX/2+1);
+ assert_se(UINT32_SCALE_FROM_PERCENT(100) == UINT32_MAX);
+
+ assert_se(UINT32_SCALE_FROM_PERMILLE(0) == 0);
+ assert_se(UINT32_SCALE_FROM_PERMILLE(500) == UINT32_MAX/2+1);
+ assert_se(UINT32_SCALE_FROM_PERMILLE(1000) == UINT32_MAX);
+
+ assert_se(UINT32_SCALE_FROM_PERMYRIAD(0) == 0);
+ assert_se(UINT32_SCALE_FROM_PERMYRIAD(5000) == UINT32_MAX/2+1);
+ assert_se(UINT32_SCALE_FROM_PERMYRIAD(10000) == UINT32_MAX);
+
+ /* Make sure there's no numeric noise on the 0%…100% scale when converting from percent and back. */
+ for (int percent = 0; percent <= 100; percent++) {
+ log_debug("%i%% → %" PRIu32 " → %i%%",
+ percent,
+ UINT32_SCALE_FROM_PERCENT(percent),
+ UINT32_SCALE_TO_PERCENT(UINT32_SCALE_FROM_PERCENT(percent)));
+
+ assert_se(UINT32_SCALE_TO_PERCENT(UINT32_SCALE_FROM_PERCENT(percent)) == percent);
+ }
+
+ /* Make sure there's no numeric noise on the 0‰…1000‰ scale when converting from permille and back. */
+ for (int permille = 0; permille <= 1000; permille++) {
+ log_debug("%i‰ → %" PRIu32 " → %i‰",
+ permille,
+ UINT32_SCALE_FROM_PERMILLE(permille),
+ UINT32_SCALE_TO_PERMILLE(UINT32_SCALE_FROM_PERMILLE(permille)));
+
+ assert_se(UINT32_SCALE_TO_PERMILLE(UINT32_SCALE_FROM_PERMILLE(permille)) == permille);
+ }
+
+ /* Make sure there's no numeric noise on the 0‱…10000‱ scale when converting from permyriad and back. */
+ for (int permyriad = 0; permyriad <= 10000; permyriad++) {
+ log_debug("%i‱ → %" PRIu32 " → %i‱",
+ permyriad,
+ UINT32_SCALE_FROM_PERMYRIAD(permyriad),
+ UINT32_SCALE_TO_PERMYRIAD(UINT32_SCALE_FROM_PERMYRIAD(permyriad)));
+
+ assert_se(UINT32_SCALE_TO_PERMYRIAD(UINT32_SCALE_FROM_PERMYRIAD(permyriad)) == permyriad);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_DEBUG);
+
+ test_parse_percent();
+ test_parse_percent_unbounded();
+ test_parse_permille();
+ test_parse_permille_unbounded();
+ test_parse_permyriad();
+ test_parse_permyriad_unbounded();
+ test_scale();
+
+ return 0;
+}