]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/limits-util.c
0cd59f97acfbf8f9260667a3c1a6400a82c050e5
[thirdparty/systemd.git] / src / basic / limits-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "alloc-util.h"
4 #include "cgroup-util.h"
5 #include "limits-util.h"
6 #include "parse-util.h"
7 #include "process-util.h"
8 #include "procfs-util.h"
9 #include "string-util.h"
10
11 uint64_t physical_memory(void) {
12 _cleanup_free_ char *root = NULL, *value = NULL;
13 uint64_t mem, lim;
14 size_t ps;
15 long sc;
16 int r;
17
18 /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
19 * memory.
20 *
21 * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
22 * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
23
24 sc = sysconf(_SC_PHYS_PAGES);
25 assert(sc > 0);
26
27 ps = page_size();
28 mem = (uint64_t) sc * (uint64_t) ps;
29
30 r = cg_get_root_path(&root);
31 if (r < 0) {
32 log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
33 return mem;
34 }
35
36 r = cg_all_unified();
37 if (r < 0) {
38 log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
39 return mem;
40 }
41 if (r > 0) {
42 r = cg_get_attribute("memory", root, "memory.max", &value);
43 if (r < 0) {
44 log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
45 return mem;
46 }
47
48 if (streq(value, "max"))
49 return mem;
50 } else {
51 r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
52 if (r < 0) {
53 log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
54 return mem;
55 }
56 }
57
58 r = safe_atou64(value, &lim);
59 if (r < 0) {
60 log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
61 return mem;
62 }
63 if (lim == UINT64_MAX)
64 return mem;
65
66 /* Make sure the limit is a multiple of our own page size */
67 lim /= ps;
68 lim *= ps;
69
70 return MIN(mem, lim);
71 }
72
73 uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
74 uint64_t p, m, ps, r;
75
76 assert(max > 0);
77
78 /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
79 * the result is a multiple of the page size (rounds down). */
80
81 ps = page_size();
82 assert(ps > 0);
83
84 p = physical_memory() / ps;
85 assert(p > 0);
86
87 m = p * v;
88 if (m / p != v)
89 return UINT64_MAX;
90
91 m /= max;
92
93 r = m * ps;
94 if (r / ps != m)
95 return UINT64_MAX;
96
97 return r;
98 }
99
100 uint64_t system_tasks_max(void) {
101
102 uint64_t a = TASKS_MAX, b = TASKS_MAX;
103 _cleanup_free_ char *root = NULL;
104 int r;
105
106 /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
107 * limit:
108 *
109 * a) the maximum tasks value the kernel allows on this architecture
110 * b) the cgroups pids_max attribute for the system
111 * c) the kernel's configured maximum PID value
112 *
113 * And then pick the smallest of the three */
114
115 r = procfs_tasks_get_limit(&a);
116 if (r < 0)
117 log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
118
119 r = cg_get_root_path(&root);
120 if (r < 0)
121 log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
122 else {
123 _cleanup_free_ char *value = NULL;
124
125 r = cg_get_attribute("pids", root, "pids.max", &value);
126 if (r < 0)
127 log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
128 else if (!streq(value, "max")) {
129 r = safe_atou64(value, &b);
130 if (r < 0)
131 log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
132 }
133 }
134
135 return MIN3(TASKS_MAX,
136 a <= 0 ? TASKS_MAX : a,
137 b <= 0 ? TASKS_MAX : b);
138 }
139
140 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
141 uint64_t t, m;
142
143 assert(max > 0);
144
145 /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
146 * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
147
148 t = system_tasks_max();
149 assert(t > 0);
150
151 m = t * v;
152 if (m / t != v) /* overflow? */
153 return UINT64_MAX;
154
155 return m / max;
156 }