Merge tag 'ep93xx-fixes-for-3.9-rc5' of git://github.com/RyanMallon/linux-ep93xx...
[firefly-linux-kernel-4.4.55.git] / kernel / sys.c
index e10566bee39967394b05c42effce1e56cb6b76f6..39c9c4a2949f3166b114f11534957ff2f6060565 100644 (file)
@@ -2185,14 +2185,8 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
 
 char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
 
-static void argv_cleanup(struct subprocess_info *info)
+static int __orderly_poweroff(bool force)
 {
-       argv_free(info->argv);
-}
-
-static int __orderly_poweroff(void)
-{
-       int argc;
        char **argv;
        static char *envp[] = {
                "HOME=/",
@@ -2201,21 +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, argv_cleanup, NULL);
-       if (ret == -ENOMEM)
-               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
@@ -2225,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);