diff options
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/parse-util.c | 19 | ||||
-rw-r--r-- | src/basic/parse-util.h | 2 | ||||
-rw-r--r-- | src/basic/util.c | 62 | ||||
-rw-r--r-- | src/basic/util.h | 1 |
4 files changed, 78 insertions, 6 deletions
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 6c11b605a9..503a895731 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -532,3 +532,22 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } + +int parse_percent(const char *p) { + const char *pc, *n; + unsigned v; + int r; + + pc = endswith(p, "%"); + if (!pc) + return -EINVAL; + + n = strndupa(p, pc - p); + r = safe_atou(n, &v); + if (r < 0) + return r; + if (v > 100) + return -ERANGE; + + return (int) v; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 7dc579a159..73441bb6fd 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -105,3 +105,5 @@ static inline int safe_atozu(const char *s, size_t *ret_u) { 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(const char *p); diff --git a/src/basic/util.c b/src/basic/util.c index f2f92fb3b7..09d16697b7 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -36,6 +36,7 @@ #include "alloc-util.h" #include "build.h" +#include "cgroup-util.h" #include "def.h" #include "dirent-util.h" #include "fd-util.h" @@ -771,15 +772,64 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int } uint64_t physical_memory(void) { - long mem; + _cleanup_free_ char *root = NULL, *value = NULL; + uint64_t mem, lim; + size_t ps; + long sc; - /* We return this as uint64_t in case we are running as 32bit - * process on a 64bit kernel with huge amounts of memory */ + /* 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; + + if (cg_get_root_path(&root) < 0) + return mem; + + if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value)) + return mem; + + if (safe_atou64(value, &lim) < 0) + 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; - mem = sysconf(_SC_PHYS_PAGES); - assert(mem > 0); + r = m * ps; + if (r / ps != m) + return UINT64_MAX; - return (uint64_t) mem * (uint64_t) page_size(); + return r; } int update_reboot_parameter_and_warn(const char *param) { diff --git a/src/basic/util.h b/src/basic/util.h index 9e6df19ef1..db105197e8 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -184,6 +184,7 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); uint64_t physical_memory(void); +uint64_t physical_memory_scale(uint64_t v, uint64_t max); int update_reboot_parameter_and_warn(const char *param); |