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 21static 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 */ 34static 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 41realloc: 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 67static 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 111static 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 140static struct tst_test test = { 141 .test_all = run, 142}; 143