Skip to content

Commit

Permalink
xen: handle external requests for shutdown, reboot and sysrq
Browse files Browse the repository at this point in the history
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
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
2 changes: 1 addition & 1 deletion arch/i386/xen/Makefile
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
143 changes: 143 additions & 0 deletions arch/i386/xen/manage.c
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);

0 comments on commit 3e2b8fb

Please sign in to comment.