xen: do not respond to unknown xenstore control requests
authorIan Campbell <ian.campbell@citrix.com>
Thu, 17 Feb 2011 11:04:20 +0000 (11:04 +0000)
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>
Fri, 25 Feb 2011 16:43:09 +0000 (16:43 +0000)
The PV xenbus control/shutdown node is written by the toolstack as a
request to the guest to perform a particular action (shutdown, reboot,
suspend etc). The guest is expected to acknowledge that it will
complete a request by clearing the control node.

Previously it would acknowledge any request, even if it did not know
what to do with it. Specifically in the case where CONFIG_PM_SLEEP is
not enabled the kernel would acknowledge a suspend request even though
it was not actually going to do anything.

Instead make the kernel only acknowledge requests if it is actually
going to do something with it. This will improve the toolstack's
ability to diagnose and deal with failures.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
drivers/xen/manage.c

index b2a8d7856ce39b99e793fda9992eba24bcd3c24f..972bf783a1825d2b811ac70de4ef1f81d6fd2410 100644 (file)
@@ -172,12 +172,39 @@ out:
 }
 #endif /* CONFIG_PM_SLEEP */
 
+struct shutdown_handler {
+       const char *command;
+       void (*cb)(void);
+};
+
+static void do_poweroff(void)
+{
+       shutting_down = SHUTDOWN_POWEROFF;
+       orderly_poweroff(false);
+}
+
+static void do_reboot(void)
+{
+       shutting_down = SHUTDOWN_POWEROFF; /* ? */
+       ctrl_alt_del();
+}
+
 static void shutdown_handler(struct xenbus_watch *watch,
                             const char **vec, unsigned int len)
 {
        char *str;
        struct xenbus_transaction xbt;
        int err;
+       static struct shutdown_handler handlers[] = {
+               { "poweroff",   do_poweroff },
+               { "halt",       do_poweroff },
+               { "reboot",     do_reboot   },
+#ifdef CONFIG_PM_SLEEP
+               { "suspend",    do_suspend  },
+#endif
+               {NULL, NULL},
+       };
+       static struct shutdown_handler *handler;
 
        if (shutting_down != SHUTDOWN_INVALID)
                return;
@@ -194,7 +221,14 @@ static void shutdown_handler(struct xenbus_watch *watch,
                return;
        }
 
-       xenbus_write(xbt, "control", "shutdown", "");
+       for (handler = &handlers[0]; handler->command; handler++) {
+               if (strcmp(str, handler->command) == 0)
+                       break;
+       }
+
+       /* Only acknowledge commands which we are prepared to handle. */
+       if (handler->cb)
+               xenbus_write(xbt, "control", "shutdown", "");
 
        err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN) {
@@ -202,17 +236,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
                goto again;
        }
 
-       if (strcmp(str, "poweroff") == 0 ||
-           strcmp(str, "halt") == 0) {
-               shutting_down = SHUTDOWN_POWEROFF;
-               orderly_poweroff(false);
-       } else if (strcmp(str, "reboot") == 0) {
-               shutting_down = SHUTDOWN_POWEROFF; /* ? */
-               ctrl_alt_del();
-#ifdef CONFIG_PM_SLEEP
-       } else if (strcmp(str, "suspend") == 0) {
-               do_suspend();
-#endif
+       if (handler->cb) {
+               handler->cb();
        } else {
                printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
                shutting_down = SHUTDOWN_INVALID;