manage.c revision 1f112cee07b314e244ee9e71d9c1e6950dc13327
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
12016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini#include <xen/xen.h>
133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <xen/xenbus.h>
140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/grant_table.h>
150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/events.h>
160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/hvc-console.h>
170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/xen-ops.h>
183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/hypercall.h>
200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/page.h>
21016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini#include <asm/xen/hypervisor.h>
220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
230e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeenum shutdown_state {
240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_INVALID = -1,
250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_POWEROFF = 0,
260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	SHUTDOWN_SUSPEND = 2,
270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   report a crash, not be instructed to crash!
290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
300e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   the distinction when we return the reason code to them.  */
310e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 SHUTDOWN_HALT = 4,
320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge};
333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* Ignore multiple shutdown requests. */
350e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic enum shutdown_state shutting_down = SHUTDOWN_INVALID;
360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
37ceb180294790c8a6a437533488616f6b591b49d0Ian Campbellstruct suspend_info {
38ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell	int cancelled;
3936b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell	unsigned long arg; /* extra hypercall argument */
4055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	void (*pre)(void);
4155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	void (*post)(int cancelled);
42ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell};
43ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell
4407af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbellstatic void xen_hvm_post_suspend(int cancelled)
4582043bb60d24d2897074905c94be5a53071e8913Ian Campbell{
4607af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell	xen_arch_hvm_post_suspend(cancelled);
4782043bb60d24d2897074905c94be5a53071e8913Ian Campbell	gnttab_resume();
4882043bb60d24d2897074905c94be5a53071e8913Ian Campbell}
4982043bb60d24d2897074905c94be5a53071e8913Ian Campbell
5082043bb60d24d2897074905c94be5a53071e8913Ian Campbellstatic void xen_pre_suspend(void)
5182043bb60d24d2897074905c94be5a53071e8913Ian Campbell{
5282043bb60d24d2897074905c94be5a53071e8913Ian Campbell	xen_mm_pin_all();
5382043bb60d24d2897074905c94be5a53071e8913Ian Campbell	gnttab_suspend();
5407af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell	xen_arch_pre_suspend();
5582043bb60d24d2897074905c94be5a53071e8913Ian Campbell}
5682043bb60d24d2897074905c94be5a53071e8913Ian Campbell
5707af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbellstatic void xen_post_suspend(int cancelled)
5882043bb60d24d2897074905c94be5a53071e8913Ian Campbell{
5907af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell	xen_arch_post_suspend(cancelled);
6082043bb60d24d2897074905c94be5a53071e8913Ian Campbell	gnttab_resume();
6182043bb60d24d2897074905c94be5a53071e8913Ian Campbell	xen_mm_unpin_all();
6282043bb60d24d2897074905c94be5a53071e8913Ian Campbell}
6382043bb60d24d2897074905c94be5a53071e8913Ian Campbell
641f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#ifdef CONFIG_HIBERNATE_CALLBACKS
65016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellinistatic int xen_suspend(void *data)
66016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini{
67ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell	struct suspend_info *si = data;
68359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	int err;
690e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	BUG_ON(!irqs_disabled());
710e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
72b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan	err = sysdev_suspend(PMSG_FREEZE);
73770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	if (err) {
74770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
75770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki			err);
76770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki		return err;
77770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki	}
78359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge
7955fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	if (si->pre)
8055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell		si->pre();
810e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
820e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/*
830e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * This hypercall returns 1 if suspend was cancelled
840e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * or the domain was merely checkpointed, and 0 if it
850e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 * is resuming in a new domain.
860e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	 */
8736b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell	si->cancelled = HYPERVISOR_suspend(si->arg);
880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
8955fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	if (si->post)
9055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell		si->post(si->cancelled);
910e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
92ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell	if (!si->cancelled) {
930e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_irq_resume();
940e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		xen_console_resume();
95ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_timer_resume();
960e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
970e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
981e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell	sysdev_resume();
991e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell
1000e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	return 0;
1010e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
1020e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
1030e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic void do_suspend(void)
1040e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{
1050e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	int err;
106ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell	struct suspend_info si;
1070e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
1080e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_SUSPEND;
1090e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
1100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
1110e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	/* If the kernel is preemptible, we need to freeze all the processes
1120e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   to prevent them from being in the middle of a pagetable update
1130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	   during suspend. */
1140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	err = freeze_processes();
1150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
1160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
1173fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo		goto out;
1180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif
1200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
121b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan	err = dpm_suspend_start(PMSG_FREEZE);
1220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
123d161630297a20802d01c55847bfcba85d2118a9fAlan Stern		printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
12465f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		goto out_thaw;
1250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
127c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell	printk(KERN_DEBUG "suspending xenstore...\n");
128c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell	xs_suspend();
129c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell
130b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan	err = dpm_suspend_noirq(PMSG_FREEZE);
1312ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki	if (err) {
132d161630297a20802d01c55847bfcba85d2118a9fAlan Stern		printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
13365f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell		goto out_resume;
1342ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki	}
1352ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki
136ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell	si.cancelled = 1;
137ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell
13855fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	if (xen_hvm_domain()) {
13936b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell		si.arg = 0UL;
14055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell		si.pre = NULL;
14155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell		si.post = &xen_hvm_post_suspend;
14255fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	} else {
14336b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell		si.arg = virt_to_mfn(xen_start_info);
14455fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell		si.pre = &xen_pre_suspend;
14555fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell		si.post = &xen_post_suspend;
14655fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell	}
14736b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell
148b056b6a0144de90707cd22cf7b4f60bf69c86d59Ian Campbell	err = stop_machine(xen_suspend, &si, cpumask_of(0));
149922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge
150b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan	dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
151922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge
1520e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	if (err) {
1530e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge		printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
154ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell		si.cancelled = 1;
1550e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	}
1560e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
157c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbellout_resume:
158ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell	if (!si.cancelled) {
159ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata		xen_arch_resume();
160de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell		xs_resume();
161ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata	} else
162de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell		xs_suspend_cancel();
1630e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
164b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan	dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
1650e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge
166359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	/* Make sure timer events get retriggered on all CPUs */
167359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge	clock_was_set();
16865f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell
16965f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout_thaw:
1700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT
1710e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	thaw_processes();
17265f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout:
1733fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo#endif
1740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	shutting_down = SHUTDOWN_INVALID;
1750e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}
1761f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#endif	/* CONFIG_HIBERNATE_CALLBACKS */
1773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
178552717231e50b478dfd19d63fd97879476ae051dIan Campbellstruct shutdown_handler {
179552717231e50b478dfd19d63fd97879476ae051dIan Campbell	const char *command;
180552717231e50b478dfd19d63fd97879476ae051dIan Campbell	void (*cb)(void);
181552717231e50b478dfd19d63fd97879476ae051dIan Campbell};
182552717231e50b478dfd19d63fd97879476ae051dIan Campbell
183552717231e50b478dfd19d63fd97879476ae051dIan Campbellstatic void do_poweroff(void)
184552717231e50b478dfd19d63fd97879476ae051dIan Campbell{
185552717231e50b478dfd19d63fd97879476ae051dIan Campbell	shutting_down = SHUTDOWN_POWEROFF;
186552717231e50b478dfd19d63fd97879476ae051dIan Campbell	orderly_poweroff(false);
187552717231e50b478dfd19d63fd97879476ae051dIan Campbell}
188552717231e50b478dfd19d63fd97879476ae051dIan Campbell
189552717231e50b478dfd19d63fd97879476ae051dIan Campbellstatic void do_reboot(void)
190552717231e50b478dfd19d63fd97879476ae051dIan Campbell{
191552717231e50b478dfd19d63fd97879476ae051dIan Campbell	shutting_down = SHUTDOWN_POWEROFF; /* ? */
192552717231e50b478dfd19d63fd97879476ae051dIan Campbell	ctrl_alt_del();
193552717231e50b478dfd19d63fd97879476ae051dIan Campbell}
194552717231e50b478dfd19d63fd97879476ae051dIan Campbell
1953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void shutdown_handler(struct xenbus_watch *watch,
1963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			     const char **vec, unsigned int len)
1973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
1983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char *str;
1993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
2003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
201552717231e50b478dfd19d63fd97879476ae051dIan Campbell	static struct shutdown_handler handlers[] = {
202552717231e50b478dfd19d63fd97879476ae051dIan Campbell		{ "poweroff",	do_poweroff },
203552717231e50b478dfd19d63fd97879476ae051dIan Campbell		{ "halt",	do_poweroff },
204552717231e50b478dfd19d63fd97879476ae051dIan Campbell		{ "reboot",	do_reboot   },
2051f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#ifdef CONFIG_HIBERNATE_CALLBACKS
206552717231e50b478dfd19d63fd97879476ae051dIan Campbell		{ "suspend",	do_suspend  },
207552717231e50b478dfd19d63fd97879476ae051dIan Campbell#endif
208552717231e50b478dfd19d63fd97879476ae051dIan Campbell		{NULL, NULL},
209552717231e50b478dfd19d63fd97879476ae051dIan Campbell	};
210552717231e50b478dfd19d63fd97879476ae051dIan Campbell	static struct shutdown_handler *handler;
2113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (shutting_down != SHUTDOWN_INVALID)
2133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
2163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
2173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
2183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
2213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	/* Ignore read errors and empty reads. */
2223e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (XENBUS_IS_ERR_READ(str)) {
2233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
2243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
227552717231e50b478dfd19d63fd97879476ae051dIan Campbell	for (handler = &handlers[0]; handler->command; handler++) {
228552717231e50b478dfd19d63fd97879476ae051dIan Campbell		if (strcmp(str, handler->command) == 0)
229552717231e50b478dfd19d63fd97879476ae051dIan Campbell			break;
230552717231e50b478dfd19d63fd97879476ae051dIan Campbell	}
231552717231e50b478dfd19d63fd97879476ae051dIan Campbell
232552717231e50b478dfd19d63fd97879476ae051dIan Campbell	/* Only acknowledge commands which we are prepared to handle. */
233552717231e50b478dfd19d63fd97879476ae051dIan Campbell	if (handler->cb)
234552717231e50b478dfd19d63fd97879476ae051dIan Campbell		xenbus_write(xbt, "control", "shutdown", "");
2353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
2373e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN) {
2383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		kfree(str);
2393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
2403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
242552717231e50b478dfd19d63fd97879476ae051dIan Campbell	if (handler->cb) {
243552717231e50b478dfd19d63fd97879476ae051dIan Campbell		handler->cb();
2440e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge	} else {
2453e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
2463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		shutting_down = SHUTDOWN_INVALID;
2473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	kfree(str);
2503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
252f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ
2533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void sysrq_handler(struct xenbus_watch *watch, const char **vec,
2543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned int len)
2553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	char sysrq_key = '\0';
2573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	struct xenbus_transaction xbt;
2583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
2593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again:
2613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_start(&xbt);
2623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err)
2633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
2653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Unable to read sysrq code in "
2663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		       "control/sysrq\n");
2673e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_transaction_end(xbt, 1);
2683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return;
2693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
2703e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2713e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
2723e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
2733e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2743e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = xenbus_transaction_end(xbt, 0);
2753e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err == -EAGAIN)
2763e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		goto again;
2773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2783e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (sysrq_key != '\0')
279f335397d177c906256ee1bba28e8c49e8ec63817Dmitry Torokhov		handle_sysrq(sysrq_key);
2803e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
2813e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2823e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch sysrq_watch = {
2833e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.node = "control/sysrq",
2843e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	.callback = sysrq_handler
2853e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge};
286f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif
287f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap
288f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlapstatic struct xenbus_watch shutdown_watch = {
289f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap	.node = "control/shutdown",
290f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap	.callback = shutdown_handler
291f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap};
2923e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2933e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int setup_shutdown_watcher(void)
2943e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
2953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	int err;
2963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
2973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&shutdown_watch);
2983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
2993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set shutdown watcher\n");
3003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
3013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
3023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
303f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ
3043e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	err = register_xenbus_watch(&sysrq_watch);
3053e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	if (err) {
3063e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		printk(KERN_ERR "Failed to set sysrq watcher\n");
3073e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		return err;
3083e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	}
309f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif
3103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
3113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
3123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
3133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
3143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int shutdown_event(struct notifier_block *notifier,
3153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  unsigned long event,
3163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge			  void *data)
3173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
3183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	setup_shutdown_watcher();
3193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return NOTIFY_DONE;
3203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
3213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
322016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabelliniint xen_setup_shutdown_event(void)
3233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{
3243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	static struct notifier_block xenstore_notifier = {
3253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge		.notifier_call = shutdown_event
3263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	};
327702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini
328702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini	if (!xen_domain())
329702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini		return -ENODEV;
3303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	register_xenstore_notifier(&xenstore_notifier);
3313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
3323e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge	return 0;
3333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}
334183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3cStefano StabelliniEXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
3353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge
336702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellinisubsys_initcall(xen_setup_shutdown_event);
337