diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 60 |
1 files changed, 34 insertions, 26 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 81f56445fba9..0da73cf73e60 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -324,7 +324,6 @@ void kernel_restart_prepare(char *cmd) | |||
324 | system_state = SYSTEM_RESTART; | 324 | system_state = SYSTEM_RESTART; |
325 | usermodehelper_disable(); | 325 | usermodehelper_disable(); |
326 | device_shutdown(); | 326 | device_shutdown(); |
327 | syscore_shutdown(); | ||
328 | } | 327 | } |
329 | 328 | ||
330 | /** | 329 | /** |
@@ -370,6 +369,7 @@ void kernel_restart(char *cmd) | |||
370 | { | 369 | { |
371 | kernel_restart_prepare(cmd); | 370 | kernel_restart_prepare(cmd); |
372 | disable_nonboot_cpus(); | 371 | disable_nonboot_cpus(); |
372 | syscore_shutdown(); | ||
373 | if (!cmd) | 373 | if (!cmd) |
374 | printk(KERN_EMERG "Restarting system.\n"); | 374 | printk(KERN_EMERG "Restarting system.\n"); |
375 | else | 375 | else |
@@ -395,6 +395,7 @@ static void kernel_shutdown_prepare(enum system_states state) | |||
395 | void kernel_halt(void) | 395 | void kernel_halt(void) |
396 | { | 396 | { |
397 | kernel_shutdown_prepare(SYSTEM_HALT); | 397 | kernel_shutdown_prepare(SYSTEM_HALT); |
398 | disable_nonboot_cpus(); | ||
398 | syscore_shutdown(); | 399 | syscore_shutdown(); |
399 | printk(KERN_EMERG "System halted.\n"); | 400 | printk(KERN_EMERG "System halted.\n"); |
400 | kmsg_dump(KMSG_DUMP_HALT); | 401 | kmsg_dump(KMSG_DUMP_HALT); |
@@ -2185,9 +2186,8 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, | |||
2185 | 2186 | ||
2186 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; | 2187 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; |
2187 | 2188 | ||
2188 | static int __orderly_poweroff(void) | 2189 | static int __orderly_poweroff(bool force) |
2189 | { | 2190 | { |
2190 | int argc; | ||
2191 | char **argv; | 2191 | char **argv; |
2192 | static char *envp[] = { | 2192 | static char *envp[] = { |
2193 | "HOME=/", | 2193 | "HOME=/", |
@@ -2196,20 +2196,40 @@ static int __orderly_poweroff(void) | |||
2196 | }; | 2196 | }; |
2197 | int ret; | 2197 | int ret; |
2198 | 2198 | ||
2199 | argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc); | 2199 | argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL); |
2200 | if (argv == NULL) { | 2200 | if (argv) { |
2201 | ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); | ||
2202 | argv_free(argv); | ||
2203 | } else { | ||
2201 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", | 2204 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", |
2202 | __func__, poweroff_cmd); | 2205 | __func__, poweroff_cmd); |
2203 | return -ENOMEM; | 2206 | ret = -ENOMEM; |
2204 | } | 2207 | } |
2205 | 2208 | ||
2206 | ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_WAIT_EXEC, | 2209 | if (ret && force) { |
2207 | NULL, NULL, NULL); | 2210 | printk(KERN_WARNING "Failed to start orderly shutdown: " |
2208 | argv_free(argv); | 2211 | "forcing the issue\n"); |
2212 | /* | ||
2213 | * I guess this should try to kick off some daemon to sync and | ||
2214 | * poweroff asap. Or not even bother syncing if we're doing an | ||
2215 | * emergency shutdown? | ||
2216 | */ | ||
2217 | emergency_sync(); | ||
2218 | kernel_power_off(); | ||
2219 | } | ||
2209 | 2220 | ||
2210 | return ret; | 2221 | return ret; |
2211 | } | 2222 | } |
2212 | 2223 | ||
2224 | static bool poweroff_force; | ||
2225 | |||
2226 | static void poweroff_work_func(struct work_struct *work) | ||
2227 | { | ||
2228 | __orderly_poweroff(poweroff_force); | ||
2229 | } | ||
2230 | |||
2231 | static DECLARE_WORK(poweroff_work, poweroff_work_func); | ||
2232 | |||
2213 | /** | 2233 | /** |
2214 | * orderly_poweroff - Trigger an orderly system poweroff | 2234 | * orderly_poweroff - Trigger an orderly system poweroff |
2215 | * @force: force poweroff if command execution fails | 2235 | * @force: force poweroff if command execution fails |
@@ -2219,21 +2239,9 @@ static int __orderly_poweroff(void) | |||
2219 | */ | 2239 | */ |
2220 | int orderly_poweroff(bool force) | 2240 | int orderly_poweroff(bool force) |
2221 | { | 2241 | { |
2222 | int ret = __orderly_poweroff(); | 2242 | if (force) /* do not override the pending "true" */ |
2223 | 2243 | poweroff_force = true; | |
2224 | if (ret && force) { | 2244 | schedule_work(&poweroff_work); |
2225 | printk(KERN_WARNING "Failed to start orderly shutdown: " | 2245 | return 0; |
2226 | "forcing the issue\n"); | ||
2227 | |||
2228 | /* | ||
2229 | * I guess this should try to kick off some daemon to sync and | ||
2230 | * poweroff asap. Or not even bother syncing if we're doing an | ||
2231 | * emergency shutdown? | ||
2232 | */ | ||
2233 | emergency_sync(); | ||
2234 | kernel_power_off(); | ||
2235 | } | ||
2236 | |||
2237 | return ret; | ||
2238 | } | 2246 | } |
2239 | EXPORT_SYMBOL_GPL(orderly_poweroff); | 2247 | EXPORT_SYMBOL_GPL(orderly_poweroff); |