-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Jeremy Fitzhardinge
authored and
Jeremy Fitzhardinge
committed
Jul 18, 2007
1 parent
fefa629
commit 3e2b8fb
Showing
2 changed files
with
144 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \ | ||
events.o time.o | ||
events.o time.o manage.o | ||
|
||
obj-$(CONFIG_SMP) += smp.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
* Handle extern requests for shutdown, reboot and sysrq | ||
*/ | ||
#include <linux/kernel.h> | ||
#include <linux/err.h> | ||
#include <linux/reboot.h> | ||
#include <linux/sysrq.h> | ||
|
||
#include <xen/xenbus.h> | ||
|
||
#define SHUTDOWN_INVALID -1 | ||
#define SHUTDOWN_POWEROFF 0 | ||
#define SHUTDOWN_SUSPEND 2 | ||
/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only | ||
* report a crash, not be instructed to crash! | ||
* HALT is the same as POWEROFF, as far as we're concerned. The tools use | ||
* the distinction when we return the reason code to them. | ||
*/ | ||
#define SHUTDOWN_HALT 4 | ||
|
||
/* Ignore multiple shutdown requests. */ | ||
static int shutting_down = SHUTDOWN_INVALID; | ||
|
||
static void shutdown_handler(struct xenbus_watch *watch, | ||
const char **vec, unsigned int len) | ||
{ | ||
char *str; | ||
struct xenbus_transaction xbt; | ||
int err; | ||
|
||
if (shutting_down != SHUTDOWN_INVALID) | ||
return; | ||
|
||
again: | ||
err = xenbus_transaction_start(&xbt); | ||
if (err) | ||
return; | ||
|
||
str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); | ||
/* Ignore read errors and empty reads. */ | ||
if (XENBUS_IS_ERR_READ(str)) { | ||
xenbus_transaction_end(xbt, 1); | ||
return; | ||
} | ||
|
||
xenbus_write(xbt, "control", "shutdown", ""); | ||
|
||
err = xenbus_transaction_end(xbt, 0); | ||
if (err == -EAGAIN) { | ||
kfree(str); | ||
goto again; | ||
} | ||
|
||
if (strcmp(str, "poweroff") == 0 || | ||
strcmp(str, "halt") == 0) | ||
orderly_poweroff(false); | ||
else if (strcmp(str, "reboot") == 0) | ||
ctrl_alt_del(); | ||
else { | ||
printk(KERN_INFO "Ignoring shutdown request: %s\n", str); | ||
shutting_down = SHUTDOWN_INVALID; | ||
} | ||
|
||
kfree(str); | ||
} | ||
|
||
static void sysrq_handler(struct xenbus_watch *watch, const char **vec, | ||
unsigned int len) | ||
{ | ||
char sysrq_key = '\0'; | ||
struct xenbus_transaction xbt; | ||
int err; | ||
|
||
again: | ||
err = xenbus_transaction_start(&xbt); | ||
if (err) | ||
return; | ||
if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { | ||
printk(KERN_ERR "Unable to read sysrq code in " | ||
"control/sysrq\n"); | ||
xenbus_transaction_end(xbt, 1); | ||
return; | ||
} | ||
|
||
if (sysrq_key != '\0') | ||
xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); | ||
|
||
err = xenbus_transaction_end(xbt, 0); | ||
if (err == -EAGAIN) | ||
goto again; | ||
|
||
if (sysrq_key != '\0') | ||
handle_sysrq(sysrq_key, NULL); | ||
} | ||
|
||
static struct xenbus_watch shutdown_watch = { | ||
.node = "control/shutdown", | ||
.callback = shutdown_handler | ||
}; | ||
|
||
static struct xenbus_watch sysrq_watch = { | ||
.node = "control/sysrq", | ||
.callback = sysrq_handler | ||
}; | ||
|
||
static int setup_shutdown_watcher(void) | ||
{ | ||
int err; | ||
|
||
err = register_xenbus_watch(&shutdown_watch); | ||
if (err) { | ||
printk(KERN_ERR "Failed to set shutdown watcher\n"); | ||
return err; | ||
} | ||
|
||
err = register_xenbus_watch(&sysrq_watch); | ||
if (err) { | ||
printk(KERN_ERR "Failed to set sysrq watcher\n"); | ||
return err; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int shutdown_event(struct notifier_block *notifier, | ||
unsigned long event, | ||
void *data) | ||
{ | ||
setup_shutdown_watcher(); | ||
return NOTIFY_DONE; | ||
} | ||
|
||
static int __init setup_shutdown_event(void) | ||
{ | ||
static struct notifier_block xenstore_notifier = { | ||
.notifier_call = shutdown_event | ||
}; | ||
register_xenstore_notifier(&xenstore_notifier); | ||
|
||
return 0; | ||
} | ||
|
||
subsys_initcall(setup_shutdown_event); |