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