aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/manage.c
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-05-26 18:31:27 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-27 04:11:38 -0400
commit0e91398f2a5d4eb6b07df8115917d0d1cf3e9b58 (patch)
treec6a3b31b7bcbbfb55bb2304d8651abdd28cdad54 /drivers/xen/manage.c
parent7d88d32a4670af583c896e5ecd3929b78538ca62 (diff)
xen: implement save/restore
This patch implements Xen save/restore and migration. Saving is triggered via xenbus, which is polled in drivers/xen/manage.c. When a suspend request comes in, the kernel prepares itself for saving by: 1 - Freeze all processes. This is primarily to prevent any partially-completed pagetable updates from confusing the suspend process. If CONFIG_PREEMPT isn't defined, then this isn't necessary. 2 - Suspend xenbus and other devices 3 - Stop_machine, to make sure all the other vcpus are quiescent. The Xen tools require the domain to run its save off vcpu0. 4 - Within the stop_machine state, it pins any unpinned pgds (under construction or destruction), performs canonicalizes various other pieces of state (mostly converting mfns to pfns), and finally 5 - Suspend the domain Restore reverses the steps used to save the domain, ending when all the frozen processes are thawed. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/xen/manage.c')
-rw-r--r--drivers/xen/manage.c126
1 files changed, 112 insertions, 14 deletions
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index aa7af9e6abc0..ba85fa2cff33 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -5,21 +5,113 @@
5#include <linux/err.h> 5#include <linux/err.h>
6#include <linux/reboot.h> 6#include <linux/reboot.h>
7#include <linux/sysrq.h> 7#include <linux/sysrq.h>
8#include <linux/stop_machine.h>
9#include <linux/freezer.h>
8 10
9#include <xen/xenbus.h> 11#include <xen/xenbus.h>
10 12#include <xen/grant_table.h>
11#define SHUTDOWN_INVALID -1 13#include <xen/events.h>
12#define SHUTDOWN_POWEROFF 0 14#include <xen/hvc-console.h>
13#define SHUTDOWN_SUSPEND 2 15#include <xen/xen-ops.h>
14/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 16
15 * report a crash, not be instructed to crash! 17#include <asm/xen/hypercall.h>
16 * HALT is the same as POWEROFF, as far as we're concerned. The tools use 18#include <asm/xen/page.h>
17 * the distinction when we return the reason code to them. 19
18 */ 20enum shutdown_state {
19#define SHUTDOWN_HALT 4 21 SHUTDOWN_INVALID = -1,
22 SHUTDOWN_POWEROFF = 0,
23 SHUTDOWN_SUSPEND = 2,
24 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
25 report a crash, not be instructed to crash!
26 HALT is the same as POWEROFF, as far as we're concerned. The tools use
27 the distinction when we return the reason code to them. */
28 SHUTDOWN_HALT = 4,
29};
20 30
21/* Ignore multiple shutdown requests. */ 31/* Ignore multiple shutdown requests. */
22static int shutting_down = SHUTDOWN_INVALID; 32static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
34static int xen_suspend(void *data)
35{
36 int *cancelled = data;
37
38 BUG_ON(!irqs_disabled());
39
40 load_cr3(swapper_pg_dir);
41
42 xen_mm_pin_all();
43 gnttab_suspend();
44 xen_time_suspend();
45 xen_pre_suspend();
46
47 /*
48 * This hypercall returns 1 if suspend was cancelled
49 * or the domain was merely checkpointed, and 0 if it
50 * is resuming in a new domain.
51 */
52 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
53
54 xen_post_suspend(*cancelled);
55 xen_time_resume();
56 gnttab_resume();
57 xen_mm_unpin_all();
58
59 if (!*cancelled) {
60 xen_irq_resume();
61 xen_console_resume();
62 }
63
64 return 0;
65}
66
67static void do_suspend(void)
68{
69 int err;
70 int cancelled = 1;
71
72 shutting_down = SHUTDOWN_SUSPEND;
73
74#ifdef CONFIG_PREEMPT
75 /* If the kernel is preemptible, we need to freeze all the processes
76 to prevent them from being in the middle of a pagetable update
77 during suspend. */
78 err = freeze_processes();
79 if (err) {
80 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
81 return;
82 }
83#endif
84
85 err = device_suspend(PMSG_SUSPEND);
86 if (err) {
87 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
88 goto out;
89 }
90
91 printk("suspending xenbus...\n");
92 /* XXX use normal device tree? */
93 xenbus_suspend();
94
95 err = stop_machine_run(xen_suspend, &cancelled, 0);
96 if (err) {
97 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
98 goto out;
99 }
100
101 if (!cancelled)
102 xenbus_resume();
103 else
104 xenbus_suspend_cancel();
105
106 device_resume();
107
108
109out:
110#ifdef CONFIG_PREEMPT
111 thaw_processes();
112#endif
113 shutting_down = SHUTDOWN_INVALID;
114}
23 115
24static void shutdown_handler(struct xenbus_watch *watch, 116static void shutdown_handler(struct xenbus_watch *watch,
25 const char **vec, unsigned int len) 117 const char **vec, unsigned int len)
@@ -52,11 +144,17 @@ static void shutdown_handler(struct xenbus_watch *watch,
52 } 144 }
53 145
54 if (strcmp(str, "poweroff") == 0 || 146 if (strcmp(str, "poweroff") == 0 ||
55 strcmp(str, "halt") == 0) 147 strcmp(str, "halt") == 0) {
148 shutting_down = SHUTDOWN_POWEROFF;
56 orderly_poweroff(false); 149 orderly_poweroff(false);
57 else if (strcmp(str, "reboot") == 0) 150 } else if (strcmp(str, "reboot") == 0) {
151 shutting_down = SHUTDOWN_POWEROFF; /* ? */
58 ctrl_alt_del(); 152 ctrl_alt_del();
59 else { 153#ifdef CONFIG_PM_SLEEP
154 } else if (strcmp(str, "suspend") == 0) {
155 do_suspend();
156#endif
157 } else {
60 printk(KERN_INFO "Ignoring shutdown request: %s\n", str); 158 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
61 shutting_down = SHUTDOWN_INVALID; 159 shutting_down = SHUTDOWN_INVALID;
62 } 160 }