From eefc66aa8f77c96a13a78d6c40c79ed7f3d6dc9d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Mar 2019 11:35:47 +0100 Subject: [PATCH] util: split out some stuff into a new file limits-util.[ch] --- src/basic/limits-util.c | 156 +++++++++++++++++++++++++++++++++++++++ src/basic/limits-util.h | 10 +++ src/basic/meson.build | 2 + src/basic/util.c | 148 ------------------------------------- src/basic/util.h | 6 -- src/core/dbus-cgroup.c | 1 + src/core/load-fragment.c | 1 + src/core/main.c | 1 + src/login/logind-core.c | 1 + src/login/logind-user.c | 1 + src/test/test-util.c | 1 + src/udev/udevd.c | 1 + 12 files changed, 175 insertions(+), 154 deletions(-) create mode 100644 src/basic/limits-util.c create mode 100644 src/basic/limits-util.h diff --git a/src/basic/limits-util.c b/src/basic/limits-util.c new file mode 100644 index 0000000000..0cd59f97ac --- /dev/null +++ b/src/basic/limits-util.c @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "alloc-util.h" +#include "cgroup-util.h" +#include "limits-util.h" +#include "parse-util.h" +#include "process-util.h" +#include "procfs-util.h" +#include "string-util.h" + +uint64_t physical_memory(void) { + _cleanup_free_ char *root = NULL, *value = NULL; + uint64_t mem, lim; + size_t ps; + long sc; + int r; + + /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of + * memory. + * + * In order to support containers nicely that have a configured memory limit we'll take the minimum of the + * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */ + + sc = sysconf(_SC_PHYS_PAGES); + assert(sc > 0); + + ps = page_size(); + mem = (uint64_t) sc * (uint64_t) ps; + + r = cg_get_root_path(&root); + if (r < 0) { + log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m"); + return mem; + } + + r = cg_all_unified(); + if (r < 0) { + log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m"); + return mem; + } + if (r > 0) { + r = cg_get_attribute("memory", root, "memory.max", &value); + if (r < 0) { + log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m"); + return mem; + } + + if (streq(value, "max")) + return mem; + } else { + r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value); + if (r < 0) { + log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m"); + return mem; + } + } + + r = safe_atou64(value, &lim); + if (r < 0) { + log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value); + return mem; + } + if (lim == UINT64_MAX) + return mem; + + /* Make sure the limit is a multiple of our own page size */ + lim /= ps; + lim *= ps; + + return MIN(mem, lim); +} + +uint64_t physical_memory_scale(uint64_t v, uint64_t max) { + uint64_t p, m, ps, r; + + assert(max > 0); + + /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success + * the result is a multiple of the page size (rounds down). */ + + ps = page_size(); + assert(ps > 0); + + p = physical_memory() / ps; + assert(p > 0); + + m = p * v; + if (m / p != v) + return UINT64_MAX; + + m /= max; + + r = m * ps; + if (r / ps != m) + return UINT64_MAX; + + return r; +} + +uint64_t system_tasks_max(void) { + + uint64_t a = TASKS_MAX, b = TASKS_MAX; + _cleanup_free_ char *root = NULL; + int r; + + /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this + * limit: + * + * a) the maximum tasks value the kernel allows on this architecture + * b) the cgroups pids_max attribute for the system + * c) the kernel's configured maximum PID value + * + * And then pick the smallest of the three */ + + r = procfs_tasks_get_limit(&a); + if (r < 0) + log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m"); + + r = cg_get_root_path(&root); + if (r < 0) + log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m"); + else { + _cleanup_free_ char *value = NULL; + + r = cg_get_attribute("pids", root, "pids.max", &value); + if (r < 0) + log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m"); + else if (!streq(value, "max")) { + r = safe_atou64(value, &b); + if (r < 0) + log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m"); + } + } + + return MIN3(TASKS_MAX, + a <= 0 ? TASKS_MAX : a, + b <= 0 ? TASKS_MAX : b); +} + +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { + uint64_t t, m; + + assert(max > 0); + + /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages + * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ + + t = system_tasks_max(); + assert(t > 0); + + m = t * v; + if (m / t != v) /* overflow? */ + return UINT64_MAX; + + return m / max; +} diff --git a/src/basic/limits-util.h b/src/basic/limits-util.h new file mode 100644 index 0000000000..77895cbad4 --- /dev/null +++ b/src/basic/limits-util.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include + +uint64_t physical_memory(void); +uint64_t physical_memory_scale(uint64_t v, uint64_t max); + +uint64_t system_tasks_max(void); +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); diff --git a/src/basic/meson.build b/src/basic/meson.build index 4cfd3c861d..f7556b4198 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -79,6 +79,8 @@ basic_sources = files(''' khash.h label.c label.h + limits-util.c + limits-util.h list.h locale-util.c locale-util.h diff --git a/src/basic/util.c b/src/basic/util.c index 6f68bc404e..b275570618 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -19,7 +19,6 @@ #include "alloc-util.h" #include "btrfs-util.h" #include "build.h" -#include "cgroup-util.h" #include "def.h" #include "device-nodes.h" #include "dirent-util.h" @@ -294,153 +293,6 @@ int container_get_leader(const char *machine, pid_t *pid) { return 0; } -uint64_t physical_memory(void) { - _cleanup_free_ char *root = NULL, *value = NULL; - uint64_t mem, lim; - size_t ps; - long sc; - int r; - - /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of - * memory. - * - * In order to support containers nicely that have a configured memory limit we'll take the minimum of the - * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */ - - sc = sysconf(_SC_PHYS_PAGES); - assert(sc > 0); - - ps = page_size(); - mem = (uint64_t) sc * (uint64_t) ps; - - r = cg_get_root_path(&root); - if (r < 0) { - log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m"); - return mem; - } - - r = cg_all_unified(); - if (r < 0) { - log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m"); - return mem; - } - if (r > 0) { - r = cg_get_attribute("memory", root, "memory.max", &value); - if (r < 0) { - log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m"); - return mem; - } - - if (streq(value, "max")) - return mem; - } else { - r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value); - if (r < 0) { - log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m"); - return mem; - } - } - - r = safe_atou64(value, &lim); - if (r < 0) { - log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value); - return mem; - } - if (lim == UINT64_MAX) - return mem; - - /* Make sure the limit is a multiple of our own page size */ - lim /= ps; - lim *= ps; - - return MIN(mem, lim); -} - -uint64_t physical_memory_scale(uint64_t v, uint64_t max) { - uint64_t p, m, ps, r; - - assert(max > 0); - - /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success - * the result is a multiple of the page size (rounds down). */ - - ps = page_size(); - assert(ps > 0); - - p = physical_memory() / ps; - assert(p > 0); - - m = p * v; - if (m / p != v) - return UINT64_MAX; - - m /= max; - - r = m * ps; - if (r / ps != m) - return UINT64_MAX; - - return r; -} - -uint64_t system_tasks_max(void) { - - uint64_t a = TASKS_MAX, b = TASKS_MAX; - _cleanup_free_ char *root = NULL; - int r; - - /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this - * limit: - * - * a) the maximum tasks value the kernel allows on this architecture - * b) the cgroups pids_max attribute for the system - * c) the kernel's configured maximum PID value - * - * And then pick the smallest of the three */ - - r = procfs_tasks_get_limit(&a); - if (r < 0) - log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m"); - - r = cg_get_root_path(&root); - if (r < 0) - log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m"); - else { - _cleanup_free_ char *value = NULL; - - r = cg_get_attribute("pids", root, "pids.max", &value); - if (r < 0) - log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m"); - else if (!streq(value, "max")) { - r = safe_atou64(value, &b); - if (r < 0) - log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m"); - } - } - - return MIN3(TASKS_MAX, - a <= 0 ? TASKS_MAX : a, - b <= 0 ? TASKS_MAX : b); -} - -uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { - uint64_t t, m; - - assert(max > 0); - - /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages - * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ - - t = system_tasks_max(); - assert(t > 0); - - m = t * v; - if (m / t != v) /* overflow? */ - return UINT64_MAX; - - return m / max; -} - int version(void) { puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n" SYSTEMD_FEATURES); diff --git a/src/basic/util.h b/src/basic/util.h index 82851e910c..dd0f6e5cc8 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -237,12 +237,6 @@ static inline unsigned log2u_round_up(unsigned x) { int container_get_leader(const char *machine, pid_t *pid); -uint64_t physical_memory(void); -uint64_t physical_memory_scale(uint64_t v, uint64_t max); - -uint64_t system_tasks_max(void); -uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); - int version(void); int str_verscmp(const char *s1, const char *s2); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 7ab53a1c2a..4615aeaf66 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -13,6 +13,7 @@ #include "dbus-util.h" #include "fd-util.h" #include "fileio.h" +#include "limits-util.h" #include "path-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 084c61d982..805bdbca9b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -36,6 +36,7 @@ #include "ioprio.h" #include "ip-protocol-list.h" #include "journal-util.h" +#include "limits-util.h" #include "load-fragment.h" #include "log.h" #include "missing.h" diff --git a/src/core/main.c b/src/core/main.c index 47a976ad0f..c0fa33bab4 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -47,6 +47,7 @@ #include "ima-setup.h" #include "killall.h" #include "kmod-setup.h" +#include "limits-util.h" #include "load-fragment.h" #include "log.h" #include "loopback-setup.h" diff --git a/src/login/logind-core.c b/src/login/logind-core.c index f3d8de4f14..2467da18ee 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -18,6 +18,7 @@ #include "conf-parser.h" #include "device-util.h" #include "fd-util.h" +#include "limits-util.h" #include "logind.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 2b327cbe19..045b6f0e17 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -19,6 +19,7 @@ #include "fs-util.h" #include "hashmap.h" #include "label.h" +#include "limits-util.h" #include "logind-user.h" #include "mkdir.h" #include "parse-util.h" diff --git a/src/test/test-util.c b/src/test/test-util.c index ffacd65669..056708650d 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -8,6 +8,7 @@ #include "def.h" #include "fileio.h" #include "fs-util.h" +#include "limits-util.h" #include "missing_syscall.h" #include "parse-util.h" #include "process-util.h" diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 0da82dca55..eab2b46250 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -46,6 +46,7 @@ #include "hashmap.h" #include "io-util.h" #include "libudev-device-internal.h" +#include "limits-util.h" #include "list.h" #include "main-func.h" #include "mkdir.h"