debuggers.hg

view tools/xcutils/xc_save.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents 07f6d9047af4
children 3ffdb094c2c0 f7605c6c9548
line source
1 /*
2 * This file is subject to the terms and conditions of the GNU General
3 * Public License. See the file "COPYING" in the main directory of
4 * this archive for more details.
5 *
6 * Copyright (C) 2005 by Christian Limpach
7 *
8 */
10 #include <err.h>
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <sys/ipc.h>
16 #include <sys/shm.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <err.h>
22 #include <xs.h>
23 #include <xenctrl.h>
24 #include <xenguest.h>
26 static struct suspendinfo {
27 int xc_fd; /* libxc handle */
28 int xce; /* event channel handle */
29 int suspend_evtchn;
30 int domid;
31 unsigned int flags;
32 } si;
34 /**
35 * Issue a suspend request through stdout, and receive the acknowledgement
36 * from stdin. This is handled by XendCheckpoint in the Python layer.
37 */
38 static int compat_suspend(void)
39 {
40 char ans[30];
42 printf("suspend\n");
43 fflush(stdout);
45 return (fgets(ans, sizeof(ans), stdin) != NULL &&
46 !strncmp(ans, "done\n", 5));
47 }
49 /**
50 * Issue a suspend request to a dedicated event channel in the guest, and
51 * receive the acknowledgement from the subscribe event channel. */
52 static int evtchn_suspend(void)
53 {
54 int rc;
56 rc = xc_evtchn_notify(si.xce, si.suspend_evtchn);
57 if (rc < 0) {
58 warnx("failed to notify suspend request channel: %d", rc);
59 return 0;
60 }
62 if (xc_await_suspend(si.xce, si.suspend_evtchn) < 0) {
63 warnx("suspend failed");
64 return 0;
65 }
67 /* notify xend that it can do device migration */
68 printf("suspended\n");
69 fflush(stdout);
71 return 1;
72 }
74 static int suspend(void* data)
75 {
76 unsigned long sx_state = 0;
78 /* Cannot notify guest to shut itself down if it's in ACPI sleep state. */
79 if (si.flags & XCFLAGS_HVM)
80 xc_get_hvm_param(si.xc_fd, si.domid,
81 HVM_PARAM_ACPI_S_STATE, &sx_state);
83 if ((sx_state == 0) && (si.suspend_evtchn >= 0))
84 return evtchn_suspend();
86 return compat_suspend();
87 }
89 /* For HVM guests, there are two sources of dirty pages: the Xen shadow
90 * log-dirty bitmap, which we get with a hypercall, and qemu's version.
91 * The protocol for getting page-dirtying data from qemu uses a
92 * double-buffered shared memory interface directly between xc_save and
93 * qemu-dm.
94 *
95 * xc_save calculates the size of the bitmaps and notifies qemu-dm
96 * through the store that it wants to share the bitmaps. qemu-dm then
97 * starts filling in the 'active' buffer.
98 *
99 * To change the buffers over, xc_save writes the other buffer number to
100 * the store and waits for qemu to acknowledge that it is now writing to
101 * the new active buffer. xc_save can then process and clear the old
102 * active buffer. */
105 static void switch_qemu_logdirty(int domid, unsigned int enable)
106 {
107 struct xs_handle *xs;
108 char *path, *p, *ret_str, *cmd_str, **watch;
109 unsigned int len;
110 struct timeval tv;
111 fd_set fdset;
113 if ((xs = xs_daemon_open()) == NULL)
114 errx(1, "Couldn't contact xenstore");
115 if (!(path = strdup("/local/domain/0/device-model/")))
116 errx(1, "can't get domain path in store");
117 if (!(path = realloc(path, strlen(path)
118 + 10
119 + strlen("/logdirty/cmd") + 1)))
120 errx(1, "no memory for constructing xenstore path");
121 snprintf(path + strlen(path), 11, "%i", domid);
122 strcat(path, "/logdirty/");
123 p = path + strlen(path);
126 /* Watch for qemu's return value */
127 strcpy(p, "ret");
128 if (!xs_watch(xs, path, "qemu-logdirty-ret"))
129 errx(1, "can't set watch in store (%s)\n", path);
131 if (!(cmd_str = strdup( enable == 0 ? "disable" : "enable")))
132 errx(1, "can't get logdirty cmd path in store");
134 /* Tell qemu that we want it to start logging dirty page to Xen */
135 strcpy(p, "cmd");
136 if (!xs_write(xs, XBT_NULL, path, cmd_str, strlen(cmd_str)))
137 errx(1, "can't write to store path (%s)\n",
138 path);
140 /* Wait a while for qemu to signal that it has service logdirty command */
141 read_again:
142 tv.tv_sec = 5;
143 tv.tv_usec = 0;
144 FD_ZERO(&fdset);
145 FD_SET(xs_fileno(xs), &fdset);
147 if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1)
148 errx(1, "timed out waiting for qemu logdirty response.\n");
150 watch = xs_read_watch(xs, &len);
151 free(watch);
153 strcpy(p, "ret");
154 ret_str = xs_read(xs, XBT_NULL, path, &len);
155 if (ret_str == NULL || strcmp(ret_str, cmd_str))
156 /* Watch fired but value is not yet right */
157 goto read_again;
159 free(path);
160 free(cmd_str);
161 free(ret_str);
162 }
164 int
165 main(int argc, char **argv)
166 {
167 unsigned int maxit, max_f;
168 int io_fd, ret, port;
169 struct save_callbacks callbacks;
171 if (argc != 6)
172 errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
174 si.xc_fd = xc_interface_open();
175 if (si.xc_fd < 0)
176 errx(1, "failed to open control interface");
178 io_fd = atoi(argv[1]);
179 si.domid = atoi(argv[2]);
180 maxit = atoi(argv[3]);
181 max_f = atoi(argv[4]);
182 si.flags = atoi(argv[5]);
184 si.suspend_evtchn = si.xce = -1;
186 si.xce = xc_evtchn_open();
187 if (si.xce < 0)
188 warnx("failed to open event channel handle");
190 if (si.xce > 0)
191 {
192 port = xs_suspend_evtchn_port(si.domid);
194 if (port < 0)
195 warnx("failed to get the suspend evtchn port\n");
196 else
197 {
198 si.suspend_evtchn =
199 xc_suspend_evtchn_init(si.xc_fd, si.xce, si.domid, port);
201 if (si.suspend_evtchn < 0)
202 warnx("suspend event channel initialization failed"
203 "using slow path");
204 }
205 }
206 memset(&callbacks, 0, sizeof(callbacks));
207 callbacks.suspend = suspend;
208 ret = xc_domain_save(si.xc_fd, io_fd, si.domid, maxit, max_f, si.flags,
209 &callbacks, !!(si.flags & XCFLAGS_HVM),
210 &switch_qemu_logdirty);
212 if (si.suspend_evtchn > 0)
213 xc_suspend_evtchn_release(si.xce, si.suspend_evtchn);
215 if (si.xce > 0)
216 xc_evtchn_close(si.xce);
218 xc_interface_close(si.xc_fd);
220 return ret;
221 }