Blame view

drivers/xen/manage.c 6.78 KB
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
1
2
3
4
5
  /*
   * Handle extern requests for shutdown, reboot and sysrq
   */
  #include <linux/kernel.h>
  #include <linux/err.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
6
  #include <linux/slab.h>
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
7
8
  #include <linux/reboot.h>
  #include <linux/sysrq.h>
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
9
10
  #include <linux/stop_machine.h>
  #include <linux/freezer.h>
19234c081   Rafael J. Wysocki   PM: Add missing s...
11
  #include <linux/syscore_ops.h>
63c9744b9   Paul Gortmaker   xen: Add export.h...
12
  #include <linux/export.h>
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
13

016b6f5fe   Stefano Stabellini   xen: Add suspend/...
14
  #include <xen/xen.h>
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
15
  #include <xen/xenbus.h>
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
16
17
18
19
  #include <xen/grant_table.h>
  #include <xen/events.h>
  #include <xen/hvc-console.h>
  #include <xen/xen-ops.h>
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
20

0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
21
22
  #include <asm/xen/hypercall.h>
  #include <asm/xen/page.h>
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
23
  #include <asm/xen/hypervisor.h>
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
24
25
26
27
28
29
30
31
32
33
34
  
  enum shutdown_state {
  	SHUTDOWN_INVALID = -1,
  	SHUTDOWN_POWEROFF = 0,
  	SHUTDOWN_SUSPEND = 2,
  	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
  	   report a crash, not be instructed to crash!
  	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
  	   the distinction when we return the reason code to them.  */
  	 SHUTDOWN_HALT = 4,
  };
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
35
36
  
  /* Ignore multiple shutdown requests. */
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
37
  static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
ceb180294   Ian Campbell   xen: suspend: ref...
38
39
  struct suspend_info {
  	int cancelled;
36b401e2c   Ian Campbell   xen: suspend: pas...
40
  	unsigned long arg; /* extra hypercall argument */
55fb4acef   Ian Campbell   xen: suspend: pul...
41
42
  	void (*pre)(void);
  	void (*post)(int cancelled);
ceb180294   Ian Campbell   xen: suspend: ref...
43
  };
07af38102   Ian Campbell   xen: suspend: mov...
44
  static void xen_hvm_post_suspend(int cancelled)
82043bb60   Ian Campbell   xen: suspend: ref...
45
  {
07af38102   Ian Campbell   xen: suspend: mov...
46
  	xen_arch_hvm_post_suspend(cancelled);
82043bb60   Ian Campbell   xen: suspend: ref...
47
48
49
50
51
52
53
  	gnttab_resume();
  }
  
  static void xen_pre_suspend(void)
  {
  	xen_mm_pin_all();
  	gnttab_suspend();
07af38102   Ian Campbell   xen: suspend: mov...
54
  	xen_arch_pre_suspend();
82043bb60   Ian Campbell   xen: suspend: ref...
55
  }
07af38102   Ian Campbell   xen: suspend: mov...
56
  static void xen_post_suspend(int cancelled)
82043bb60   Ian Campbell   xen: suspend: ref...
57
  {
07af38102   Ian Campbell   xen: suspend: mov...
58
  	xen_arch_post_suspend(cancelled);
82043bb60   Ian Campbell   xen: suspend: ref...
59
60
61
  	gnttab_resume();
  	xen_mm_unpin_all();
  }
1f112cee0   Rafael J. Wysocki   PM / Hibernate: I...
62
  #ifdef CONFIG_HIBERNATE_CALLBACKS
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
63
64
  static int xen_suspend(void *data)
  {
ceb180294   Ian Campbell   xen: suspend: ref...
65
  	struct suspend_info *si = data;
359cdd3f8   Jeremy Fitzhardinge   xen: maintain clo...
66
  	int err;
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
67
68
  
  	BUG_ON(!irqs_disabled());
2e711c04d   Rafael J. Wysocki   PM: Remove sysdev...
69
  	err = syscore_suspend();
770824bdc   Rafael J. Wysocki   PM: Split up sysd...
70
  	if (err) {
19234c081   Rafael J. Wysocki   PM: Add missing s...
71
72
  		printk(KERN_ERR "xen_suspend: system core suspend failed: %d
  ",
770824bdc   Rafael J. Wysocki   PM: Split up sysd...
73
  			err);
770824bdc   Rafael J. Wysocki   PM: Split up sysd...
74
75
  		return err;
  	}
359cdd3f8   Jeremy Fitzhardinge   xen: maintain clo...
76

55fb4acef   Ian Campbell   xen: suspend: pul...
77
78
  	if (si->pre)
  		si->pre();
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
79
80
81
82
83
84
  
  	/*
  	 * This hypercall returns 1 if suspend was cancelled
  	 * or the domain was merely checkpointed, and 0 if it
  	 * is resuming in a new domain.
  	 */
36b401e2c   Ian Campbell   xen: suspend: pas...
85
  	si->cancelled = HYPERVISOR_suspend(si->arg);
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
86

55fb4acef   Ian Campbell   xen: suspend: pul...
87
88
  	if (si->post)
  		si->post(si->cancelled);
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
89

ceb180294   Ian Campbell   xen: suspend: ref...
90
  	if (!si->cancelled) {
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
91
92
  		xen_irq_resume();
  		xen_console_resume();
ad55db9fe   Isaku Yamahata   xen: add xen_arch...
93
  		xen_timer_resume();
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
94
  	}
19234c081   Rafael J. Wysocki   PM: Add missing s...
95
  	syscore_resume();
1e6fcf840   Ian Campbell   xen: resume inter...
96

0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
97
98
99
100
101
102
  	return 0;
  }
  
  static void do_suspend(void)
  {
  	int err;
ceb180294   Ian Campbell   xen: suspend: ref...
103
  	struct suspend_info si;
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
104
105
106
107
108
109
110
111
112
113
114
  
  	shutting_down = SHUTDOWN_SUSPEND;
  
  #ifdef CONFIG_PREEMPT
  	/* If the kernel is preemptible, we need to freeze all the processes
  	   to prevent them from being in the middle of a pagetable update
  	   during suspend. */
  	err = freeze_processes();
  	if (err) {
  		printk(KERN_ERR "xen suspend: freeze failed %d
  ", err);
3fc1f1e27   Tejun Heo   stop_machine: rei...
115
  		goto out;
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
116
117
  	}
  #endif
b3e96c0c7   Shriram Rajagopalan   xen: use freeze/r...
118
  	err = dpm_suspend_start(PMSG_FREEZE);
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
119
  	if (err) {
d16163029   Alan Stern   PM core: rename s...
120
121
  		printk(KERN_ERR "xen suspend: dpm_suspend_start %d
  ", err);
65f63384b   Ian Campbell   xen: improve erro...
122
  		goto out_thaw;
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
123
  	}
c5cae661d   Ian Campbell   xen: fix hang on ...
124
125
126
  	printk(KERN_DEBUG "suspending xenstore...
  ");
  	xs_suspend();
b3e96c0c7   Shriram Rajagopalan   xen: use freeze/r...
127
  	err = dpm_suspend_noirq(PMSG_FREEZE);
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
128
  	if (err) {
d16163029   Alan Stern   PM core: rename s...
129
130
  		printk(KERN_ERR "dpm_suspend_noirq failed: %d
  ", err);
65f63384b   Ian Campbell   xen: improve erro...
131
  		goto out_resume;
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
132
  	}
ceb180294   Ian Campbell   xen: suspend: ref...
133
  	si.cancelled = 1;
55fb4acef   Ian Campbell   xen: suspend: pul...
134
  	if (xen_hvm_domain()) {
36b401e2c   Ian Campbell   xen: suspend: pas...
135
  		si.arg = 0UL;
55fb4acef   Ian Campbell   xen: suspend: pul...
136
137
138
  		si.pre = NULL;
  		si.post = &xen_hvm_post_suspend;
  	} else {
36b401e2c   Ian Campbell   xen: suspend: pas...
139
  		si.arg = virt_to_mfn(xen_start_info);
55fb4acef   Ian Campbell   xen: suspend: pul...
140
141
142
  		si.pre = &xen_pre_suspend;
  		si.post = &xen_post_suspend;
  	}
36b401e2c   Ian Campbell   xen: suspend: pas...
143

b056b6a01   Ian Campbell   xen: suspend: rem...
144
  	err = stop_machine(xen_suspend, &si, cpumask_of(0));
922cc38ab   Jeremy Fitzhardinge   xen: don't call d...
145

b3e96c0c7   Shriram Rajagopalan   xen: use freeze/r...
146
  	dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
922cc38ab   Jeremy Fitzhardinge   xen: don't call d...
147

0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
148
149
150
  	if (err) {
  		printk(KERN_ERR "failed to start xen_suspend: %d
  ", err);
ceb180294   Ian Campbell   xen: suspend: ref...
151
  		si.cancelled = 1;
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
152
  	}
c5cae661d   Ian Campbell   xen: fix hang on ...
153
  out_resume:
ceb180294   Ian Campbell   xen: suspend: ref...
154
  	if (!si.cancelled) {
ad55db9fe   Isaku Yamahata   xen: add xen_arch...
155
  		xen_arch_resume();
de5b31bd4   Ian Campbell   xen: use device m...
156
  		xs_resume();
ad55db9fe   Isaku Yamahata   xen: add xen_arch...
157
  	} else
de5b31bd4   Ian Campbell   xen: use device m...
158
  		xs_suspend_cancel();
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
159

b3e96c0c7   Shriram Rajagopalan   xen: use freeze/r...
160
  	dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
161

359cdd3f8   Jeremy Fitzhardinge   xen: maintain clo...
162
163
  	/* Make sure timer events get retriggered on all CPUs */
  	clock_was_set();
65f63384b   Ian Campbell   xen: improve erro...
164
165
  
  out_thaw:
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
166
167
  #ifdef CONFIG_PREEMPT
  	thaw_processes();
65f63384b   Ian Campbell   xen: improve erro...
168
  out:
3fc1f1e27   Tejun Heo   stop_machine: rei...
169
  #endif
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
170
171
  	shutting_down = SHUTDOWN_INVALID;
  }
1f112cee0   Rafael J. Wysocki   PM / Hibernate: I...
172
  #endif	/* CONFIG_HIBERNATE_CALLBACKS */
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
173

552717231   Ian Campbell   xen: do not respo...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  struct shutdown_handler {
  	const char *command;
  	void (*cb)(void);
  };
  
  static void do_poweroff(void)
  {
  	shutting_down = SHUTDOWN_POWEROFF;
  	orderly_poweroff(false);
  }
  
  static void do_reboot(void)
  {
  	shutting_down = SHUTDOWN_POWEROFF; /* ? */
  	ctrl_alt_del();
  }
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
190
191
192
193
194
195
  static void shutdown_handler(struct xenbus_watch *watch,
  			     const char **vec, unsigned int len)
  {
  	char *str;
  	struct xenbus_transaction xbt;
  	int err;
552717231   Ian Campbell   xen: do not respo...
196
197
198
199
  	static struct shutdown_handler handlers[] = {
  		{ "poweroff",	do_poweroff },
  		{ "halt",	do_poweroff },
  		{ "reboot",	do_reboot   },
1f112cee0   Rafael J. Wysocki   PM / Hibernate: I...
200
  #ifdef CONFIG_HIBERNATE_CALLBACKS
552717231   Ian Campbell   xen: do not respo...
201
202
203
204
205
  		{ "suspend",	do_suspend  },
  #endif
  		{NULL, NULL},
  	};
  	static struct shutdown_handler *handler;
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  
  	if (shutting_down != SHUTDOWN_INVALID)
  		return;
  
   again:
  	err = xenbus_transaction_start(&xbt);
  	if (err)
  		return;
  
  	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
  	/* Ignore read errors and empty reads. */
  	if (XENBUS_IS_ERR_READ(str)) {
  		xenbus_transaction_end(xbt, 1);
  		return;
  	}
552717231   Ian Campbell   xen: do not respo...
221
222
223
224
225
226
227
228
  	for (handler = &handlers[0]; handler->command; handler++) {
  		if (strcmp(str, handler->command) == 0)
  			break;
  	}
  
  	/* Only acknowledge commands which we are prepared to handle. */
  	if (handler->cb)
  		xenbus_write(xbt, "control", "shutdown", "");
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
229
230
231
232
233
234
  
  	err = xenbus_transaction_end(xbt, 0);
  	if (err == -EAGAIN) {
  		kfree(str);
  		goto again;
  	}
552717231   Ian Campbell   xen: do not respo...
235
236
  	if (handler->cb) {
  		handler->cb();
0e91398f2   Jeremy Fitzhardinge   xen: implement sa...
237
  	} else {
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
238
239
240
241
242
243
244
  		printk(KERN_INFO "Ignoring shutdown request: %s
  ", str);
  		shutting_down = SHUTDOWN_INVALID;
  	}
  
  	kfree(str);
  }
f3bc3189a   Randy Dunlap   xen: fix build wh...
245
  #ifdef CONFIG_MAGIC_SYSRQ
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
  			  unsigned int len)
  {
  	char sysrq_key = '\0';
  	struct xenbus_transaction xbt;
  	int err;
  
   again:
  	err = xenbus_transaction_start(&xbt);
  	if (err)
  		return;
  	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
  		printk(KERN_ERR "Unable to read sysrq code in "
  		       "control/sysrq
  ");
  		xenbus_transaction_end(xbt, 1);
  		return;
  	}
  
  	if (sysrq_key != '\0')
  		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
  
  	err = xenbus_transaction_end(xbt, 0);
  	if (err == -EAGAIN)
  		goto again;
  
  	if (sysrq_key != '\0')
f335397d1   Dmitry Torokhov   Input: sysrq - dr...
273
  		handle_sysrq(sysrq_key);
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
274
  }
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
275
276
277
278
  static struct xenbus_watch sysrq_watch = {
  	.node = "control/sysrq",
  	.callback = sysrq_handler
  };
f3bc3189a   Randy Dunlap   xen: fix build wh...
279
280
281
282
283
284
  #endif
  
  static struct xenbus_watch shutdown_watch = {
  	.node = "control/shutdown",
  	.callback = shutdown_handler
  };
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
285
286
287
288
289
290
291
292
293
294
295
  
  static int setup_shutdown_watcher(void)
  {
  	int err;
  
  	err = register_xenbus_watch(&shutdown_watch);
  	if (err) {
  		printk(KERN_ERR "Failed to set shutdown watcher
  ");
  		return err;
  	}
f3bc3189a   Randy Dunlap   xen: fix build wh...
296
  #ifdef CONFIG_MAGIC_SYSRQ
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
297
298
299
300
301
302
  	err = register_xenbus_watch(&sysrq_watch);
  	if (err) {
  		printk(KERN_ERR "Failed to set sysrq watcher
  ");
  		return err;
  	}
f3bc3189a   Randy Dunlap   xen: fix build wh...
303
  #endif
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
304
305
306
307
308
309
310
311
312
313
314
  
  	return 0;
  }
  
  static int shutdown_event(struct notifier_block *notifier,
  			  unsigned long event,
  			  void *data)
  {
  	setup_shutdown_watcher();
  	return NOTIFY_DONE;
  }
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
315
  int xen_setup_shutdown_event(void)
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
316
317
318
319
  {
  	static struct notifier_block xenstore_notifier = {
  		.notifier_call = shutdown_event
  	};
702d4eb9b   Stefano Stabellini   xen: no need to d...
320
321
322
  
  	if (!xen_domain())
  		return -ENODEV;
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
323
324
325
326
  	register_xenstore_notifier(&xenstore_notifier);
  
  	return 0;
  }
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
327
  EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
3e2b8fbee   Jeremy Fitzhardinge   xen: handle exter...
328

702d4eb9b   Stefano Stabellini   xen: no need to d...
329
  subsys_initcall(xen_setup_shutdown_event);