diff --git a/testcases/kernel/syscalls/numa/lib/numa_helper.c b/testcases/kernel/syscalls/numa/lib/numa_helper.c index d50cb41..aa98522 100644 --- a/testcases/kernel/syscalls/numa/lib/numa_helper.c +++ b/testcases/kernel/syscalls/numa/lib/numa_helper.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -36,26 +37,10 @@ #include "numa_helper.h" #include "linux_syscall_numbers.h" -/* - * get_allowed_nodes_arr - get number and array of available nodes - * @num_allowed_nodes: pointer where number of available nodes will be stored - * @allowed_nodes: array of available node ids, this is MPOL_F_MEMS_ALLOWED - * node bitmask compacted (without holes), so that each field - * contains node number. If NULL only num_allowed_nodes is - * returned, otherwise it cotains new allocated array, - * which caller is responsible to free. - * RETURNS: - * 0 on success - * -1 on allocation failure - * -2 on get_mempolicy failure - */ -int get_allowed_nodes_arr(int *num_allowed_nodes, int **allowed_nodes) -{ #if HAVE_NUMA_H - int i; - nodemask_t *allowed_nodemask = NULL; - unsigned long max_node; - +static unsigned long get_max_node() +{ + unsigned long max_node = 0; #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2 max_node = NUMA_NUM_NODES; /* @@ -68,61 +53,150 @@ int get_allowed_nodes_arr(int *num_allowed_nodes, int **allowed_nodes) #else max_node = numa_max_possible_node() + 1; #endif -#endif /* HAVE_NUMA_H */ + return max_node; +} - *num_allowed_nodes = 0; - if (allowed_nodes) - *allowed_nodes = NULL; +static void get_nodemask_allnodes(nodemask_t *nodemask, + unsigned long max_node) +{ + unsigned long nodemask_size = max_node/8+1; + int i; + char fn[64]; + struct stat st; -#if HAVE_NUMA_H - allowed_nodemask = malloc(max_node/8+1); - if (allowed_nodemask == NULL) - return -1; - nodemask_zero(allowed_nodemask); - - if (allowed_nodes) { - *allowed_nodes = malloc(sizeof(int)*max_node); - if (*allowed_nodes == NULL) { - free(allowed_nodemask); - return -1; - } + memset(nodemask, 0, nodemask_size); + for (i = 0; i < max_node; i++) { + sprintf(fn, "/sys/devices/system/node/node%d", i); + if (stat(fn, &st) == 0) + nodemask_set(nodemask, i); } +} +static int filter_nodemask_mem(nodemask_t *nodemask, unsigned long max_node) +{ #if MPOL_F_MEMS_ALLOWED + unsigned long nodemask_size = max_node/8+1; + memset(nodemask, 0, nodemask_size); /* * avoid numa_get_mems_allowed(), because of bug in getpol() * utility function in older versions: * http://www.spinics.net/lists/linux-numa/msg00849.html */ - if (syscall(__NR_get_mempolicy, NULL, allowed_nodemask->n, - max_node, 0, MPOL_F_MEMS_ALLOWED) < 0) { - free(allowed_nodemask); - if (allowed_nodes) { - free(*allowed_nodes); - *allowed_nodes = NULL; - } + if (syscall(__NR_get_mempolicy, NULL, nodemask->n, + max_node, 0, MPOL_F_MEMS_ALLOWED) < 0) return -2; - } #else + int i; /* * old libnuma/kernel don't have MPOL_F_MEMS_ALLOWED, so let's assume * that we can use any node with memory > 0 */ - for (i = 0; i < max_node; i++) - if (numa_node_size64(i, NULL) > 0) - nodemask_set(allowed_nodemask, i); - + for (i = 0; i < max_node; i++) { + if (!nodemask_isset(nodemask, i)) + continue; + if (numa_node_size64(i, NULL) <= 0) + nodemask_clr(nodemask, i); + } #endif /* MPOL_F_MEMS_ALLOWED */ + return 0; +} + +static int cpumask_has_cpus(char *cpumask, size_t len) +{ + int j; + for (j = 0; j < len; j++) + if (cpumask[j] == '\0') + return 0; + else if ((cpumask[j] > '0' && cpumask[j] <= '9') || + (cpumask[j] >= 'a' && cpumask[j] <= 'f')) + return 1; + return 0; + +} + +static void filter_nodemask_cpu(nodemask_t *nodemask, unsigned long max_node) +{ + char *cpumask = NULL; + char fn[64]; + FILE *f; + size_t len; + int i, ret; + for (i = 0; i < max_node; i++) { - if (nodemask_isset(allowed_nodemask, i)) { - if (allowed_nodes) - (*allowed_nodes)[*num_allowed_nodes] = i; - (*num_allowed_nodes)++; + if (!nodemask_isset(nodemask, i)) + continue; + sprintf(fn, "/sys/devices/system/node/node%d/cpumap", i); + f = fopen(fn, "r"); + if (f) { + ret = getdelim(&cpumask, &len, '\n', f); + if ((ret > 0) && (!cpumask_has_cpus(cpumask, len))) + nodemask_clr(nodemask, i); + fclose(f); } } - free(allowed_nodemask); + free(cpumask); +} #endif /* HAVE_NUMA_H */ - return 0; + +/* + * get_allowed_nodes_arr - get number and array of available nodes + * @num_nodes: pointer where number of available nodes will be stored + * @nodes: array of available node ids, this is MPOL_F_MEMS_ALLOWED + * node bitmask compacted (without holes), so that each field + * contains node number. If NULL only num_nodes is + * returned, otherwise it cotains new allocated array, + * which caller is responsible to free. + * RETURNS: + * 0 on success + * -1 on allocation failure + * -2 on get_mempolicy failure + */ +int get_allowed_nodes_arr(int flag, int *num_nodes, int **nodes) +{ + int ret = 0; +#if HAVE_NUMA_H + int i; + nodemask_t *nodemask = NULL; +#endif + *num_nodes = 0; + if (nodes) + *nodes = NULL; + +#if HAVE_NUMA_H + unsigned long max_node = get_max_node(); + unsigned long nodemask_size = max_node/8+1; + + nodemask = malloc(nodemask_size); + if (nodes) + *nodes = malloc(sizeof(int)*max_node); + + do { + if (nodemask == NULL || (nodes && (*nodes == NULL))) { + ret = -1; + break; + } + + /* allow all nodes at start, then filter based on flags */ + get_nodemask_allnodes(nodemask, max_node); + if ((flag & NH_MEMS) == NH_MEMS) { + ret = filter_nodemask_mem(nodemask, max_node); + if (ret < 0) + break; + } + if ((flag & NH_CPUS) == NH_CPUS) + filter_nodemask_cpu(nodemask, max_node); + + for (i = 0; i < max_node; i++) { + if (nodemask_isset(nodemask, i)) { + if (nodes) + (*nodes)[*num_nodes] = i; + (*num_nodes)++; + } + } + } while (0); + free(nodemask); +#endif + return ret; } /* @@ -135,7 +209,7 @@ int get_allowed_nodes_arr(int *num_allowed_nodes, int **allowed_nodes) * -2 on get_mempolicy failure * -3 on not enough allowed nodes */ -int get_allowed_nodes(int count, ...) +int get_allowed_nodes(int flag, int count, ...) { int ret; int i, *nodep; @@ -143,7 +217,7 @@ int get_allowed_nodes(int count, ...) int num_nodes = 0; int *nodes = NULL; - ret = get_allowed_nodes_arr(&num_nodes, &nodes); + ret = get_allowed_nodes_arr(flag, &num_nodes, &nodes); if (ret < 0) return ret; @@ -163,3 +237,30 @@ int get_allowed_nodes(int count, ...) return ret; } + +static void print_node_info(int flag) +{ + int *allowed_nodes = NULL; + int i, ret, num_nodes; + + ret = get_allowed_nodes_arr(flag, &num_nodes, &allowed_nodes); + printf("nodes (flag=%d): ", flag); + if (ret == 0) { + for (i = 0; i < num_nodes; i++) + printf("%d ", allowed_nodes[i]); + printf("\n"); + } else + printf("error(%d)\n", ret); + free(allowed_nodes); +} + +/* + * nh_dump_nodes - dump info about nodes to stdout + */ +void nh_dump_nodes() +{ + print_node_info(0); + print_node_info(NH_MEMS); + print_node_info(NH_CPUS); + print_node_info(NH_MEMS | NH_CPUS); +} diff --git a/testcases/kernel/syscalls/numa/lib/numa_helper.h b/testcases/kernel/syscalls/numa/lib/numa_helper.h index 6bfc58e..463019a 100644 --- a/testcases/kernel/syscalls/numa/lib/numa_helper.h +++ b/testcases/kernel/syscalls/numa/lib/numa_helper.h @@ -27,7 +27,11 @@ #include #endif -int get_allowed_nodes_arr(int *num_allowed_nodes, int **allowed_nodes); -int get_allowed_nodes(int count, ...); +#define NH_MEMS (1 << 0) +#define NH_CPUS (1 << 1) + +int get_allowed_nodes_arr(int flag, int *num_nodes, int **nodes); +int get_allowed_nodes(int flag, int count, ...); +void nh_dump_nodes(); #endif