]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/numa-util.c
update TODO
[thirdparty/systemd.git] / src / shared / numa-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <sched.h>
5
6 #include "alloc-util.h"
7 #include "cpu-set-util.h"
8 #include "fileio.h"
9 #include "macro.h"
10 #include "missing_syscall.h"
11 #include "numa-util.h"
12 #include "stdio-util.h"
13 #include "string-table.h"
14
15 bool numa_policy_is_valid(const NUMAPolicy *policy) {
16 assert(policy);
17
18 if (!mpol_is_valid(numa_policy_get_type(policy)))
19 return false;
20
21 if (!policy->nodes.set &&
22 !IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED))
23 return false;
24
25 if (policy->nodes.set &&
26 numa_policy_get_type(policy) == MPOL_PREFERRED &&
27 CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1)
28 return false;
29
30 return true;
31 }
32
33 static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) {
34 unsigned node, bits = 0, ulong_bits;
35 _cleanup_free_ unsigned long *out = NULL;
36
37 assert(policy);
38 assert(ret_maxnode);
39 assert(ret_nodes);
40
41 if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) ||
42 (numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) {
43 *ret_nodes = NULL;
44 *ret_maxnode = 0;
45 return 0;
46 }
47
48 bits = policy->nodes.allocated * 8;
49 ulong_bits = sizeof(unsigned long) * 8;
50
51 out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)));
52 if (!out)
53 return -ENOMEM;
54
55 /* We don't make any assumptions about internal type libc is using to store NUMA node mask.
56 Hence we need to convert the node mask to the representation expected by set_mempolicy() */
57 for (node = 0; node < bits; node++)
58 if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set))
59 out[node / ulong_bits] |= 1ul << (node % ulong_bits);
60
61 *ret_nodes = TAKE_PTR(out);
62 *ret_maxnode = bits + 1;
63 return 0;
64 }
65
66 int apply_numa_policy(const NUMAPolicy *policy) {
67 int r;
68 _cleanup_free_ unsigned long *nodes = NULL;
69 unsigned long maxnode;
70
71 assert(policy);
72
73 if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
74 return -EOPNOTSUPP;
75
76 if (!numa_policy_is_valid(policy))
77 return -EINVAL;
78
79 r = numa_policy_to_mempolicy(policy, &maxnode, &nodes);
80 if (r < 0)
81 return r;
82
83 r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode);
84 if (r < 0)
85 return -errno;
86
87 return 0;
88 }
89
90 int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret) {
91 int r;
92 size_t i;
93 _cleanup_(cpu_set_reset) CPUSet s = {};
94
95 assert(policy);
96 assert(ret);
97
98 for (i = 0; i < policy->nodes.allocated * 8; i++) {
99 _cleanup_free_ char *l = NULL;
100 char p[STRLEN("/sys/devices/system/node/node//cpulist") + DECIMAL_STR_MAX(size_t) + 1];
101 _cleanup_(cpu_set_reset) CPUSet part = {};
102
103 if (!CPU_ISSET_S(i, policy->nodes.allocated, policy->nodes.set))
104 continue;
105
106 xsprintf(p, "/sys/devices/system/node/node%zu/cpulist", i);
107
108 r = read_one_line_file(p, &l);
109 if (r < 0)
110 return r;
111
112 r = parse_cpu_set(l, &part);
113 if (r < 0)
114 return r;
115
116 r = cpu_set_add_all(&s, &part);
117 if (r < 0)
118 return r;
119 }
120
121 *ret = s;
122 s = (CPUSet) {};
123
124 return 0;
125 }
126
127 static const char* const mpol_table[] = {
128 [MPOL_DEFAULT] = "default",
129 [MPOL_PREFERRED] = "preferred",
130 [MPOL_BIND] = "bind",
131 [MPOL_INTERLEAVE] = "interleave",
132 [MPOL_LOCAL] = "local",
133 };
134
135 DEFINE_STRING_TABLE_LOOKUP(mpol, int);