]> err.no Git - linux-2.6/blob - drivers/xen/manage.c
Merge branch 'master' of /home/cbou/linux-2.6
[linux-2.6] / 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         load_cr3(swapper_pg_dir);
43
44         err = device_power_down(PMSG_SUSPEND);
45         if (err) {
46                 printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
47                        err);
48                 return err;
49         }
50
51         xen_mm_pin_all();
52         gnttab_suspend();
53         xen_pre_suspend();
54
55         /*
56          * This hypercall returns 1 if suspend was cancelled
57          * or the domain was merely checkpointed, and 0 if it
58          * is resuming in a new domain.
59          */
60         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
61
62         xen_post_suspend(*cancelled);
63         gnttab_resume();
64         xen_mm_unpin_all();
65
66         device_power_up(PMSG_RESUME);
67
68         if (!*cancelled) {
69                 xen_irq_resume();
70                 xen_console_resume();
71                 xen_timer_resume();
72         }
73
74         return 0;
75 }
76
77 static void do_suspend(void)
78 {
79         int err;
80         int cancelled = 1;
81
82         shutting_down = SHUTDOWN_SUSPEND;
83
84 #ifdef CONFIG_PREEMPT
85         /* If the kernel is preemptible, we need to freeze all the processes
86            to prevent them from being in the middle of a pagetable update
87            during suspend. */
88         err = freeze_processes();
89         if (err) {
90                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
91                 return;
92         }
93 #endif
94
95         err = device_suspend(PMSG_SUSPEND);
96         if (err) {
97                 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
98                 goto out;
99         }
100
101         printk("suspending xenbus...\n");
102         /* XXX use normal device tree? */
103         xenbus_suspend();
104
105         err = stop_machine_run(xen_suspend, &cancelled, 0);
106         if (err) {
107                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
108                 goto out;
109         }
110
111         if (!cancelled) {
112                 xen_arch_resume();
113                 xenbus_resume();
114         } else
115                 xenbus_suspend_cancel();
116
117         device_resume(PMSG_RESUME);
118
119         /* Make sure timer events get retriggered on all CPUs */
120         clock_was_set();
121 out:
122 #ifdef CONFIG_PREEMPT
123         thaw_processes();
124 #endif
125         shutting_down = SHUTDOWN_INVALID;
126 }
127 #endif  /* CONFIG_PM_SLEEP */
128
129 static void shutdown_handler(struct xenbus_watch *watch,
130                              const char **vec, unsigned int len)
131 {
132         char *str;
133         struct xenbus_transaction xbt;
134         int err;
135
136         if (shutting_down != SHUTDOWN_INVALID)
137                 return;
138
139  again:
140         err = xenbus_transaction_start(&xbt);
141         if (err)
142                 return;
143
144         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
145         /* Ignore read errors and empty reads. */
146         if (XENBUS_IS_ERR_READ(str)) {
147                 xenbus_transaction_end(xbt, 1);
148                 return;
149         }
150
151         xenbus_write(xbt, "control", "shutdown", "");
152
153         err = xenbus_transaction_end(xbt, 0);
154         if (err == -EAGAIN) {
155                 kfree(str);
156                 goto again;
157         }
158
159         if (strcmp(str, "poweroff") == 0 ||
160             strcmp(str, "halt") == 0) {
161                 shutting_down = SHUTDOWN_POWEROFF;
162                 orderly_poweroff(false);
163         } else if (strcmp(str, "reboot") == 0) {
164                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
165                 ctrl_alt_del();
166 #ifdef CONFIG_PM_SLEEP
167         } else if (strcmp(str, "suspend") == 0) {
168                 do_suspend();
169 #endif
170         } else {
171                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
172                 shutting_down = SHUTDOWN_INVALID;
173         }
174
175         kfree(str);
176 }
177
178 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
179                           unsigned int len)
180 {
181         char sysrq_key = '\0';
182         struct xenbus_transaction xbt;
183         int err;
184
185  again:
186         err = xenbus_transaction_start(&xbt);
187         if (err)
188                 return;
189         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
190                 printk(KERN_ERR "Unable to read sysrq code in "
191                        "control/sysrq\n");
192                 xenbus_transaction_end(xbt, 1);
193                 return;
194         }
195
196         if (sysrq_key != '\0')
197                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
198
199         err = xenbus_transaction_end(xbt, 0);
200         if (err == -EAGAIN)
201                 goto again;
202
203         if (sysrq_key != '\0')
204                 handle_sysrq(sysrq_key, NULL);
205 }
206
207 static struct xenbus_watch shutdown_watch = {
208         .node = "control/shutdown",
209         .callback = shutdown_handler
210 };
211
212 static struct xenbus_watch sysrq_watch = {
213         .node = "control/sysrq",
214         .callback = sysrq_handler
215 };
216
217 static int setup_shutdown_watcher(void)
218 {
219         int err;
220
221         err = register_xenbus_watch(&shutdown_watch);
222         if (err) {
223                 printk(KERN_ERR "Failed to set shutdown watcher\n");
224                 return err;
225         }
226
227         err = register_xenbus_watch(&sysrq_watch);
228         if (err) {
229                 printk(KERN_ERR "Failed to set sysrq watcher\n");
230                 return err;
231         }
232
233         return 0;
234 }
235
236 static int shutdown_event(struct notifier_block *notifier,
237                           unsigned long event,
238                           void *data)
239 {
240         setup_shutdown_watcher();
241         return NOTIFY_DONE;
242 }
243
244 static int __init setup_shutdown_event(void)
245 {
246         static struct notifier_block xenstore_notifier = {
247                 .notifier_call = shutdown_event
248         };
249         register_xenstore_notifier(&xenstore_notifier);
250
251         return 0;
252 }
253
254 subsys_initcall(setup_shutdown_event);