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 81f56445fba..39c9c4a2949 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2185,9 +2185,8 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,  char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; -static int __orderly_poweroff(void) +static int __orderly_poweroff(bool force)  { -	int argc;  	char **argv;  	static char *envp[] = {  		"HOME=/", @@ -2196,20 +2195,40 @@ static int __orderly_poweroff(void)  	};  	int ret; -	argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc); -	if (argv == NULL) { +	argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL); +	if (argv) { +		ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); +		argv_free(argv); +	} else {  		printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", -		       __func__, poweroff_cmd); -		return -ENOMEM; +					 __func__, poweroff_cmd); +		ret = -ENOMEM;  	} -	ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_WAIT_EXEC, -				      NULL, NULL, NULL); -	argv_free(argv); +	if (ret && force) { +		printk(KERN_WARNING "Failed to start orderly shutdown: " +					"forcing the issue\n"); +		/* +		 * I guess this should try to kick off some daemon to sync and +		 * poweroff asap.  Or not even bother syncing if we're doing an +		 * emergency shutdown? +		 */ +		emergency_sync(); +		kernel_power_off(); +	}  	return ret;  } +static bool poweroff_force; + +static void poweroff_work_func(struct work_struct *work) +{ +	__orderly_poweroff(poweroff_force); +} + +static DECLARE_WORK(poweroff_work, poweroff_work_func); +  /**   * orderly_poweroff - Trigger an orderly system poweroff   * @force: force poweroff if command execution fails @@ -2219,21 +2238,9 @@ static int __orderly_poweroff(void)   */  int orderly_poweroff(bool force)  { -	int ret = __orderly_poweroff(); - -	if (ret && force) { -		printk(KERN_WARNING "Failed to start orderly shutdown: " -		       "forcing the issue\n"); - -		/* -		 * I guess this should try to kick off some daemon to sync and -		 * poweroff asap.  Or not even bother syncing if we're doing an -		 * emergency shutdown? -		 */ -		emergency_sync(); -		kernel_power_off(); -	} - -	return ret; +	if (force) /* do not override the pending "true" */ +		poweroff_force = true; +	schedule_work(&poweroff_work); +	return 0;  }  EXPORT_SYMBOL_GPL(orderly_poweroff); |