<listitem><para>Controls the NUMA node list which will be applied alongside with selected NUMA policy.
Takes a list of NUMA nodes and has the same syntax as a list of CPUs for <varname>CPUAffinity=</varname>
- option. Note that the list of NUMA nodes is not required for <option>default</option> and <option>local</option>
+ option or special "all" value which will include all available NUMA nodes in the mask. Note that the list
+ of NUMA nodes is not required for <option>default</option> and <option>local</option>
policies and for <option>preferred</option> policy we expect a single NUMA node.</para></listitem>
</varlistentry>
assert(rvalue);
assert(data);
- r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
- return 0;
+ if (streq(rvalue, "all")) {
+ r = numa_mask_add_all(&p->nodes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to create NUMA mask representing \"all\" NUMA nodes, ignoring: %m");
+ return 0;
+ }
+ } else {
+ r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
+ return 0;
+ }
}
return r;
_cleanup_free_ uint8_t *array = NULL;
size_t allocated;
- r = parse_cpu_set(eq, &nodes);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ if (eq && streq(eq, "all")) {
+ r = numa_mask_add_all(&nodes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
+ } else {
+ r = parse_cpu_set(eq, &nodes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ }
r = cpu_set_to_dbus(&nodes, &array, &allocated);
if (r < 0)
return 0;
}
-static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) {
+int cpu_set_add(CPUSet *cpu_set, unsigned cpu) {
int r;
if (cpu >= 8192)
}
int cpu_set_add_all(CPUSet *a, const CPUSet *b);
+int cpu_set_add(CPUSet *a, unsigned cpu);
char* cpu_set_to_string(const CPUSet *a);
char *cpu_set_to_range_string(const CPUSet *a);
#include "alloc-util.h"
#include "cpu-set-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "fileio.h"
#include "macro.h"
#include "missing_syscall.h"
return 0;
}
+static int numa_max_node(void) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r, max_node = 0;
+
+ d = opendir("/sys/devices/system/node");
+ if (!d)
+ return -errno;
+
+ FOREACH_DIRENT(de, d, break) {
+ int node;
+ const char *n;
+
+ (void) dirent_ensure_type(d, de);
+
+ if (de->d_type != DT_DIR)
+ continue;
+
+ n = startswith(de->d_name, "node");
+ if (!n)
+ continue;
+
+ r = safe_atoi(n, &node);
+ if (r < 0)
+ continue;
+
+ if (node > max_node)
+ max_node = node;
+ }
+
+ return max_node;
+}
+
+int numa_mask_add_all(CPUSet *mask) {
+ int m;
+
+ assert(mask);
+
+ m = numa_max_node();
+ if (m < 0) {
+ log_debug_errno(m, "Failed to determine maximum NUMA node index, assuming 1023: %m");
+ m = 1023; /* CONFIG_NODES_SHIFT is set to 10 on x86_64, i.e. 1024 NUMA nodes in total */
+ }
+
+ for (int i = 0; i <= m; i++) {
+ int r;
+
+ r = cpu_set_add(mask, i);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const mpol_table[] = {
[MPOL_DEFAULT] = "default",
[MPOL_PREFERRED] = "preferred",
int apply_numa_policy(const NUMAPolicy *policy);
int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *set);
+int numa_mask_add_all(CPUSet *mask);
+
const char* mpol_to_string(int i) _const_;
int mpol_from_string(const char *s) _pure_;