ia64/xen-unstable

view linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @ 6218:7c1d66d4e51e

Avoid spurious "Ignoring shutdown request" messages, fix memory leak and simplif
y code.
Also fix whitespace.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Wed Aug 17 08:26:58 2005 +0000 (2005-08-17)
parents 35f3f9424c93
children 3b0ce44f7b7a
line source
1 #define __KERNEL_SYSCALLS__
2 #include <linux/version.h>
3 #include <linux/kernel.h>
4 #include <linux/mm.h>
5 #include <linux/unistd.h>
6 #include <linux/module.h>
7 #include <linux/reboot.h>
8 #include <linux/sysrq.h>
9 #include <linux/stringify.h>
10 #include <asm/irq.h>
11 #include <asm/mmu_context.h>
12 #include <asm-xen/evtchn.h>
13 #include <asm-xen/hypervisor.h>
14 #include <asm-xen/xen-public/dom0_ops.h>
15 #include <asm-xen/linux-public/suspend.h>
16 #include <asm-xen/queues.h>
17 #include <asm-xen/xenbus.h>
18 #include <asm-xen/ctrl_if.h>
20 #define SHUTDOWN_INVALID -1
21 #define SHUTDOWN_POWEROFF 0
22 #define SHUTDOWN_REBOOT 1
23 #define SHUTDOWN_SUSPEND 2
25 void machine_restart(char * __unused)
26 {
27 /* We really want to get pending console data out before we die. */
28 extern void xencons_force_flush(void);
29 xencons_force_flush();
30 HYPERVISOR_reboot();
31 }
33 void machine_halt(void)
34 {
35 machine_power_off();
36 }
38 void machine_power_off(void)
39 {
40 /* We really want to get pending console data out before we die. */
41 extern void xencons_force_flush(void);
42 xencons_force_flush();
43 HYPERVISOR_shutdown();
44 }
46 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
47 int reboot_thru_bios = 0; /* for dmi_scan.c */
48 EXPORT_SYMBOL(machine_restart);
49 EXPORT_SYMBOL(machine_halt);
50 EXPORT_SYMBOL(machine_power_off);
51 #endif
54 /******************************************************************************
55 * Stop/pickle callback handling.
56 */
58 /* Ignore multiple shutdown requests. */
59 static int shutting_down = SHUTDOWN_INVALID;
61 static void __do_suspend(void)
62 {
63 int i, j;
64 suspend_record_t *suspend_record;
66 /* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */
67 /* XXX SMH: yes it would :-( */
68 #ifdef CONFIG_XEN_BLKDEV_FRONTEND
69 extern void blkdev_suspend(void);
70 extern void blkdev_resume(void);
71 #else
72 #define blkdev_suspend() do{}while(0)
73 #define blkdev_resume() do{}while(0)
74 #endif
76 #ifdef CONFIG_XEN_NETDEV_FRONTEND
77 extern void netif_suspend(void);
78 extern void netif_resume(void);
79 #else
80 #define netif_suspend() do{}while(0)
81 #define netif_resume() do{}while(0)
82 #endif
84 #ifdef CONFIG_XEN_USB_FRONTEND
85 extern void usbif_resume();
86 #else
87 #define usbif_resume() do{}while(0)
88 #endif
90 #ifdef CONFIG_XEN_BLKDEV_GRANT
91 extern int gnttab_suspend(void);
92 extern int gnttab_resume(void);
93 #else
94 #define gnttab_suspend() do{}while(0)
95 #define gnttab_resume() do{}while(0)
96 #endif
98 #ifdef CONFIG_SMP
99 extern void smp_suspend(void);
100 extern void smp_resume(void);
101 #endif
102 extern void time_suspend(void);
103 extern void time_resume(void);
104 extern unsigned long max_pfn;
105 extern unsigned int *pfn_to_mfn_frame_list;
107 suspend_record = (suspend_record_t *)__get_free_page(GFP_KERNEL);
108 if ( suspend_record == NULL )
109 goto out;
111 suspend_record->nr_pfns = max_pfn; /* final number of pfns */
113 __cli();
115 #ifdef __i386__
116 mm_pin_all();
117 kmem_cache_shrink(pgd_cache);
118 #endif
120 netif_suspend();
122 blkdev_suspend();
124 time_suspend();
126 #ifdef CONFIG_SMP
127 smp_suspend();
128 #endif
130 xenbus_suspend();
132 ctrl_if_suspend();
134 irq_suspend();
136 gnttab_suspend();
138 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
139 clear_fixmap(FIX_SHARED_INFO);
141 memcpy(&suspend_record->resume_info, &xen_start_info,
142 sizeof(xen_start_info));
144 HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
146 shutting_down = SHUTDOWN_INVALID;
148 memcpy(&xen_start_info, &suspend_record->resume_info,
149 sizeof(xen_start_info));
151 set_fixmap(FIX_SHARED_INFO, xen_start_info.shared_info);
153 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
155 memset(empty_zero_page, 0, PAGE_SIZE);
157 for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
158 {
159 pfn_to_mfn_frame_list[j] =
160 virt_to_machine(&phys_to_machine_mapping[i]) >> PAGE_SHIFT;
161 }
162 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list =
163 virt_to_machine(pfn_to_mfn_frame_list) >> PAGE_SHIFT;
165 gnttab_resume();
167 irq_resume();
169 ctrl_if_resume();
171 xenbus_resume();
173 #ifdef CONFIG_SMP
174 smp_resume();
175 #endif
177 time_resume();
179 blkdev_resume();
181 netif_resume();
183 usbif_resume();
185 __sti();
187 out:
188 if ( suspend_record != NULL )
189 free_page((unsigned long)suspend_record);
190 }
192 static int shutdown_process(void *__unused)
193 {
194 static char *envp[] = { "HOME=/", "TERM=linux",
195 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
196 static char *restart_argv[] = { "/sbin/reboot", NULL };
197 static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
199 extern asmlinkage long sys_reboot(int magic1, int magic2,
200 unsigned int cmd, void *arg);
202 daemonize(
203 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
204 "shutdown"
205 #endif
206 );
208 switch ( shutting_down )
209 {
210 case SHUTDOWN_POWEROFF:
211 if ( execve("/sbin/poweroff", poweroff_argv, envp) < 0 )
212 {
213 sys_reboot(LINUX_REBOOT_MAGIC1,
214 LINUX_REBOOT_MAGIC2,
215 LINUX_REBOOT_CMD_POWER_OFF,
216 NULL);
217 }
218 break;
220 case SHUTDOWN_REBOOT:
221 if ( execve("/sbin/reboot", restart_argv, envp) < 0 )
222 {
223 sys_reboot(LINUX_REBOOT_MAGIC1,
224 LINUX_REBOOT_MAGIC2,
225 LINUX_REBOOT_CMD_RESTART,
226 NULL);
227 }
228 break;
229 }
231 shutting_down = SHUTDOWN_INVALID; /* could try again */
233 return 0;
234 }
236 static void __shutdown_handler(void *unused)
237 {
238 int err;
240 if ( shutting_down != SHUTDOWN_SUSPEND )
241 {
242 err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
243 if ( err < 0 )
244 printk(KERN_ALERT "Error creating shutdown process!\n");
245 }
246 else
247 {
248 __do_suspend();
249 }
250 }
252 static void shutdown_handler(struct xenbus_watch *watch, const char *node)
253 {
254 static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
256 char *str;
258 str = (char *)xenbus_read("control", "shutdown", NULL);
259 /* Ignore read errors. */
260 if (IS_ERR(str))
261 return;
262 if (strlen(str) == 0) {
263 kfree(str);
264 return;
265 }
267 xenbus_printf("control", "shutdown", "");
269 if (strcmp(str, "poweroff") == 0)
270 shutting_down = SHUTDOWN_POWEROFF;
271 else if (strcmp(str, "reboot") == 0)
272 shutting_down = SHUTDOWN_REBOOT;
273 else if (strcmp(str, "suspend") == 0)
274 shutting_down = SHUTDOWN_SUSPEND;
275 else {
276 printk("Ignoring shutdown request: %s\n", str);
277 shutting_down = SHUTDOWN_INVALID;
278 }
280 kfree(str);
282 if (shutting_down != SHUTDOWN_INVALID)
283 schedule_work(&shutdown_work);
284 }
286 #ifdef CONFIG_MAGIC_SYSRQ
287 static void sysrq_handler(struct xenbus_watch *watch, const char *node)
288 {
289 char sysrq_key = '\0';
291 if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
292 printk(KERN_ERR "Unable to read sysrq code in control/sysrq\n");
293 return;
294 }
296 xenbus_printf("control", "sysrq", "%c", '\0');
298 if (sysrq_key != '\0') {
300 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
301 handle_sysrq(sysrq_key, NULL, NULL);
302 #else
303 handle_sysrq(sysrq_key, NULL, NULL, NULL);
304 #endif
305 }
306 }
307 #endif
309 static struct xenbus_watch shutdown_watch = {
310 .node = "control/shutdown",
311 .callback = shutdown_handler
312 };
314 #ifdef CONFIG_MAGIC_SYSRQ
315 static struct xenbus_watch sysrq_watch = {
316 .node ="control/sysrq",
317 .callback = sysrq_handler
318 };
319 #endif
321 static struct notifier_block xenstore_notifier;
323 /* Setup our watcher
324 NB: Assumes xenbus_lock is held!
325 */
326 static int setup_shutdown_watcher(struct notifier_block *notifier,
327 unsigned long event,
328 void *data)
329 {
330 int err1 = 0;
331 #ifdef CONFIG_MAGIC_SYSRQ
332 int err2 = 0;
333 #endif
335 BUG_ON(down_trylock(&xenbus_lock) == 0);
337 err1 = register_xenbus_watch(&shutdown_watch);
338 #ifdef CONFIG_MAGIC_SYSRQ
339 err2 = register_xenbus_watch(&sysrq_watch);
340 #endif
342 if (err1) {
343 printk(KERN_ERR "Failed to set shutdown watcher\n");
344 }
346 #ifdef CONFIG_MAGIC_SYSRQ
347 if (err2) {
348 printk(KERN_ERR "Failed to set sysrq watcher\n");
349 }
350 #endif
352 return NOTIFY_DONE;
353 }
355 static int __init setup_shutdown_event(void)
356 {
358 xenstore_notifier.notifier_call = setup_shutdown_watcher;
360 register_xenstore_notifier(&xenstore_notifier);
362 return 0;
363 }
365 subsys_initcall(setup_shutdown_event);