diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 57 |
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 | ||
2186 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; | 2186 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; |
2187 | 2187 | ||
2188 | static int __orderly_poweroff(void) | 2188 | static 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 | ||
2223 | static bool poweroff_force; | ||
2224 | |||
2225 | static void poweroff_work_func(struct work_struct *work) | ||
2226 | { | ||
2227 | __orderly_poweroff(poweroff_force); | ||
2228 | } | ||
2229 | |||
2230 | static 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 | */ |
2220 | int orderly_poweroff(bool force) | 2239 | int 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 | } |
2239 | EXPORT_SYMBOL_GPL(orderly_poweroff); | 2246 | EXPORT_SYMBOL_GPL(orderly_poweroff); |