aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c57
1 files changed, 32 insertions, 25 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index 81f56445fba9..39c9c4a2949f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2185,9 +2185,8 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
2185 2185
2186char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; 2186char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
2187 2187
2188static int __orderly_poweroff(void) 2188static int __orderly_poweroff(bool force)
2189{ 2189{
2190 int argc;
2191 char **argv; 2190 char **argv;
2192 static char *envp[] = { 2191 static char *envp[] = {
2193 "HOME=/", 2192 "HOME=/",
@@ -2196,20 +2195,40 @@ static int __orderly_poweroff(void)
2196 }; 2195 };
2197 int ret; 2196 int ret;
2198 2197
2199 argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc); 2198 argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL);
2200 if (argv == NULL) { 2199 if (argv) {
2200 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
2201 argv_free(argv);
2202 } else {
2201 printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", 2203 printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
2202 __func__, poweroff_cmd); 2204 __func__, poweroff_cmd);
2203 return -ENOMEM; 2205 ret = -ENOMEM;
2204 } 2206 }
2205 2207
2206 ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_WAIT_EXEC, 2208 if (ret && force) {
2207 NULL, NULL, NULL); 2209 printk(KERN_WARNING "Failed to start orderly shutdown: "
2208 argv_free(argv); 2210 "forcing the issue\n");
2211 /*
2212 * I guess this should try to kick off some daemon to sync and
2213 * poweroff asap. Or not even bother syncing if we're doing an
2214 * emergency shutdown?
2215 */
2216 emergency_sync();
2217 kernel_power_off();
2218 }
2209 2219
2210 return ret; 2220 return ret;
2211} 2221}
2212 2222
2223static bool poweroff_force;
2224
2225static void poweroff_work_func(struct work_struct *work)
2226{
2227 __orderly_poweroff(poweroff_force);
2228}
2229
2230static DECLARE_WORK(poweroff_work, poweroff_work_func);
2231
2213/** 2232/**
2214 * orderly_poweroff - Trigger an orderly system poweroff 2233 * orderly_poweroff - Trigger an orderly system poweroff
2215 * @force: force poweroff if command execution fails 2234 * @force: force poweroff if command execution fails
@@ -2219,21 +2238,9 @@ static int __orderly_poweroff(void)
2219 */ 2238 */
2220int orderly_poweroff(bool force) 2239int orderly_poweroff(bool force)
2221{ 2240{
2222 int ret = __orderly_poweroff(); 2241 if (force) /* do not override the pending "true" */
2223 2242 poweroff_force = true;
2224 if (ret && force) { 2243 schedule_work(&poweroff_work);
2225 printk(KERN_WARNING "Failed to start orderly shutdown: " 2244 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} 2245}
2239EXPORT_SYMBOL_GPL(orderly_poweroff); 2246EXPORT_SYMBOL_GPL(orderly_poweroff);