manage.c revision 183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3c
13e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/*
23e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge * Handle extern requests for shutdown, reboot and sysrq
33e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge */
43e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/kernel.h>
53e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/err.h>
65a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
73e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/reboot.h>
83e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/sysrq.h>
90e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/stop_machine.h>
100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/freezer.h>
113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <xen/xenbus.h>
130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/grant_table.h>
140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/events.h>
150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/hvc-console.h>
160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/xen-ops.h>
173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/hypercall.h>
190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/page.h>
200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeenum shutdown_state {
220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_INVALID = -1,
230e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_POWEROFF = 0,
240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_SUSPEND = 2,
250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   report a crash, not be instructed to crash!
270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   the distinction when we return the reason code to them.  */
290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 SHUTDOWN_HALT = 4,
300e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge};
313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
323e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* Ignore multiple shutdown requests. */
330e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic enum shutdown_state shutting_down = SHUTDOWN_INVALID;
340e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
35c78277288e3d561d55fb48bc0fe8d6e2cf4d0880Jeremy Fitzhardinge#ifdef CONFIG_PM_SLEEP
360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic int xen_suspend(void *data)
370e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
380e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int *cancelled = data;
39359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	int err;
400e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
410e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	BUG_ON(!irqs_disabled());
420e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
43770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	err = sysdev_suspend(PMSG_SUSPEND);
44770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	if (err) {
45770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
46770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki			err);
47770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		return err;
48770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	}
49359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge
500e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_mm_pin_all();
510e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	gnttab_suspend();
520e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_pre_suspend();
530e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
540e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/*
550e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * This hypercall returns 1 if suspend was cancelled
560e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * or the domain was merely checkpointed, and 0 if it
570e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * is resuming in a new domain.
580e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 */
590e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	*cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
600e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
610e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_post_suspend(*cancelled);
620e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	gnttab_resume();
630e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_mm_unpin_all();
640e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
650e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (!*cancelled) {
660e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_irq_resume();
670e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_console_resume();
68ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_timer_resume();
690e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
711e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell	sysdev_resume();
721e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell
730e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	return 0;
740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
750e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
760e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic void do_suspend(void)
770e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
780e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int err;
790e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int cancelled = 1;
800e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
810e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_SUSPEND;
820e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
830e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
840e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* If the kernel is preemptible, we need to freeze all the processes
850e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   to prevent them from being in the middle of a pagetable update
860e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   during suspend. */
870e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	err = freeze_processes();
880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
890e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
903fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo		goto out;
910e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
920e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
930e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
94d161630297a20802d01c55847bfcba85d2118a9fAlan Stern	err = dpm_suspend_start(PMSG_SUSPEND);
950e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
96d161630297a20802d01c55847bfcba85d2118a9fAlan Stern		printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
9765f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		goto out_thaw;
980e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
990e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
100c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell	printk(KERN_DEBUG "suspending xenstore...\n");
101c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell	xs_suspend();
102c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell
103d161630297a20802d01c55847bfcba85d2118a9fAlan Stern	err = dpm_suspend_noirq(PMSG_SUSPEND);
1042ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki	if (err) {
105d161630297a20802d01c55847bfcba85d2118a9fAlan Stern		printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
10665f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		goto out_resume;
1072ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki	}
1082ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki
109f7df8ed164996cd2c6aca9674388be6ef78d8b37Rusty Russell	err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
110922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge
111922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge	dpm_resume_noirq(PMSG_RESUME);
112922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge
1130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
1140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
11565f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		cancelled = 1;
1160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
118c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbellout_resume:
119ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	if (!cancelled) {
120ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_arch_resume();
121de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell		xs_resume();
122ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	} else
123de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell		xs_suspend_cancel();
1240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
125d161630297a20802d01c55847bfcba85d2118a9fAlan Stern	dpm_resume_end(PMSG_RESUME);
1260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
127359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	/* Make sure timer events get retriggered on all CPUs */
128359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	clock_was_set();
12965f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell
13065f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout_thaw:
1310e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
1320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	thaw_processes();
13365f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout:
1343fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo#endif
1350e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_INVALID;
1360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
137c78277288e3d561d55fb48bc0fe8d6e2cf4d0880Jeremy Fitzhardinge#endif	/* CONFIG_PM_SLEEP */
1383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void shutdown_handler(struct xenbus_watch *watch,
1403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			     const char **vec, unsigned int len)
1413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
1423e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char *str;
1433e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
1443e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
1453e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (shutting_down != SHUTDOWN_INVALID)
1473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
1503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
1513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
1523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
1553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	/* Ignore read errors and empty reads. */
1563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (XENBUS_IS_ERR_READ(str)) {
1573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
1583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	xenbus_write(xbt, "control", "shutdown", "");
1623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
1643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN) {
1653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		kfree(str);
1663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
1673e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (strcmp(str, "poweroff") == 0 ||
1700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	    strcmp(str, "halt") == 0) {
1710e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		shutting_down = SHUTDOWN_POWEROFF;
1723e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		orderly_poweroff(false);
1730e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else if (strcmp(str, "reboot") == 0) {
1740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		shutting_down = SHUTDOWN_POWEROFF; /* ? */
1753e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		ctrl_alt_del();
1760e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PM_SLEEP
1770e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else if (strcmp(str, "suspend") == 0) {
1780e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		do_suspend();
1790e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
1800e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else {
1813e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
1823e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		shutting_down = SHUTDOWN_INVALID;
1833e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1843e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1853e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	kfree(str);
1863e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
1873e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
188f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ
1893e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void sysrq_handler(struct xenbus_watch *watch, const char **vec,
1903e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned int len)
1913e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
1923e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char sysrq_key = '\0';
1933e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
1943e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
1953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
1973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
1983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
1993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
2013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Unable to read sysrq code in "
2023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		       "control/sysrq\n");
2033e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
2043e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2053e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2063e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2073e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2083e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
2093e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
2113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN)
2123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
2133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		handle_sysrq(sysrq_key, NULL);
2163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch sysrq_watch = {
2193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.node = "control/sysrq",
2203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.callback = sysrq_handler
2213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge};
222f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif
223f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap
224f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlapstatic struct xenbus_watch shutdown_watch = {
225f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap	.node = "control/shutdown",
226f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap	.callback = shutdown_handler
227f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap};
2283e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2293e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int setup_shutdown_watcher(void)
2303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
2323e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&shutdown_watch);
2343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set shutdown watcher\n");
2363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
2373e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
239f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ
2403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&sysrq_watch);
2413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2423e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set sysrq watcher\n");
2433e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
2443e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
245f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif
2463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
2483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int shutdown_event(struct notifier_block *notifier,
2513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned long event,
2523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  void *data)
2533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	setup_shutdown_watcher();
2553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return NOTIFY_DONE;
2563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int __init setup_shutdown_event(void)
2593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	static struct notifier_block xenstore_notifier = {
2613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		.notifier_call = shutdown_event
2623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	};
2633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	register_xenstore_notifier(&xenstore_notifier);
2643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
2663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
267183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3cStefano StabelliniEXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
2683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingesubsys_initcall(setup_shutdown_event);
270