From: Javier Viguera Date: Wed, 29 Oct 2014 13:06:15 +0100 Subject: [PATCH] sysvinit: disable all cpus but cpu0 for halt/reboot Signed-off-by: Javier Viguera --- src/Makefile | 6 ++--- src/halt.c | 20 ++++++++++------ src/init.c | 5 ++++ src/shutdown.c | 3 +++ src/sysfs_cpu.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ src/sysfs_cpu.h | 24 +++++++++++++++++++ 6 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 src/sysfs_cpu.c create mode 100644 src/sysfs_cpu.h diff --git a/src/Makefile b/src/Makefile index 1b368dc..b22fd52 100644 --- a/src/Makefile +++ b/src/Makefile @@ -107,14 +107,14 @@ all: $(BIN) $(SBIN) $(USRBIN) # $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) #%.o: %.c # $(CC) $(CFLAGS) $(CPPFLAGS) -c $^ -o $@ init: LDLIBS += $(INITLIBS) $(STATIC) -init: init.o init_utmp.o runlevellog.o +init: init.o init_utmp.o runlevellog.o sysfs_cpu.o halt: LDLIBS += $(STATIC) -halt: halt.o ifdown.o hddown.o utmp.o runlevellog.o +halt: halt.o ifdown.o hddown.o utmp.o runlevellog.o sysfs_cpu.o last: LDLIBS += $(STATIC) last: last.o logsave: LDLIBS += $(STATIC) @@ -137,11 +137,11 @@ sulogin: sulogin.o consoles.o wall: LDLIBS += $(STATIC) wall: dowall.o wall.o shutdown: LDLIBS += $(STATIC) -shutdown: dowall.o shutdown.o utmp.o +shutdown: dowall.o shutdown.o utmp.o sysfs_cpu.o bootlogd: LDLIBS += -lutil $(STATIC) bootlogd: bootlogd.o readbootlog: LDLIBS += $(STATIC) diff --git a/src/halt.c b/src/halt.c index a469147..f51d0cb 100644 --- a/src/halt.c +++ b/src/halt.c @@ -56,10 +56,11 @@ #include #include #include #include "reboot.h" #include "runlevellog.h" +#include "sysfs_cpu.h" char *Version = "@(#)halt 2.86 31-Jul-2004 miquels@cistron.nl"; char *progname; #define KERNEL_MONITOR 1 /* If halt() puts you into the kernel monitor. */ @@ -253,17 +254,22 @@ int main(int argc, char **argv) if (chdir("/")) { fprintf(stderr, "%s: chdir(/): %m\n", progname); exit(1); } - if (!do_hard && !do_nothing) { - /* - * See if we are in runlevel 0 or 6. - */ - c = get_runlevel(); - if (c != '0' && c != '6') - do_shutdown(do_reboot ? "-r" : "-h", do_poweroff, tm); + if (!do_nothing) { + if (!do_hard) { + /* + * See if we are in runlevel 0 or 6. + */ + c = get_runlevel(); + if (c != '0' && c != '6') + do_shutdown(do_reboot ? "-r" : "-h", do_poweroff, tm); + } else { + /* Disable cores for halt/reboot */ + sysfs_disable_cpu_all(); + } } /* * Record the fact that we're going down */ diff --git a/src/init.c b/src/init.c index 78ae760..432f0e5 100644 --- a/src/init.c +++ b/src/init.c @@ -93,10 +93,11 @@ extern char **environ; #include "initreq.h" #include "paths.h" #include "reboot.h" #include "runlevellog.h" #include "set.h" +#include "sysfs_cpu.h" #ifndef SIGPWR # define SIGPWR SIGUSR2 #endif @@ -3016,10 +3017,14 @@ int telinit(char *progname, int argc, char **argv) if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0])) usage(progname); request.cmd = INIT_CMD_RUNLVL; request.runlevel = argv[optind][0]; request.sleeptime = sleep_time; + + /* Disable cores for halt/reboot */ + if (request.runlevel == '0' || request.runlevel == '6') + sysfs_disable_cpu_all(); } /* Change to the root directory. */ if (0 != chdir("/")) initlog(L_VB, "unable to chdir to /: %s", diff --git a/src/shutdown.c b/src/shutdown.c index c49795f..48e65d1 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -344,10 +344,13 @@ void fastdown() else script = REBOOTSCRIPT2; } #endif + /* Disable cores for halt/reboot */ + sysfs_disable_cpu_all(); + /* First close all files. */ for(i = 0; i < 3; i++) if (!isatty(i)) { close(i); open("/dev/null", O_RDWR); diff --git a/src/sysfs_cpu.c b/src/sysfs_cpu.c new file mode 100644 index 0000000..fe14ff7 --- /dev/null +++ b/src/sysfs_cpu.c @@ -0,0 +1,63 @@ +/* + * sysfs_cpu.c + * + * Copyright (C) 2014 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Description: CPU SYSFS API + * + */ + +#include +#include +#include +#include + +#include "sysfs_cpu.h" + +static int sysfs_cpu_set_value(int cpu, int value) +{ + int fd = -1, len; + char buf[64]; + + if (cpu < 0) + return 0; + + snprintf(buf, sizeof(buf), CPUS_SYSDIR "/cpu%d/online", cpu); + fd = open(buf, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "unable to open %s.\r\n", buf); + return fd; + } + snprintf(buf, sizeof(buf), "%s", value ? "1" : "0"); + len = write(fd, buf, 1); + close(fd); + + return (len < 1) ? -1 : 0; +} + +int sysfs_disable_cpu(int cpu) +{ + return sysfs_cpu_set_value(cpu, 0); +} + +/* Disable all CPUS but 'cpu0' */ +int sysfs_disable_cpu_all(void) +{ + int i, ncores; + + ncores = get_nprocs_conf(); + for (i = 1; i < ncores; i++) + sysfs_disable_cpu(i); + + return 0; +} + +int sysfs_enable_cpu(int cpu) +{ + return sysfs_cpu_set_value(cpu, 1); +} diff --git a/src/sysfs_cpu.h b/src/sysfs_cpu.h new file mode 100644 index 0000000..7728d52 --- /dev/null +++ b/src/sysfs_cpu.h @@ -0,0 +1,24 @@ +/* + * sysfs_cpu.h + * + * Copyright (C) 2014 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Description: CPU SYSFS API + * + */ + +#ifndef SYSFS_CPU_H +#define SYSFS_CPU_H + +#define CPUS_SYSDIR "/sys/devices/system/cpu" + +int sysfs_disable_cpu(int cpu); +int sysfs_disable_cpu_all(void); +int sysfs_enable_cpu(int cpu); + +#endif /* SYSFS_CPU_H */