]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/chcpu.c
chcpu: Fix maximal number of CPUs
[thirdparty/util-linux.git] / sys-utils / chcpu.c
1 /*
2 * chcpu - CPU configuration tool
3 *
4 * Copyright IBM Corp. 2011
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include <ctype.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/utsname.h>
31 #include <unistd.h>
32 #include <stdarg.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "cpuset.h"
37 #include "nls.h"
38 #include "xalloc.h"
39 #include "c.h"
40 #include "strutils.h"
41 #include "bitops.h"
42 #include "path.h"
43 #include "closestream.h"
44 #include "optutils.h"
45
46 #define EXCL_ERROR "--{configure,deconfigure,disable,dispatch,enable}"
47
48 /* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
49 #define CHCPU_EXIT_SOMEOK 64
50
51 #define _PATH_SYS_CPU "/sys/devices/system/cpu"
52 #define _PATH_SYS_CPU_ONLINE _PATH_SYS_CPU "/online"
53 #define _PATH_SYS_CPU_RESCAN _PATH_SYS_CPU "/rescan"
54 #define _PATH_SYS_CPU_DISPATCH _PATH_SYS_CPU "/dispatching"
55
56 static cpu_set_t *onlinecpus;
57 static int maxcpus;
58
59 #define is_cpu_online(cpu) (CPU_ISSET_S((cpu), CPU_ALLOC_SIZE(maxcpus), onlinecpus))
60 #define num_online_cpus() (CPU_COUNT_S(CPU_ALLOC_SIZE(maxcpus), onlinecpus))
61
62 enum {
63 CMD_CPU_ENABLE = 0,
64 CMD_CPU_DISABLE,
65 CMD_CPU_CONFIGURE,
66 CMD_CPU_DECONFIGURE,
67 CMD_CPU_RESCAN,
68 CMD_CPU_DISPATCH_HORIZONTAL,
69 CMD_CPU_DISPATCH_VERTICAL,
70 };
71
72 /* returns: 0 = success
73 * < 0 = failure
74 * > 0 = partial success
75 */
76 static int cpu_enable(cpu_set_t *cpu_set, size_t setsize, int enable)
77 {
78 int cpu;
79 int online, rc;
80 int configured = -1;
81 int fails = 0;
82
83 for (cpu = 0; cpu < maxcpus; cpu++) {
84 if (!CPU_ISSET_S(cpu, setsize, cpu_set))
85 continue;
86 if (!path_exist(_PATH_SYS_CPU "/cpu%d", cpu)) {
87 warnx(_("CPU %u does not exist"), cpu);
88 fails++;
89 continue;
90 }
91 if (!path_exist(_PATH_SYS_CPU "/cpu%d/online", cpu)) {
92 warnx(_("CPU %u is not hot pluggable"), cpu);
93 fails++;
94 continue;
95 }
96 online = path_read_s32(_PATH_SYS_CPU "/cpu%d/online", cpu);
97 if ((online == 1) && (enable == 1)) {
98 printf(_("CPU %u is already enabled\n"), cpu);
99 continue;
100 }
101 if ((online == 0) && (enable == 0)) {
102 printf(_("CPU %u is already disabled\n"), cpu);
103 continue;
104 }
105 if (path_exist(_PATH_SYS_CPU "/cpu%d/configure", cpu))
106 configured = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", cpu);
107 if (enable) {
108 rc = path_write_str("1", _PATH_SYS_CPU "/cpu%d/online", cpu);
109 if ((rc == -1) && (configured == 0)) {
110 warn(_("CPU %u enable failed (CPU is deconfigured)"), cpu);
111 fails++;
112 } else if (rc == -1) {
113 warn(_("CPU %u enable failed"), cpu);
114 fails++;
115 } else
116 printf(_("CPU %u enabled\n"), cpu);
117 } else {
118 if (onlinecpus && num_online_cpus() == 1) {
119 warnx(_("CPU %u disable failed (last enabled CPU)"), cpu);
120 fails++;
121 continue;
122 }
123 rc = path_write_str("0", _PATH_SYS_CPU "/cpu%d/online", cpu);
124 if (rc == -1) {
125 warn(_("CPU %u disable failed"), cpu);
126 fails++;
127 } else {
128 printf(_("CPU %u disabled\n"), cpu);
129 if (onlinecpus)
130 CPU_CLR_S(cpu, setsize, onlinecpus);
131 }
132 }
133 }
134
135 return fails == 0 ? 0 : fails == maxcpus ? -1 : 1;
136 }
137
138 static int cpu_rescan(void)
139 {
140 if (!path_exist(_PATH_SYS_CPU_RESCAN))
141 errx(EXIT_FAILURE, _("This system does not support rescanning of CPUs"));
142 if (path_write_str("1", _PATH_SYS_CPU_RESCAN) == -1)
143 err(EXIT_FAILURE, _("Failed to trigger rescan of CPUs"));
144 printf(_("Triggered rescan of CPUs\n"));
145 return 0;
146 }
147
148 static int cpu_set_dispatch(int mode)
149 {
150 if (!path_exist(_PATH_SYS_CPU_DISPATCH))
151 errx(EXIT_FAILURE, _("This system does not support setting "
152 "the dispatching mode of CPUs"));
153 if (mode == 0) {
154 if (path_write_str("0", _PATH_SYS_CPU_DISPATCH) == -1)
155 err(EXIT_FAILURE, _("Failed to set horizontal dispatch mode"));
156 printf(_("Successfully set horizontal dispatching mode\n"));
157 } else {
158 if (path_write_str("1", _PATH_SYS_CPU_DISPATCH) == -1)
159 err(EXIT_FAILURE, _("Failed to set vertical dispatch mode"));
160 printf(_("Successfully set vertical dispatching mode\n"));
161 }
162 return 0;
163 }
164
165 /* returns: 0 = success
166 * < 0 = failure
167 * > 0 = partial success
168 */
169 static int cpu_configure(cpu_set_t *cpu_set, size_t setsize, int configure)
170 {
171 int cpu;
172 int rc, current;
173 int fails = 0;
174
175 for (cpu = 0; cpu < maxcpus; cpu++) {
176 if (!CPU_ISSET_S(cpu, setsize, cpu_set))
177 continue;
178 if (!path_exist(_PATH_SYS_CPU "/cpu%d", cpu)) {
179 warnx(_("CPU %u does not exist"), cpu);
180 fails++;
181 continue;
182 }
183 if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", cpu)) {
184 warnx(_("CPU %u is not configurable"), cpu);
185 fails++;
186 continue;
187 }
188 current = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", cpu);
189 if ((current == 1) && (configure == 1)) {
190 printf(_("CPU %u is already configured\n"), cpu);
191 continue;
192 }
193 if ((current == 0) && (configure == 0)) {
194 printf(_("CPU %u is already deconfigured\n"), cpu);
195 continue;
196 }
197 if ((current == 1) && (configure == 0) && onlinecpus &&
198 is_cpu_online(cpu)) {
199 warnx(_("CPU %u deconfigure failed (CPU is enabled)"), cpu);
200 fails++;
201 continue;
202 }
203 if (configure) {
204 rc = path_write_str("1", _PATH_SYS_CPU "/cpu%d/configure", cpu);
205 if (rc == -1) {
206 warn(_("CPU %u configure failed"), cpu);
207 fails++;
208 } else
209 printf(_("CPU %u configured\n"), cpu);
210 } else {
211 rc = path_write_str("0", _PATH_SYS_CPU "/cpu%d/configure", cpu);
212 if (rc == -1) {
213 warn(_("CPU %u deconfigure failed"), cpu);
214 fails++;
215 } else
216 printf(_("CPU %u deconfigured\n"), cpu);
217 }
218 }
219
220 return fails == 0 ? 0 : fails == maxcpus ? -1 : 1;
221 }
222
223 static void cpu_parse(char *cpu_string, cpu_set_t *cpu_set, size_t setsize)
224 {
225 int rc;
226
227 rc = cpulist_parse(cpu_string, cpu_set, setsize, 1);
228 if (rc == 0)
229 return;
230 if (rc == 2)
231 errx(EXIT_FAILURE, _("invalid CPU number in CPU list: %s"), cpu_string);
232 errx(EXIT_FAILURE, _("failed to parse CPU list: %s"), cpu_string);
233 }
234
235 static void __attribute__((__noreturn__)) usage(void)
236 {
237 FILE *out = stdout;
238 fprintf(out, _(
239 "\nUsage:\n"
240 " %s [options]\n"), program_invocation_short_name);
241
242 fputs(USAGE_SEPARATOR, out);
243 fputs(_("Configure CPUs in a multi-processor system.\n"), out);
244
245 fputs(USAGE_OPTIONS, stdout);
246 fputs(_(
247 " -e, --enable <cpu-list> enable cpus\n"
248 " -d, --disable <cpu-list> disable cpus\n"
249 " -c, --configure <cpu-list> configure cpus\n"
250 " -g, --deconfigure <cpu-list> deconfigure cpus\n"
251 " -p, --dispatch <mode> set dispatching mode\n"
252 " -r, --rescan trigger rescan of cpus\n"
253 ), stdout);
254 printf(USAGE_HELP_OPTIONS(31));
255
256 printf(USAGE_MAN_TAIL("chcpu(8)"));
257 exit(EXIT_SUCCESS);
258 }
259
260 int main(int argc, char *argv[])
261 {
262 cpu_set_t *cpu_set;
263 size_t setsize;
264 int cmd = -1;
265 int c, rc;
266
267 static const struct option longopts[] = {
268 { "configure", required_argument, NULL, 'c' },
269 { "deconfigure",required_argument, NULL, 'g' },
270 { "disable", required_argument, NULL, 'd' },
271 { "dispatch", required_argument, NULL, 'p' },
272 { "enable", required_argument, NULL, 'e' },
273 { "help", no_argument, NULL, 'h' },
274 { "rescan", no_argument, NULL, 'r' },
275 { "version", no_argument, NULL, 'V' },
276 { NULL, 0, NULL, 0 }
277 };
278
279 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
280 { 'c','d','e','g','p' },
281 { 0 }
282 };
283 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
284
285 setlocale(LC_ALL, "");
286 bindtextdomain(PACKAGE, LOCALEDIR);
287 textdomain(PACKAGE);
288 atexit(close_stdout);
289
290 maxcpus = get_max_number_of_cpus();
291 if (maxcpus < 1)
292 errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting"));
293 if (path_exist(_PATH_SYS_CPU_ONLINE))
294 onlinecpus = path_read_cpulist(maxcpus, _PATH_SYS_CPU_ONLINE);
295 setsize = CPU_ALLOC_SIZE(maxcpus);
296 cpu_set = CPU_ALLOC(maxcpus);
297 if (!cpu_set)
298 err(EXIT_FAILURE, _("cpuset_alloc failed"));
299
300 while ((c = getopt_long(argc, argv, "c:d:e:g:hp:rV", longopts, NULL)) != -1) {
301
302 err_exclusive_options(c, longopts, excl, excl_st);
303
304 switch (c) {
305 case 'c':
306 cmd = CMD_CPU_CONFIGURE;
307 cpu_parse(argv[optind - 1], cpu_set, setsize);
308 break;
309 case 'd':
310 cmd = CMD_CPU_DISABLE;
311 cpu_parse(argv[optind - 1], cpu_set, setsize);
312 break;
313 case 'e':
314 cmd = CMD_CPU_ENABLE;
315 cpu_parse(argv[optind - 1], cpu_set, setsize);
316 break;
317 case 'g':
318 cmd = CMD_CPU_DECONFIGURE;
319 cpu_parse(argv[optind - 1], cpu_set, setsize);
320 break;
321 case 'h':
322 usage();
323 case 'p':
324 if (strcmp("horizontal", argv[optind - 1]) == 0)
325 cmd = CMD_CPU_DISPATCH_HORIZONTAL;
326 else if (strcmp("vertical", argv[optind - 1]) == 0)
327 cmd = CMD_CPU_DISPATCH_VERTICAL;
328 else
329 errx(EXIT_FAILURE, _("unsupported argument: %s"),
330 argv[optind -1 ]);
331 break;
332 case 'r':
333 cmd = CMD_CPU_RESCAN;
334 break;
335 case 'V':
336 printf(UTIL_LINUX_VERSION);
337 return EXIT_SUCCESS;
338 default:
339 errtryhelp(EXIT_FAILURE);
340 }
341 }
342
343 if ((argc == 1) || (argc != optind)) {
344 warnx(_("bad usage"));
345 errtryhelp(EXIT_FAILURE);
346 }
347
348 switch (cmd) {
349 case CMD_CPU_ENABLE:
350 rc = cpu_enable(cpu_set, maxcpus, 1);
351 break;
352 case CMD_CPU_DISABLE:
353 rc = cpu_enable(cpu_set, maxcpus, 0);
354 break;
355 case CMD_CPU_CONFIGURE:
356 rc = cpu_configure(cpu_set, maxcpus, 1);
357 break;
358 case CMD_CPU_DECONFIGURE:
359 rc = cpu_configure(cpu_set, maxcpus, 0);
360 break;
361 case CMD_CPU_RESCAN:
362 rc = cpu_rescan();
363 break;
364 case CMD_CPU_DISPATCH_HORIZONTAL:
365 rc = cpu_set_dispatch(0);
366 break;
367 case CMD_CPU_DISPATCH_VERTICAL:
368 rc = cpu_set_dispatch(1);
369 break;
370 default:
371 rc = -EINVAL;
372 break;
373 }
374
375 return rc == 0 ? EXIT_SUCCESS :
376 rc < 0 ? EXIT_FAILURE : CHCPU_EXIT_SOMEOK;
377 }