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