]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/numa-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "alloc-util.h"
7 #include "cpu-set-util.h"
8 #include "dirent-util.h"
12 #include "missing_syscall.h"
13 #include "numa-util.h"
14 #include "stdio-util.h"
15 #include "string-table.h"
17 bool numa_policy_is_valid(const NUMAPolicy
*policy
) {
20 if (!mpol_is_valid(numa_policy_get_type(policy
)))
23 if (!policy
->nodes
.set
&&
24 !IN_SET(numa_policy_get_type(policy
), MPOL_DEFAULT
, MPOL_LOCAL
, MPOL_PREFERRED
))
27 if (policy
->nodes
.set
&&
28 numa_policy_get_type(policy
) == MPOL_PREFERRED
&&
29 CPU_COUNT_S(policy
->nodes
.allocated
, policy
->nodes
.set
) != 1)
35 static int numa_policy_to_mempolicy(const NUMAPolicy
*policy
, unsigned long *ret_maxnode
, unsigned long **ret_nodes
) {
36 unsigned node
, bits
= 0, ulong_bits
;
37 _cleanup_free_
unsigned long *out
= NULL
;
43 if (IN_SET(numa_policy_get_type(policy
), MPOL_DEFAULT
, MPOL_LOCAL
) ||
44 (numa_policy_get_type(policy
) == MPOL_PREFERRED
&& !policy
->nodes
.set
)) {
50 bits
= policy
->nodes
.allocated
* 8;
51 ulong_bits
= sizeof(unsigned long) * 8;
53 out
= new0(unsigned long, DIV_ROUND_UP(policy
->nodes
.allocated
, sizeof(unsigned long)));
57 /* We don't make any assumptions about internal type libc is using to store NUMA node mask.
58 Hence we need to convert the node mask to the representation expected by set_mempolicy() */
59 for (node
= 0; node
< bits
; node
++)
60 if (CPU_ISSET_S(node
, policy
->nodes
.allocated
, policy
->nodes
.set
))
61 out
[node
/ ulong_bits
] |= 1ul << (node
% ulong_bits
);
63 *ret_nodes
= TAKE_PTR(out
);
64 *ret_maxnode
= bits
+ 1;
68 int apply_numa_policy(const NUMAPolicy
*policy
) {
70 _cleanup_free_
unsigned long *nodes
= NULL
;
71 unsigned long maxnode
;
75 if (get_mempolicy(NULL
, NULL
, 0, 0, 0) < 0 && errno
== ENOSYS
)
78 if (!numa_policy_is_valid(policy
))
81 r
= numa_policy_to_mempolicy(policy
, &maxnode
, &nodes
);
85 r
= set_mempolicy(numa_policy_get_type(policy
), nodes
, maxnode
);
92 int numa_to_cpu_set(const NUMAPolicy
*policy
, CPUSet
*ret
) {
95 _cleanup_(cpu_set_reset
) CPUSet s
= {};
100 for (i
= 0; i
< policy
->nodes
.allocated
* 8; i
++) {
101 _cleanup_free_
char *l
= NULL
;
102 char p
[STRLEN("/sys/devices/system/node/node//cpulist") + DECIMAL_STR_MAX(size_t) + 1];
103 _cleanup_(cpu_set_reset
) CPUSet part
= {};
105 if (!CPU_ISSET_S(i
, policy
->nodes
.allocated
, policy
->nodes
.set
))
108 xsprintf(p
, "/sys/devices/system/node/node%zu/cpulist", i
);
110 r
= read_one_line_file(p
, &l
);
114 r
= parse_cpu_set(l
, &part
);
118 r
= cpu_set_add_all(&s
, &part
);
129 static int numa_max_node(void) {
130 _cleanup_closedir_
DIR *d
= NULL
;
134 d
= opendir("/sys/devices/system/node");
138 FOREACH_DIRENT(de
, d
, break) {
142 (void) dirent_ensure_type(d
, de
);
144 if (de
->d_type
!= DT_DIR
)
147 n
= startswith(de
->d_name
, "node");
151 r
= safe_atoi(n
, &node
);
162 int numa_mask_add_all(CPUSet
*mask
) {
169 log_debug_errno(m
, "Failed to determine maximum NUMA node index, assuming 1023: %m");
170 m
= 1023; /* CONFIG_NODES_SHIFT is set to 10 on x86_64, i.e. 1024 NUMA nodes in total */
173 for (int i
= 0; i
<= m
; i
++) {
176 r
= cpu_set_add(mask
, i
);
184 static const char* const mpol_table
[] = {
185 [MPOL_DEFAULT
] = "default",
186 [MPOL_PREFERRED
] = "preferred",
187 [MPOL_BIND
] = "bind",
188 [MPOL_INTERLEAVE
] = "interleave",
189 [MPOL_LOCAL
] = "local",
192 DEFINE_STRING_TABLE_LOOKUP(mpol
, int);