1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* Copyright (C) 2020, Google LLC. */ 3 4 #ifndef SELFTEST_KVM_NUMAIF_H 5 #define SELFTEST_KVM_NUMAIF_H 6 7 #include <dirent.h> 8 9 #include <linux/mempolicy.h> 10 11 #include "kvm_syscalls.h" 12 13 KVM_SYSCALL_DEFINE(get_mempolicy, 5, int *, policy, const unsigned long *, nmask, 14 unsigned long, maxnode, void *, addr, int, flags); 15 16 KVM_SYSCALL_DEFINE(set_mempolicy, 3, int, mode, const unsigned long *, nmask, 17 unsigned long, maxnode); 18 19 KVM_SYSCALL_DEFINE(set_mempolicy_home_node, 4, unsigned long, start, 20 unsigned long, len, unsigned long, home_node, 21 unsigned long, flags); 22 23 KVM_SYSCALL_DEFINE(migrate_pages, 4, int, pid, unsigned long, maxnode, 24 const unsigned long *, frommask, const unsigned long *, tomask); 25 26 KVM_SYSCALL_DEFINE(move_pages, 6, int, pid, unsigned long, count, void *, pages, 27 const int *, nodes, int *, status, int, flags); 28 29 KVM_SYSCALL_DEFINE(mbind, 6, void *, addr, unsigned long, size, int, mode, 30 const unsigned long *, nodemask, unsigned long, maxnode, 31 unsigned int, flags); 32 33 static inline int get_max_numa_node(void) 34 { 35 struct dirent *de; 36 int max_node = 0; 37 DIR *d; 38 39 /* 40 * Assume there's a single node if the kernel doesn't support NUMA, 41 * or if no nodes are found. 42 */ 43 d = opendir("/sys/devices/system/node"); 44 if (!d) 45 return 0; 46 47 while ((de = readdir(d)) != NULL) { 48 int node_id; 49 char *endptr; 50 51 if (strncmp(de->d_name, "node", 4) != 0) 52 continue; 53 54 node_id = strtol(de->d_name + 4, &endptr, 10); 55 if (*endptr != '\0') 56 continue; 57 58 if (node_id > max_node) 59 max_node = node_id; 60 } 61 closedir(d); 62 63 return max_node; 64 } 65 66 static bool is_numa_available(void) 67 { 68 /* 69 * Probe for NUMA by doing a dummy get_mempolicy(). If the syscall 70 * fails with ENOSYS, then the kernel was built without NUMA support. 71 * if the syscall fails with EPERM, then the process/user lacks the 72 * necessary capabilities (CAP_SYS_NICE). 73 */ 74 return !get_mempolicy(NULL, NULL, 0, NULL, 0) || 75 (errno != ENOSYS && errno != EPERM); 76 } 77 78 static inline bool is_multi_numa_node_system(void) 79 { 80 return is_numa_available() && get_max_numa_node() >= 1; 81 } 82 83 #endif /* SELFTEST_KVM_NUMAIF_H */ 84