1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright © International Business Machines Corp., 2007, 2008
4 *
5 * Test Description:
6 * The test process is affined to a CPU. It then calls getcpu and
7 * checks that the CPU and node (if supported) match the expected
8 * values.
9 */
10
11 #define _GNU_SOURCE
12 #include <dirent.h>
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include "tst_test.h"
18 #include "lapi/cpuset.h"
19 #include "lapi/sched.h"
20
max_cpuid(size_t size,cpu_set_t * set)21 static unsigned int max_cpuid(size_t size, cpu_set_t * set)
22 {
23 unsigned int index, max = 0;
24 for (index = 0; index < size * 8; index++)
25 if (CPU_ISSET_S(index, size, set))
26 max = index;
27 return max;
28 }
29
30 /*
31 * This will set the affinity to max cpu on which process can run
32 * and return that cpu id to the calling process
33 */
set_cpu_affinity(void)34 static unsigned int set_cpu_affinity(void)
35 {
36 unsigned cpu_max;
37 cpu_set_t *set;
38 size_t size;
39 int nrcpus = 1024;
40
41 realloc:
42 set = CPU_ALLOC(nrcpus);
43 if (!set)
44 tst_brk(TBROK | TERRNO, "CPU_ALLOC()");
45
46 size = CPU_ALLOC_SIZE(nrcpus);
47 CPU_ZERO_S(size, set);
48 if (sched_getaffinity(0, size, set) < 0) {
49 CPU_FREE(set);
50 if (errno == EINVAL && nrcpus < (1024 << 8)) {
51 nrcpus = nrcpus << 2;
52 goto realloc;
53 }
54 tst_brk(TBROK | TERRNO, "sched_getaffinity()");
55 }
56 cpu_max = max_cpuid(size, set);
57 CPU_ZERO_S(size, set);
58 CPU_SET_S(cpu_max, size, set);
59 if (sched_setaffinity(0, size, set) < 0) {
60 CPU_FREE(set);
61 tst_brk(TBROK | TERRNO, "sched_setaffinity()");
62 }
63 CPU_FREE(set);
64 return cpu_max;
65 }
66
get_nodeid(unsigned int cpu_id)67 static unsigned int get_nodeid(unsigned int cpu_id)
68 {
69 DIR *directory_parent, *directory_node;
70 struct dirent *de, *dn;
71 char directory_path[PATH_MAX];
72 char *invalid_number;
73 unsigned int cpu;
74 int node_id = 0;
75
76 directory_parent = opendir("/sys/devices/system/node");
77 if (!directory_parent) {
78 tst_res(TINFO,
79 "/sys not mounted or not a numa system. "
80 "Assuming one node");
81 tst_res(TINFO, "Error opening: /sys/devices/system/node :%s",
82 strerror(errno));
83 /* Assume CPU belongs to the only node, node zero. */
84 return 0;
85 } else {
86 while ((de = readdir(directory_parent)) != NULL) {
87 if (strncmp(de->d_name, "node", 4))
88 continue;
89 sprintf(directory_path, "/sys/devices/system/node/%s",
90 de->d_name);
91 directory_node = opendir(directory_path);
92 while ((dn = readdir(directory_node)) != NULL) {
93 if (strncmp(dn->d_name, "cpu", 3))
94 continue;
95 cpu = strtoul(dn->d_name + 3, &invalid_number, 0);
96 if (strcmp(invalid_number, "\0"))
97 continue;
98 if (cpu == cpu_id) {
99 node_id =
100 strtoul(de->d_name + 4, NULL, 0);
101 break;
102 }
103 }
104 closedir(directory_node);
105 }
106 closedir(directory_parent);
107 }
108 return node_id;
109 }
110
run(void)111 static void run(void)
112 {
113 unsigned int cpu_id, node_id = 0;
114 unsigned int cpu_set;
115 unsigned int node_set;
116
117 cpu_set = set_cpu_affinity();
118 node_set = get_nodeid(cpu_set);
119
120 TEST(getcpu(&cpu_id, &node_id));
121 if (TST_RET == 0) {
122 if (cpu_id != cpu_set)
123 tst_res(TFAIL, "getcpu() returned wrong value"
124 " expected cpuid:%d, returned value cpuid: %d",
125 cpu_set, cpu_id);
126 else if (node_id != node_set)
127 tst_res(TFAIL, "getcpu() returned wrong value"
128 " expected node id:%d returned node id:%d",
129 node_set, node_id);
130 else
131 tst_res(TPASS, "getcpu() returned proper"
132 " cpuid:%d, node id:%d", cpu_id,
133 node_id);
134 } else {
135 tst_res(TFAIL, "getcpu() Failed, errno=%d:%s",
136 TST_ERR, strerror(TST_ERR));
137 }
138 }
139
140 static struct tst_test test = {
141 .test_all = run,
142 };
143