2 * chcpu - CPU configuration tool
4 * Copyright IBM Corp. 2011
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
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.
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.
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.
30 #include <sys/utsname.h>
33 #include <sys/types.h>
43 #include "closestream.h"
46 #define EXCL_ERROR "--{configure,deconfigure,disable,dispatch,enable}"
48 /* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
49 #define CHCPU_EXIT_SOMEOK 64
51 #define _PATH_SYS_CPU "/sys/devices/system/cpu"
53 static cpu_set_t
*onlinecpus
;
56 #define is_cpu_online(cpu) (CPU_ISSET_S((cpu), CPU_ALLOC_SIZE(maxcpus), onlinecpus))
57 #define num_online_cpus() (CPU_COUNT_S(CPU_ALLOC_SIZE(maxcpus), onlinecpus))
65 CMD_CPU_DISPATCH_HORIZONTAL
,
66 CMD_CPU_DISPATCH_VERTICAL
,
69 /* returns: 0 = success
71 * > 0 = partial success
73 static int cpu_enable(struct path_cxt
*sys
, cpu_set_t
*cpu_set
, size_t setsize
, int enable
)
80 for (cpu
= 0; cpu
< maxcpus
; cpu
++) {
81 if (!CPU_ISSET_S(cpu
, setsize
, cpu_set
))
83 if (ul_path_accessf(sys
, F_OK
, "cpu%d", cpu
) != 0) {
84 warnx(_("CPU %u does not exist"), cpu
);
88 if (ul_path_accessf(sys
, F_OK
, "cpu%d/online", cpu
) != 0) {
89 warnx(_("CPU %u is not hot pluggable"), cpu
);
93 if (ul_path_readf_s32(sys
, &online
, "cpu%d/online", cpu
) == 0
96 printf(_("CPU %u is already enabled\n"), cpu
);
99 if (online
== 0 && enable
== 0) {
100 printf(_("CPU %u is already disabled\n"), cpu
);
103 if (ul_path_accessf(sys
, F_OK
, "cpu%d/configure", cpu
) == 0)
104 ul_path_readf_s32(sys
, &configured
, "cpu%d/configure", cpu
);
106 rc
= ul_path_writef_string(sys
, "1", "cpu%d/online", cpu
);
107 if (rc
!= 0 && configured
== 0) {
108 warn(_("CPU %u enable failed (CPU is deconfigured)"), cpu
);
110 } else if (rc
!= 0) {
111 warn(_("CPU %u enable failed"), cpu
);
114 printf(_("CPU %u enabled\n"), cpu
);
116 if (onlinecpus
&& num_online_cpus() == 1) {
117 warnx(_("CPU %u disable failed (last enabled CPU)"), cpu
);
121 rc
= ul_path_writef_string(sys
, "0", "cpu%d/online", cpu
);
123 warn(_("CPU %u disable failed"), cpu
);
126 printf(_("CPU %u disabled\n"), cpu
);
128 CPU_CLR_S(cpu
, setsize
, onlinecpus
);
133 return fails
== 0 ? 0 : fails
== maxcpus
? -1 : 1;
136 static int cpu_rescan(struct path_cxt
*sys
)
138 if (ul_path_access(sys
, F_OK
, "rescan") != 0)
139 errx(EXIT_FAILURE
, _("This system does not support rescanning of CPUs"));
141 if (ul_path_write_string(sys
, "1", "rescan") != 0)
142 err(EXIT_FAILURE
, _("Failed to trigger rescan of CPUs"));
144 printf(_("Triggered rescan of CPUs\n"));
148 static int cpu_set_dispatch(struct path_cxt
*sys
, int mode
)
150 if (ul_path_access(sys
, F_OK
, "dispatching") != 0)
151 errx(EXIT_FAILURE
, _("This system does not support setting "
152 "the dispatching mode of CPUs"));
154 if (ul_path_write_string(sys
, "0", "dispatching") != 0)
155 err(EXIT_FAILURE
, _("Failed to set horizontal dispatch mode"));
157 printf(_("Successfully set horizontal dispatching mode\n"));
159 if (ul_path_write_string(sys
, "1", "dispatching") != 0)
160 err(EXIT_FAILURE
, _("Failed to set vertical dispatch mode"));
162 printf(_("Successfully set vertical dispatching mode\n"));
167 /* returns: 0 = success
169 * > 0 = partial success
171 static int cpu_configure(struct path_cxt
*sys
, cpu_set_t
*cpu_set
, size_t setsize
, int configure
)
177 for (cpu
= 0; cpu
< maxcpus
; cpu
++) {
178 if (!CPU_ISSET_S(cpu
, setsize
, cpu_set
))
180 if (ul_path_accessf(sys
, F_OK
, "cpu%d", cpu
) != 0) {
181 warnx(_("CPU %u does not exist"), cpu
);
185 if (ul_path_accessf(sys
, F_OK
, "cpu%d/configure", cpu
) != 0) {
186 warnx(_("CPU %u is not configurable"), cpu
);
190 ul_path_readf_s32(sys
, ¤t
, "cpu%d/configure", cpu
);
191 if (current
== 1 && configure
== 1) {
192 printf(_("CPU %u is already configured\n"), cpu
);
195 if (current
== 0 && configure
== 0) {
196 printf(_("CPU %u is already deconfigured\n"), cpu
);
199 if (current
== 1 && configure
== 0 && onlinecpus
&&
200 is_cpu_online(cpu
)) {
201 warnx(_("CPU %u deconfigure failed (CPU is enabled)"), cpu
);
206 rc
= ul_path_writef_string(sys
, "1", "cpu%d/configure", cpu
);
208 warn(_("CPU %u configure failed"), cpu
);
211 printf(_("CPU %u configured\n"), cpu
);
213 rc
= ul_path_writef_string(sys
, "0", "cpu%d/configure", cpu
);
215 warn(_("CPU %u deconfigure failed"), cpu
);
218 printf(_("CPU %u deconfigured\n"), cpu
);
222 return fails
== 0 ? 0 : fails
== maxcpus
? -1 : 1;
225 static void cpu_parse(char *cpu_string
, cpu_set_t
*cpu_set
, size_t setsize
)
229 rc
= cpulist_parse(cpu_string
, cpu_set
, setsize
, 1);
233 errx(EXIT_FAILURE
, _("invalid CPU number in CPU list: %s"), cpu_string
);
234 errx(EXIT_FAILURE
, _("failed to parse CPU list: %s"), cpu_string
);
237 static void __attribute__((__noreturn__
)) usage(void)
242 " %s [options]\n"), program_invocation_short_name
);
244 fputs(USAGE_SEPARATOR
, out
);
245 fputs(_("Configure CPUs in a multi-processor system.\n"), out
);
247 fputs(USAGE_OPTIONS
, stdout
);
249 " -e, --enable <cpu-list> enable cpus\n"
250 " -d, --disable <cpu-list> disable cpus\n"
251 " -c, --configure <cpu-list> configure cpus\n"
252 " -g, --deconfigure <cpu-list> deconfigure cpus\n"
253 " -p, --dispatch <mode> set dispatching mode\n"
254 " -r, --rescan trigger rescan of cpus\n"
256 printf(USAGE_HELP_OPTIONS(31));
258 printf(USAGE_MAN_TAIL("chcpu(8)"));
262 int main(int argc
, char *argv
[])
264 struct path_cxt
*sys
= NULL
; /* _PATH_SYS_CPU handler */
265 cpu_set_t
*cpu_set
= NULL
;
270 static const struct option longopts
[] = {
271 { "configure", required_argument
, NULL
, 'c' },
272 { "deconfigure",required_argument
, NULL
, 'g' },
273 { "disable", required_argument
, NULL
, 'd' },
274 { "dispatch", required_argument
, NULL
, 'p' },
275 { "enable", required_argument
, NULL
, 'e' },
276 { "help", no_argument
, NULL
, 'h' },
277 { "rescan", no_argument
, NULL
, 'r' },
278 { "version", no_argument
, NULL
, 'V' },
282 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
283 { 'c','d','e','g','p' },
286 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
288 setlocale(LC_ALL
, "");
289 bindtextdomain(PACKAGE
, LOCALEDIR
);
291 atexit(close_stdout
);
293 ul_path_init_debug();
294 sys
= ul_new_path(_PATH_SYS_CPU
);
296 err(EXIT_FAILURE
, _("failed to initialize sysfs handler"));
298 maxcpus
= get_max_number_of_cpus();
300 errx(EXIT_FAILURE
, _("cannot determine NR_CPUS; aborting"));
302 if (ul_path_access(sys
, F_OK
, "online") == 0)
303 ul_path_readf_cpulist(sys
, &cpu_set
, maxcpus
, "online");
305 cpu_set
= CPU_ALLOC(maxcpus
);
307 err(EXIT_FAILURE
, _("cpuset_alloc failed"));
309 setsize
= CPU_ALLOC_SIZE(maxcpus
);
311 while ((c
= getopt_long(argc
, argv
, "c:d:e:g:hp:rV", longopts
, NULL
)) != -1) {
313 err_exclusive_options(c
, longopts
, excl
, excl_st
);
317 cmd
= CMD_CPU_CONFIGURE
;
318 cpu_parse(argv
[optind
- 1], cpu_set
, setsize
);
321 cmd
= CMD_CPU_DISABLE
;
322 cpu_parse(argv
[optind
- 1], cpu_set
, setsize
);
325 cmd
= CMD_CPU_ENABLE
;
326 cpu_parse(argv
[optind
- 1], cpu_set
, setsize
);
329 cmd
= CMD_CPU_DECONFIGURE
;
330 cpu_parse(argv
[optind
- 1], cpu_set
, setsize
);
335 if (strcmp("horizontal", argv
[optind
- 1]) == 0)
336 cmd
= CMD_CPU_DISPATCH_HORIZONTAL
;
337 else if (strcmp("vertical", argv
[optind
- 1]) == 0)
338 cmd
= CMD_CPU_DISPATCH_VERTICAL
;
340 errx(EXIT_FAILURE
, _("unsupported argument: %s"),
344 cmd
= CMD_CPU_RESCAN
;
347 printf(UTIL_LINUX_VERSION
);
350 errtryhelp(EXIT_FAILURE
);
354 if ((argc
== 1) || (argc
!= optind
)) {
355 warnx(_("bad usage"));
356 errtryhelp(EXIT_FAILURE
);
361 rc
= cpu_enable(sys
, cpu_set
, maxcpus
, 1);
363 case CMD_CPU_DISABLE
:
364 rc
= cpu_enable(sys
, cpu_set
, maxcpus
, 0);
366 case CMD_CPU_CONFIGURE
:
367 rc
= cpu_configure(sys
, cpu_set
, maxcpus
, 1);
369 case CMD_CPU_DECONFIGURE
:
370 rc
= cpu_configure(sys
, cpu_set
, maxcpus
, 0);
373 rc
= cpu_rescan(sys
);
375 case CMD_CPU_DISPATCH_HORIZONTAL
:
376 rc
= cpu_set_dispatch(sys
, 0);
378 case CMD_CPU_DISPATCH_VERTICAL
:
379 rc
= cpu_set_dispatch(sys
, 1);
388 return rc
== 0 ? EXIT_SUCCESS
:
389 rc
< 0 ? EXIT_FAILURE
: CHCPU_EXIT_SOMEOK
;