Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
manage.c
Go to the documentation of this file.
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 #include <linux/syscore_ops.h>
12 #include <linux/export.h>
13 
14 #include <xen/xen.h>
15 #include <xen/xenbus.h>
16 #include <xen/grant_table.h>
17 #include <xen/events.h>
18 #include <xen/hvc-console.h>
19 #include <xen/xen-ops.h>
20 
21 #include <asm/xen/hypercall.h>
22 #include <asm/xen/page.h>
23 #include <asm/xen/hypervisor.h>
24 
29  /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
30  report a crash, not be instructed to crash!
31  HALT is the same as POWEROFF, as far as we're concerned. The tools use
32  the distinction when we return the reason code to them. */
34 };
35 
36 /* Ignore multiple shutdown requests. */
37 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
38 
39 struct suspend_info {
40  int cancelled;
41  unsigned long arg; /* extra hypercall argument */
42  void (*pre)(void);
43  void (*post)(int cancelled);
44 };
45 
46 static void xen_hvm_post_suspend(int cancelled)
47 {
48  xen_arch_hvm_post_suspend(cancelled);
49  gnttab_resume();
50 }
51 
52 static void xen_pre_suspend(void)
53 {
57 }
58 
59 static void xen_post_suspend(int cancelled)
60 {
61  xen_arch_post_suspend(cancelled);
62  gnttab_resume();
64 }
65 
66 #ifdef CONFIG_HIBERNATE_CALLBACKS
67 static int xen_suspend(void *data)
68 {
69  struct suspend_info *si = data;
70  int err;
71 
73 
74  err = syscore_suspend();
75  if (err) {
76  printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n",
77  err);
78  return err;
79  }
80 
81  if (si->pre)
82  si->pre();
83 
84  /*
85  * This hypercall returns 1 if suspend was cancelled
86  * or the domain was merely checkpointed, and 0 if it
87  * is resuming in a new domain.
88  */
89  si->cancelled = HYPERVISOR_suspend(si->arg);
90 
91  if (si->post)
92  si->post(si->cancelled);
93 
94  if (!si->cancelled) {
98  }
99 
100  syscore_resume();
101 
102  return 0;
103 }
104 
105 static void do_suspend(void)
106 {
107  int err;
108  struct suspend_info si;
109 
110  shutting_down = SHUTDOWN_SUSPEND;
111 
112 #ifdef CONFIG_PREEMPT
113  /* If the kernel is preemptible, we need to freeze all the processes
114  to prevent them from being in the middle of a pagetable update
115  during suspend. */
116  err = freeze_processes();
117  if (err) {
118  printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
119  goto out;
120  }
121 #endif
122 
124  if (err) {
125  printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
126  goto out_thaw;
127  }
128 
129  printk(KERN_DEBUG "suspending xenstore...\n");
130  xs_suspend();
131 
133  if (err) {
134  printk(KERN_ERR "dpm_suspend_end failed: %d\n", err);
135  si.cancelled = 0;
136  goto out_resume;
137  }
138 
139  si.cancelled = 1;
140 
141  if (xen_hvm_domain()) {
142  si.arg = 0UL;
143  si.pre = NULL;
144  si.post = &xen_hvm_post_suspend;
145  } else {
147  si.pre = &xen_pre_suspend;
148  si.post = &xen_post_suspend;
149  }
150 
151  err = stop_machine(xen_suspend, &si, cpumask_of(0));
152 
154 
155  if (err) {
156  printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
157  si.cancelled = 1;
158  }
159 
160 out_resume:
161  if (!si.cancelled) {
162  xen_arch_resume();
163  xs_resume();
164  } else
166 
168 
169  /* Make sure timer events get retriggered on all CPUs */
170  clock_was_set();
171 
172 out_thaw:
173 #ifdef CONFIG_PREEMPT
174  thaw_processes();
175 out:
176 #endif
177  shutting_down = SHUTDOWN_INVALID;
178 }
179 #endif /* CONFIG_HIBERNATE_CALLBACKS */
180 
182  const char *command;
183  void (*cb)(void);
184 };
185 
186 static void do_poweroff(void)
187 {
188  shutting_down = SHUTDOWN_POWEROFF;
189  orderly_poweroff(false);
190 }
191 
192 static void do_reboot(void)
193 {
194  shutting_down = SHUTDOWN_POWEROFF; /* ? */
195  ctrl_alt_del();
196 }
197 
198 static void shutdown_handler(struct xenbus_watch *watch,
199  const char **vec, unsigned int len)
200 {
201  char *str;
202  struct xenbus_transaction xbt;
203  int err;
204  static struct shutdown_handler handlers[] = {
205  { "poweroff", do_poweroff },
206  { "halt", do_poweroff },
207  { "reboot", do_reboot },
208 #ifdef CONFIG_HIBERNATE_CALLBACKS
209  { "suspend", do_suspend },
210 #endif
211  {NULL, NULL},
212  };
213  static struct shutdown_handler *handler;
214 
215  if (shutting_down != SHUTDOWN_INVALID)
216  return;
217 
218  again:
219  err = xenbus_transaction_start(&xbt);
220  if (err)
221  return;
222 
223  str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
224  /* Ignore read errors and empty reads. */
225  if (XENBUS_IS_ERR_READ(str)) {
226  xenbus_transaction_end(xbt, 1);
227  return;
228  }
229 
230  for (handler = &handlers[0]; handler->command; handler++) {
231  if (strcmp(str, handler->command) == 0)
232  break;
233  }
234 
235  /* Only acknowledge commands which we are prepared to handle. */
236  if (handler->cb)
237  xenbus_write(xbt, "control", "shutdown", "");
238 
239  err = xenbus_transaction_end(xbt, 0);
240  if (err == -EAGAIN) {
241  kfree(str);
242  goto again;
243  }
244 
245  if (handler->cb) {
246  handler->cb();
247  } else {
248  printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
249  shutting_down = SHUTDOWN_INVALID;
250  }
251 
252  kfree(str);
253 }
254 
255 #ifdef CONFIG_MAGIC_SYSRQ
256 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
257  unsigned int len)
258 {
259  char sysrq_key = '\0';
260  struct xenbus_transaction xbt;
261  int err;
262 
263  again:
264  err = xenbus_transaction_start(&xbt);
265  if (err)
266  return;
267  if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
268  printk(KERN_ERR "Unable to read sysrq code in "
269  "control/sysrq\n");
270  xenbus_transaction_end(xbt, 1);
271  return;
272  }
273 
274  if (sysrq_key != '\0')
275  xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
276 
277  err = xenbus_transaction_end(xbt, 0);
278  if (err == -EAGAIN)
279  goto again;
280 
281  if (sysrq_key != '\0')
282  handle_sysrq(sysrq_key);
283 }
284 
285 static struct xenbus_watch sysrq_watch = {
286  .node = "control/sysrq",
287  .callback = sysrq_handler
288 };
289 #endif
290 
291 static struct xenbus_watch shutdown_watch = {
292  .node = "control/shutdown",
293  .callback = shutdown_handler
294 };
295 
296 static int setup_shutdown_watcher(void)
297 {
298  int err;
299 
300  err = register_xenbus_watch(&shutdown_watch);
301  if (err) {
302  printk(KERN_ERR "Failed to set shutdown watcher\n");
303  return err;
304  }
305 
306 #ifdef CONFIG_MAGIC_SYSRQ
307  err = register_xenbus_watch(&sysrq_watch);
308  if (err) {
309  printk(KERN_ERR "Failed to set sysrq watcher\n");
310  return err;
311  }
312 #endif
313 
314  return 0;
315 }
316 
317 static int shutdown_event(struct notifier_block *notifier,
318  unsigned long event,
319  void *data)
320 {
321  setup_shutdown_watcher();
322  return NOTIFY_DONE;
323 }
324 
326 {
327  static struct notifier_block xenstore_notifier = {
328  .notifier_call = shutdown_event
329  };
330 
331  if (!xen_domain())
332  return -ENODEV;
333  register_xenstore_notifier(&xenstore_notifier);
334 
335  return 0;
336 }
338