manage.c revision c5cae661d6cf808b6984762f763261adf35f3eb7
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>
63e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/reboot.h>
73e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/sysrq.h>
80e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/stop_machine.h>
90e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/freezer.h>
103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <xen/xenbus.h>
120e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/grant_table.h>
130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/events.h>
140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/hvc-console.h>
150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/xen-ops.h>
163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/hypercall.h>
180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/page.h>
190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeenum shutdown_state {
210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_INVALID = -1,
220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_POWEROFF = 0,
230e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_SUSPEND = 2,
240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   report a crash, not be instructed to crash!
260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   the distinction when we return the reason code to them.  */
280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 SHUTDOWN_HALT = 4,
290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge};
303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* Ignore multiple shutdown requests. */
320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic enum shutdown_state shutting_down = SHUTDOWN_INVALID;
330e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
34c78277288e3d561d55fb48bc0fe8d6e2cf4d0880Jeremy Fitzhardinge#ifdef CONFIG_PM_SLEEP
350e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic int xen_suspend(void *data)
360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
370e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int *cancelled = data;
38359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	int err;
390e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
400e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	BUG_ON(!irqs_disabled());
410e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
42770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	err = sysdev_suspend(PMSG_SUSPEND);
43770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	if (err) {
44770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
45770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki			err);
46770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		return err;
47770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	}
48359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge
490e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_mm_pin_all();
500e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	gnttab_suspend();
510e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_pre_suspend();
520e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
530e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/*
540e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * This hypercall returns 1 if suspend was cancelled
550e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * or the domain was merely checkpointed, and 0 if it
560e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * is resuming in a new domain.
570e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 */
580e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	*cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
590e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
600e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_post_suspend(*cancelled);
610e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	gnttab_resume();
620e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	xen_mm_unpin_all();
630e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
640e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (!*cancelled) {
650e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_irq_resume();
660e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_console_resume();
67ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_timer_resume();
680e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
690e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
701e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell	sysdev_resume();
711e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell
720e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	return 0;
730e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
750e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic void do_suspend(void)
760e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
770e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int err;
780e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int cancelled = 1;
790e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
800e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_SUSPEND;
810e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
82b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell	err = stop_machine_create();
83b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell	if (err) {
84b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell		printk(KERN_ERR "xen suspend: failed to setup stop_machine %d\n", err);
85b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell		goto out;
86b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell	}
87b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell
880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
890e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* If the kernel is preemptible, we need to freeze all the processes
900e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   to prevent them from being in the middle of a pagetable update
910e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   during suspend. */
920e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	err = freeze_processes();
930e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
940e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
95b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell		goto out_destroy_sm;
960e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
970e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
980e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
99d161630297a20802d01c55847bfcba85d2118a9fAlan Stern	err = dpm_suspend_start(PMSG_SUSPEND);
1000e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
101d161630297a20802d01c55847bfcba85d2118a9fAlan Stern		printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
10265f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		goto out_thaw;
1030e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1040e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
105c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell	printk(KERN_DEBUG "suspending xenstore...\n");
106c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell	xs_suspend();
107c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell
108d161630297a20802d01c55847bfcba85d2118a9fAlan Stern	err = dpm_suspend_noirq(PMSG_SUSPEND);
1092ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki	if (err) {
110d161630297a20802d01c55847bfcba85d2118a9fAlan Stern		printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
11165f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		goto out_resume;
1122ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki	}
1132ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki
114f7df8ed164996cd2c6aca9674388be6ef78d8b37Rusty Russell	err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
115922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge
116922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge	dpm_resume_noirq(PMSG_RESUME);
117922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge
1180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
1190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
12065f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		cancelled = 1;
1210e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
123c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbellout_resume:
124ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	if (!cancelled) {
125ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_arch_resume();
126de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell		xs_resume();
127ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	} else
128de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell		xs_suspend_cancel();
1290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
130d161630297a20802d01c55847bfcba85d2118a9fAlan Stern	dpm_resume_end(PMSG_RESUME);
1310e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
132359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	/* Make sure timer events get retriggered on all CPUs */
133359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	clock_was_set();
13465f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell
13565f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout_thaw:
1360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
1370e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	thaw_processes();
138b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell
139b4606f2165153833247823e8c04c5e88cb3d298bIan Campbellout_destroy_sm:
1400e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
141b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell	stop_machine_destroy();
142b4606f2165153833247823e8c04c5e88cb3d298bIan Campbell
14365f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout:
1440e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_INVALID;
1450e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
146c78277288e3d561d55fb48bc0fe8d6e2cf4d0880Jeremy Fitzhardinge#endif	/* CONFIG_PM_SLEEP */
1473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void shutdown_handler(struct xenbus_watch *watch,
1493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			     const char **vec, unsigned int len)
1503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
1513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char *str;
1523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
1533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
1543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (shutting_down != SHUTDOWN_INVALID)
1563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
1593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
1603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
1613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
1643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	/* Ignore read errors and empty reads. */
1653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (XENBUS_IS_ERR_READ(str)) {
1663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
1673e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
1683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1703e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	xenbus_write(xbt, "control", "shutdown", "");
1713e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1723e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
1733e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN) {
1743e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		kfree(str);
1753e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
1763e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1783e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (strcmp(str, "poweroff") == 0 ||
1790e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	    strcmp(str, "halt") == 0) {
1800e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		shutting_down = SHUTDOWN_POWEROFF;
1813e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		orderly_poweroff(false);
1820e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else if (strcmp(str, "reboot") == 0) {
1830e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		shutting_down = SHUTDOWN_POWEROFF; /* ? */
1843e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		ctrl_alt_del();
1850e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PM_SLEEP
1860e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else if (strcmp(str, "suspend") == 0) {
1870e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		do_suspend();
1880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
1890e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else {
1903e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
1913e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		shutting_down = SHUTDOWN_INVALID;
1923e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
1933e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1943e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	kfree(str);
1953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
1963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
1973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void sysrq_handler(struct xenbus_watch *watch, const char **vec,
1983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned int len)
1993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char sysrq_key = '\0';
2013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
2023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
2033e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2043e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
2053e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
2063e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
2073e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2083e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
2093e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Unable to read sysrq code in "
2103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		       "control/sysrq\n");
2113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
2123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
2173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
2193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN)
2203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
2213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2223e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		handle_sysrq(sysrq_key, NULL);
2243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch shutdown_watch = {
2273e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.node = "control/shutdown",
2283e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.callback = shutdown_handler
2293e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge};
2303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch sysrq_watch = {
2323e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.node = "control/sysrq",
2333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.callback = sysrq_handler
2343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge};
2353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int setup_shutdown_watcher(void)
2373e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
2393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&shutdown_watch);
2413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2423e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set shutdown watcher\n");
2433e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
2443e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2453e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&sysrq_watch);
2473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set sysrq watcher\n");
2493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
2503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2523e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
2533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int shutdown_event(struct notifier_block *notifier,
2563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned long event,
2573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  void *data)
2583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	setup_shutdown_watcher();
2603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return NOTIFY_DONE;
2613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int __init setup_shutdown_event(void)
2643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	static struct notifier_block xenstore_notifier = {
2663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		.notifier_call = shutdown_event
2673e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	};
2683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	register_xenstore_notifier(&xenstore_notifier);
2693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2703e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
2713e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2723e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2733e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingesubsys_initcall(setup_shutdown_event);
274