diff options
| author | Jeremy Fitzhardinge <jeremy@xensource.com> | 2007-07-17 21:37:07 -0400 |
|---|---|---|
| committer | Jeremy Fitzhardinge <jeremy@goop.org> | 2007-07-18 11:47:45 -0400 |
| commit | 3e2b8fbeec8f005672f2a2e862fb9c26a0bafedc (patch) | |
| tree | 47bd623e5d692daf3b91316a3a715ff7356bc22b | |
| parent | fefa629abebe328cf6d07f99fe5796dbfc3e4981 (diff) | |
xen: handle external requests for shutdown, reboot and sysrq
The guest domain can be asked to shutdown or reboot itself, or have a
sysrq key injected, via xenbus. This patch adds a watcher for those
events, and does the appropriate action.
Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Chris Wright <chrisw@sous-sol.org>
| -rw-r--r-- | arch/i386/xen/Makefile | 2 | ||||
| -rw-r--r-- | arch/i386/xen/manage.c | 143 |
2 files changed, 144 insertions, 1 deletions
diff --git a/arch/i386/xen/Makefile b/arch/i386/xen/Makefile index fd05f243a3f8..7bf2ce399a2a 100644 --- a/arch/i386/xen/Makefile +++ b/arch/i386/xen/Makefile | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \ | 1 | obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \ |
| 2 | events.o time.o | 2 | events.o time.o manage.o |
| 3 | 3 | ||
| 4 | obj-$(CONFIG_SMP) += smp.o | 4 | obj-$(CONFIG_SMP) += smp.o |
diff --git a/arch/i386/xen/manage.c b/arch/i386/xen/manage.c new file mode 100644 index 000000000000..aa7af9e6abc0 --- /dev/null +++ b/arch/i386/xen/manage.c | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | /* | ||
| 2 | * Handle extern requests for shutdown, reboot and sysrq | ||
| 3 | */ | ||
| 4 | #include <linux/kernel.h> | ||
| 5 | #include <linux/err.h> | ||
| 6 | #include <linux/reboot.h> | ||
| 7 | #include <linux/sysrq.h> | ||
| 8 | |||
| 9 | #include <xen/xenbus.h> | ||
| 10 | |||
| 11 | #define SHUTDOWN_INVALID -1 | ||
| 12 | #define SHUTDOWN_POWEROFF 0 | ||
| 13 | #define SHUTDOWN_SUSPEND 2 | ||
| 14 | /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only | ||
| 15 | * report a crash, not be instructed to crash! | ||
| 16 | * HALT is the same as POWEROFF, as far as we're concerned. The tools use | ||
| 17 | * the distinction when we return the reason code to them. | ||
| 18 | */ | ||
| 19 | #define SHUTDOWN_HALT 4 | ||
| 20 | |||
| 21 | /* Ignore multiple shutdown requests. */ | ||
| 22 | static int shutting_down = SHUTDOWN_INVALID; | ||
| 23 | |||
| 24 | static void shutdown_handler(struct xenbus_watch *watch, | ||
| 25 | const char **vec, unsigned int len) | ||
| 26 | { | ||
| 27 | char *str; | ||
| 28 | struct xenbus_transaction xbt; | ||
| 29 | int err; | ||
| 30 | |||
| 31 | if (shutting_down != SHUTDOWN_INVALID) | ||
| 32 | return; | ||
| 33 | |||
| 34 | again: | ||
| 35 | err = xenbus_transaction_start(&xbt); | ||
| 36 | if (err) | ||
| 37 | return; | ||
| 38 | |||
| 39 | str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); | ||
| 40 | /* Ignore read errors and empty reads. */ | ||
| 41 | if (XENBUS_IS_ERR_READ(str)) { | ||
| 42 | xenbus_transaction_end(xbt, 1); | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | xenbus_write(xbt, "control", "shutdown", ""); | ||
| 47 | |||
| 48 | err = xenbus_transaction_end(xbt, 0); | ||
| 49 | if (err == -EAGAIN) { | ||
| 50 | kfree(str); | ||
| 51 | goto again; | ||
| 52 | } | ||
| 53 | |||
| 54 | if (strcmp(str, "poweroff") == 0 || | ||
| 55 | strcmp(str, "halt") == 0) | ||
| 56 | orderly_poweroff(false); | ||
| 57 | else if (strcmp(str, "reboot") == 0) | ||
| 58 | ctrl_alt_del(); | ||
| 59 | else { | ||
| 60 | printk(KERN_INFO "Ignoring shutdown request: %s\n", str); | ||
| 61 | shutting_down = SHUTDOWN_INVALID; | ||
| 62 | } | ||
| 63 | |||
| 64 | kfree(str); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void sysrq_handler(struct xenbus_watch *watch, const char **vec, | ||
| 68 | unsigned int len) | ||
| 69 | { | ||
| 70 | char sysrq_key = '\0'; | ||
| 71 | struct xenbus_transaction xbt; | ||
| 72 | int err; | ||
| 73 | |||
| 74 | again: | ||
| 75 | err = xenbus_transaction_start(&xbt); | ||
| 76 | if (err) | ||
| 77 | return; | ||
| 78 | if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { | ||
| 79 | printk(KERN_ERR "Unable to read sysrq code in " | ||
| 80 | "control/sysrq\n"); | ||
| 81 | xenbus_transaction_end(xbt, 1); | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (sysrq_key != '\0') | ||
| 86 | xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); | ||
| 87 | |||
| 88 | err = xenbus_transaction_end(xbt, 0); | ||
| 89 | if (err == -EAGAIN) | ||
| 90 | goto again; | ||
| 91 | |||
| 92 | if (sysrq_key != '\0') | ||
| 93 | handle_sysrq(sysrq_key, NULL); | ||
| 94 | } | ||
| 95 | |||
| 96 | static struct xenbus_watch shutdown_watch = { | ||
| 97 | .node = "control/shutdown", | ||
| 98 | .callback = shutdown_handler | ||
| 99 | }; | ||
| 100 | |||
| 101 | static struct xenbus_watch sysrq_watch = { | ||
| 102 | .node = "control/sysrq", | ||
| 103 | .callback = sysrq_handler | ||
| 104 | }; | ||
| 105 | |||
| 106 | static int setup_shutdown_watcher(void) | ||
| 107 | { | ||
| 108 | int err; | ||
| 109 | |||
| 110 | err = register_xenbus_watch(&shutdown_watch); | ||
| 111 | if (err) { | ||
| 112 | printk(KERN_ERR "Failed to set shutdown watcher\n"); | ||
| 113 | return err; | ||
| 114 | } | ||
| 115 | |||
| 116 | err = register_xenbus_watch(&sysrq_watch); | ||
| 117 | if (err) { | ||
| 118 | printk(KERN_ERR "Failed to set sysrq watcher\n"); | ||
| 119 | return err; | ||
| 120 | } | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int shutdown_event(struct notifier_block *notifier, | ||
| 126 | unsigned long event, | ||
| 127 | void *data) | ||
| 128 | { | ||
| 129 | setup_shutdown_watcher(); | ||
| 130 | return NOTIFY_DONE; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int __init setup_shutdown_event(void) | ||
| 134 | { | ||
| 135 | static struct notifier_block xenstore_notifier = { | ||
| 136 | .notifier_call = shutdown_event | ||
| 137 | }; | ||
| 138 | register_xenstore_notifier(&xenstore_notifier); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | subsys_initcall(setup_shutdown_event); | ||
