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