Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[deliverable/linux.git] / drivers / xen / manage.c
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>
8 #include <linux/stop_machine.h>
9 #include <linux/freezer.h>
10
11 #include <xen/xenbus.h>
12 #include <xen/grant_table.h>
13 #include <xen/events.h>
14 #include <xen/hvc-console.h>
15 #include <xen/xen-ops.h>
16
17 #include <asm/xen/hypercall.h>
18 #include <asm/xen/page.h>
19
20 enum 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 };
30
31 /* Ignore multiple shutdown requests. */
32 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
34 #ifdef CONFIG_PM_SLEEP
35 static int xen_suspend(void *data)
36 {
37 int *cancelled = data;
38 int err;
39
40 BUG_ON(!irqs_disabled());
41
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
49 xen_mm_pin_all();
50 gnttab_suspend();
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);
61 gnttab_resume();
62 xen_mm_unpin_all();
63
64 device_power_up(PMSG_RESUME);
65
66 if (!*cancelled) {
67 xen_irq_resume();
68 xen_console_resume();
69 xen_timer_resume();
70 }
71
72 return 0;
73 }
74
75 static 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
103 err = stop_machine(xen_suspend, &cancelled, &cpumask_of_cpu(0));
104 if (err) {
105 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
106 goto out;
107 }
108
109 if (!cancelled) {
110 xen_arch_resume();
111 xenbus_resume();
112 } else
113 xenbus_suspend_cancel();
114
115 device_resume(PMSG_RESUME);
116
117 /* Make sure timer events get retriggered on all CPUs */
118 clock_was_set();
119 out:
120 #ifdef CONFIG_PREEMPT
121 thaw_processes();
122 #endif
123 shutting_down = SHUTDOWN_INVALID;
124 }
125 #endif /* CONFIG_PM_SLEEP */
126
127 static 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 ||
158 strcmp(str, "halt") == 0) {
159 shutting_down = SHUTDOWN_POWEROFF;
160 orderly_poweroff(false);
161 } else if (strcmp(str, "reboot") == 0) {
162 shutting_down = SHUTDOWN_POWEROFF; /* ? */
163 ctrl_alt_del();
164 #ifdef CONFIG_PM_SLEEP
165 } else if (strcmp(str, "suspend") == 0) {
166 do_suspend();
167 #endif
168 } else {
169 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
170 shutting_down = SHUTDOWN_INVALID;
171 }
172
173 kfree(str);
174 }
175
176 static 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
205 static struct xenbus_watch shutdown_watch = {
206 .node = "control/shutdown",
207 .callback = shutdown_handler
208 };
209
210 static struct xenbus_watch sysrq_watch = {
211 .node = "control/sysrq",
212 .callback = sysrq_handler
213 };
214
215 static 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
234 static 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
242 static 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
252 subsys_initcall(setup_shutdown_event);
This page took 0.034754 seconds and 5 git commands to generate.