Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
xen
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
25
enum
shutdown_state
{
26
SHUTDOWN_INVALID
= -1,
27
SHUTDOWN_POWEROFF
= 0,
28
SHUTDOWN_SUSPEND
= 2,
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. */
33
SHUTDOWN_HALT
= 4,
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
{
54
xen_mm_pin_all
();
55
gnttab_suspend
();
56
xen_arch_pre_suspend
();
57
}
58
59
static
void
xen_post_suspend(
int
cancelled)
60
{
61
xen_arch_post_suspend
(cancelled);
62
gnttab_resume
();
63
xen_mm_unpin_all
();
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
72
BUG_ON
(!
irqs_disabled
());
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
) {
95
xen_irq_resume
();
96
xen_console_resume
();
97
xen_timer_resume
();
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
123
err =
dpm_suspend_start
(
PMSG_FREEZE
);
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
132
err =
dpm_suspend_end
(
PMSG_FREEZE
);
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
= 0
UL
;
143
si.
pre
=
NULL
;
144
si.
post
= &xen_hvm_post_suspend;
145
}
else
{
146
si.
arg
=
virt_to_mfn
(
xen_start_info
);
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
153
dpm_resume_start
(si.
cancelled
?
PMSG_THAW
:
PMSG_RESTORE
);
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
165
xs_suspend_cancel
();
166
167
dpm_resume_end
(si.
cancelled
?
PMSG_THAW
:
PMSG_RESTORE
);
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
181
struct
shutdown_handler
{
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
325
int
xen_setup_shutdown_event
(
void
)
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
}
337
EXPORT_SYMBOL_GPL
(
xen_setup_shutdown_event
);
338
339
subsys_initcall
(
xen_setup_shutdown_event
);
Generated on Thu Jan 10 2013 14:02:16 for Linux Kernel by
1.8.2