Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[deliverable/linux.git] / drivers / xen / manage.c
CommitLineData
3e2b8fbe
JF
1/*
2 * Handle extern requests for shutdown, reboot and sysrq
3 */
4#include <linux/kernel.h>
5#include <linux/err.h>
6#include <linux/reboot.h>
7#include <linux/sysrq.h>
0e91398f
JF
8#include <linux/stop_machine.h>
9#include <linux/freezer.h>
3e2b8fbe
JF
10
11#include <xen/xenbus.h>
0e91398f
JF
12#include <xen/grant_table.h>
13#include <xen/events.h>
14#include <xen/hvc-console.h>
15#include <xen/xen-ops.h>
3e2b8fbe 16
0e91398f
JF
17#include <asm/xen/hypercall.h>
18#include <asm/xen/page.h>
19
20enum shutdown_state {
21 SHUTDOWN_INVALID = -1,
22 SHUTDOWN_POWEROFF = 0,
23 SHUTDOWN_SUSPEND = 2,
24 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
25 report a crash, not be instructed to crash!
26 HALT is the same as POWEROFF, as far as we're concerned. The tools use
27 the distinction when we return the reason code to them. */
28 SHUTDOWN_HALT = 4,
29};
3e2b8fbe
JF
30
31/* Ignore multiple shutdown requests. */
0e91398f
JF
32static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
c7827728 34#ifdef CONFIG_PM_SLEEP
0e91398f
JF
35static int xen_suspend(void *data)
36{
37 int *cancelled = data;
359cdd3f 38 int err;
0e91398f
JF
39
40 BUG_ON(!irqs_disabled());
41
359cdd3f
JF
42 err = device_power_down(PMSG_SUSPEND);
43 if (err) {
44 printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
45 err);
46 return err;
47 }
48
0e91398f
JF
49 xen_mm_pin_all();
50 gnttab_suspend();
0e91398f
JF
51 xen_pre_suspend();
52
53 /*
54 * This hypercall returns 1 if suspend was cancelled
55 * or the domain was merely checkpointed, and 0 if it
56 * is resuming in a new domain.
57 */
58 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
59
60 xen_post_suspend(*cancelled);
0e91398f
JF
61 gnttab_resume();
62 xen_mm_unpin_all();
63
55ca089e 64 device_power_up(PMSG_RESUME);
359cdd3f 65
0e91398f
JF
66 if (!*cancelled) {
67 xen_irq_resume();
68 xen_console_resume();
ad55db9f 69 xen_timer_resume();
0e91398f
JF
70 }
71
72 return 0;
73}
74
75static void do_suspend(void)
76{
77 int err;
78 int cancelled = 1;
79
80 shutting_down = SHUTDOWN_SUSPEND;
81
82#ifdef CONFIG_PREEMPT
83 /* If the kernel is preemptible, we need to freeze all the processes
84 to prevent them from being in the middle of a pagetable update
85 during suspend. */
86 err = freeze_processes();
87 if (err) {
88 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
89 return;
90 }
91#endif
92
93 err = device_suspend(PMSG_SUSPEND);
94 if (err) {
95 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
96 goto out;
97 }
98
99 printk("suspending xenbus...\n");
100 /* XXX use normal device tree? */
101 xenbus_suspend();
102
37a7c0f3 103 err = stop_machine(xen_suspend, &cancelled, &cpumask_of_cpu(0));
0e91398f
JF
104 if (err) {
105 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
106 goto out;
107 }
108
ad55db9f
IY
109 if (!cancelled) {
110 xen_arch_resume();
0e91398f 111 xenbus_resume();
ad55db9f 112 } else
0e91398f
JF
113 xenbus_suspend_cancel();
114
55ca089e 115 device_resume(PMSG_RESUME);
0e91398f 116
359cdd3f
JF
117 /* Make sure timer events get retriggered on all CPUs */
118 clock_was_set();
0e91398f
JF
119out:
120#ifdef CONFIG_PREEMPT
121 thaw_processes();
122#endif
123 shutting_down = SHUTDOWN_INVALID;
124}
c7827728 125#endif /* CONFIG_PM_SLEEP */
3e2b8fbe
JF
126
127static void shutdown_handler(struct xenbus_watch *watch,
128 const char **vec, unsigned int len)
129{
130 char *str;
131 struct xenbus_transaction xbt;
132 int err;
133
134 if (shutting_down != SHUTDOWN_INVALID)
135 return;
136
137 again:
138 err = xenbus_transaction_start(&xbt);
139 if (err)
140 return;
141
142 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
143 /* Ignore read errors and empty reads. */
144 if (XENBUS_IS_ERR_READ(str)) {
145 xenbus_transaction_end(xbt, 1);
146 return;
147 }
148
149 xenbus_write(xbt, "control", "shutdown", "");
150
151 err = xenbus_transaction_end(xbt, 0);
152 if (err == -EAGAIN) {
153 kfree(str);
154 goto again;
155 }
156
157 if (strcmp(str, "poweroff") == 0 ||
0e91398f
JF
158 strcmp(str, "halt") == 0) {
159 shutting_down = SHUTDOWN_POWEROFF;
3e2b8fbe 160 orderly_poweroff(false);
0e91398f
JF
161 } else if (strcmp(str, "reboot") == 0) {
162 shutting_down = SHUTDOWN_POWEROFF; /* ? */
3e2b8fbe 163 ctrl_alt_del();
0e91398f
JF
164#ifdef CONFIG_PM_SLEEP
165 } else if (strcmp(str, "suspend") == 0) {
166 do_suspend();
167#endif
168 } else {
3e2b8fbe
JF
169 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
170 shutting_down = SHUTDOWN_INVALID;
171 }
172
173 kfree(str);
174}
175
176static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
177 unsigned int len)
178{
179 char sysrq_key = '\0';
180 struct xenbus_transaction xbt;
181 int err;
182
183 again:
184 err = xenbus_transaction_start(&xbt);
185 if (err)
186 return;
187 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
188 printk(KERN_ERR "Unable to read sysrq code in "
189 "control/sysrq\n");
190 xenbus_transaction_end(xbt, 1);
191 return;
192 }
193
194 if (sysrq_key != '\0')
195 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
196
197 err = xenbus_transaction_end(xbt, 0);
198 if (err == -EAGAIN)
199 goto again;
200
201 if (sysrq_key != '\0')
202 handle_sysrq(sysrq_key, NULL);
203}
204
205static struct xenbus_watch shutdown_watch = {
206 .node = "control/shutdown",
207 .callback = shutdown_handler
208};
209
210static struct xenbus_watch sysrq_watch = {
211 .node = "control/sysrq",
212 .callback = sysrq_handler
213};
214
215static int setup_shutdown_watcher(void)
216{
217 int err;
218
219 err = register_xenbus_watch(&shutdown_watch);
220 if (err) {
221 printk(KERN_ERR "Failed to set shutdown watcher\n");
222 return err;
223 }
224
225 err = register_xenbus_watch(&sysrq_watch);
226 if (err) {
227 printk(KERN_ERR "Failed to set sysrq watcher\n");
228 return err;
229 }
230
231 return 0;
232}
233
234static int shutdown_event(struct notifier_block *notifier,
235 unsigned long event,
236 void *data)
237{
238 setup_shutdown_watcher();
239 return NOTIFY_DONE;
240}
241
242static int __init setup_shutdown_event(void)
243{
244 static struct notifier_block xenstore_notifier = {
245 .notifier_call = shutdown_event
246 };
247 register_xenstore_notifier(&xenstore_notifier);
248
249 return 0;
250}
251
252subsys_initcall(setup_shutdown_event);
This page took 0.281036 seconds and 5 git commands to generate.