debuggers.hg

view tools/libxl/libxl_dom.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 de9c5e366527
children aef25086c71c
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
16 #include "libxl_osdeps.h"
18 #include <stdio.h>
19 #include <inttypes.h>
20 #include <string.h>
21 #include <sys/time.h> /* for struct timeval */
22 #include <unistd.h> /* for sleep(2) */
24 #include <xenctrl.h>
25 #include <xc_dom.h>
26 #include <xenguest.h>
27 #include <fcntl.h>
29 #include "libxl.h"
30 #include "libxl_internal.h"
32 int is_hvm(struct libxl_ctx *ctx, uint32_t domid)
33 {
34 xc_domaininfo_t info;
35 int ret;
37 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
38 if (ret != 1)
39 return -1;
40 if (info.domain != domid)
41 return -1;
42 return !!(info.flags & XEN_DOMINF_hvm_guest);
43 }
45 int get_shutdown_reason(struct libxl_ctx *ctx, uint32_t domid)
46 {
47 xc_domaininfo_t info;
48 int ret;
50 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
51 if (ret != 1)
52 return -1;
53 if (info.domain != domid)
54 return -1;
55 if (!(info.flags & XEN_DOMINF_shutdown))
56 return -1;
57 return dominfo_get_shutdown_reason(&info);
58 }
60 int build_pre(struct libxl_ctx *ctx, uint32_t domid,
61 libxl_domain_build_info *info, libxl_domain_build_state *state)
62 {
63 if (info->timer_mode != -1)
64 xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_TIMER_MODE,
65 (unsigned long) info->timer_mode);
66 if (info->hpet != -1)
67 xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) info->hpet);
68 if (info->vpt_align != -1)
69 xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_VPT_ALIGN, (unsigned long) info->vpt_align);
70 xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus);
71 xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + LIBXL_MAXMEM_CONSTANT);
72 xc_domain_set_memmap_limit(ctx->xch, domid,
73 (info->hvm) ? info->max_memkb :
74 (info->max_memkb + info->u.pv.slack_memkb));
76 if (info->hvm) {
77 unsigned long shadow;
78 shadow = (info->shadow_memkb + 1023) / 1024;
79 xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL);
80 }
82 state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
83 state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
84 return 0;
85 }
87 int build_post(struct libxl_ctx *ctx, uint32_t domid,
88 libxl_domain_build_info *info, libxl_domain_build_state *state,
89 char **vms_ents, char **local_ents)
90 {
91 char *dom_path, *vm_path;
92 xs_transaction_t t;
93 char **ents;
94 int i;
96 #if defined(__i386__) || defined(__x86_64__)
97 xc_cpuid_apply_policy(ctx->xch, domid);
98 #endif
100 ents = libxl_calloc(ctx, (10 + info->max_vcpus) * 2, sizeof(char *));
101 ents[0] = "memory/static-max";
102 ents[1] = libxl_sprintf(ctx, "%d", info->max_memkb);
103 ents[2] = "memory/target";
104 ents[3] = libxl_sprintf(ctx, "%d", info->target_memkb);
105 ents[2] = "memory/videoram";
106 ents[3] = libxl_sprintf(ctx, "%d", info->video_memkb);
107 ents[4] = "domid";
108 ents[5] = libxl_sprintf(ctx, "%d", domid);
109 ents[6] = "store/port";
110 ents[7] = libxl_sprintf(ctx, "%"PRIu32, state->store_port);
111 ents[8] = "store/ring-ref";
112 ents[9] = libxl_sprintf(ctx, "%lu", state->store_mfn);
113 for (i = 0; i < info->max_vcpus; i++) {
114 ents[10+(i*2)] = libxl_sprintf(ctx, "cpu/%d/availability", i);
115 ents[10+(i*2)+1] = (i && info->cur_vcpus && (i >= info->cur_vcpus))
116 ? "offline" : "online";
117 }
119 dom_path = libxl_xs_get_dompath(ctx, domid);
120 if (!dom_path)
121 return ERROR_FAIL;
123 vm_path = xs_read(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "%s/vm", dom_path), NULL);
124 retry_transaction:
125 t = xs_transaction_start(ctx->xsh);
127 libxl_xs_writev(ctx, t, dom_path, ents);
128 libxl_xs_writev(ctx, t, dom_path, local_ents);
129 libxl_xs_writev(ctx, t, vm_path, vms_ents);
131 if (!xs_transaction_end(ctx->xsh, t, 0))
132 if (errno == EAGAIN)
133 goto retry_transaction;
134 xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
135 free(vm_path);
136 libxl_free(ctx, ents);
137 libxl_free(ctx, dom_path);
138 return 0;
139 }
141 int build_pv(struct libxl_ctx *ctx, uint32_t domid,
142 libxl_domain_build_info *info, libxl_domain_build_state *state)
143 {
144 struct xc_dom_image *dom;
145 int ret;
146 int flags = 0;
148 dom = xc_dom_allocate(info->u.pv.cmdline, info->u.pv.features);
149 if (!dom) {
150 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_allocate failed");
151 return -1;
152 }
153 ret = xc_dom_linux_build(ctx->xch, dom, domid, info->target_memkb / 1024,
154 info->kernel, info->u.pv.ramdisk, flags,
155 state->store_port, &state->store_mfn,
156 state->console_port, &state->console_mfn);
157 if (ret != 0) {
158 xc_dom_release(dom);
159 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "xc_dom_linux_build failed");
160 return -2;
161 }
162 xc_dom_release(dom);
163 return 0;
164 }
166 int build_hvm(struct libxl_ctx *ctx, uint32_t domid,
167 libxl_domain_build_info *info, libxl_domain_build_state *state)
168 {
169 int ret;
171 ret = xc_hvm_build_target_mem(ctx->xch, domid, (info->max_memkb - info->video_memkb) / 1024, (info->target_memkb - info->video_memkb) / 1024, info->kernel);
172 if (ret) {
173 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm building failed");
174 return ERROR_FAIL;
175 }
176 ret = hvm_build_set_params(ctx->xch, domid, info->u.hvm.apic, info->u.hvm.acpi,
177 info->u.hvm.pae, info->u.hvm.nx, info->u.hvm.viridian,
178 info->max_vcpus,
179 state->store_port, &state->store_mfn);
180 if (ret) {
181 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm build set params failed");
182 return ERROR_FAIL;
183 }
184 return 0;
185 }
187 int restore_common(struct libxl_ctx *ctx, uint32_t domid,
188 libxl_domain_build_info *info, libxl_domain_build_state *state,
189 int fd)
190 {
191 /* read signature */
192 xc_domain_restore(ctx->xch, fd, domid,
193 state->store_port, &state->store_mfn,
194 state->console_port, &state->console_mfn,
195 info->hvm, info->u.hvm.pae, 0);
196 return 0;
197 }
199 struct suspendinfo {
200 struct libxl_ctx *ctx;
201 int xce; /* event channel handle */
202 int suspend_eventchn;
203 int domid;
204 int hvm;
205 unsigned int flags;
206 };
208 static void core_suspend_switch_qemu_logdirty(int domid, unsigned int enable)
209 {
210 struct xs_handle *xsh;
211 char path[64];
213 snprintf(path, sizeof(path), "/local/domain/0/device-model/%u/logdirty/cmd", domid);
215 xsh = xs_daemon_open();
217 if (enable)
218 xs_write(xsh, XBT_NULL, path, "enable", strlen("enable"));
219 else
220 xs_write(xsh, XBT_NULL, path, "disable", strlen("disable"));
222 xs_daemon_close(xsh);
223 }
225 static int core_suspend_callback(void *data)
226 {
227 struct suspendinfo *si = data;
228 unsigned long s_state = 0;
229 int ret;
230 char *path, *state = "suspend";
231 int watchdog = 60;
233 if (si->hvm)
234 xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &s_state);
235 if ((s_state == 0) && (si->suspend_eventchn >= 0)) {
236 ret = xc_evtchn_notify(si->xce, si->suspend_eventchn);
237 if (ret < 0) {
238 XL_LOG(si->ctx, XL_LOG_ERROR, "xc_evtchn_notify failed ret=%d", ret);
239 return 0;
240 }
241 ret = xc_await_suspend(si->xce, si->suspend_eventchn);
242 if (ret < 0) {
243 XL_LOG(si->ctx, XL_LOG_ERROR, "xc_await_suspend failed ret=%d", ret);
244 return 0;
245 }
246 return 1;
247 }
248 path = libxl_sprintf(si->ctx, "%s/control/shutdown", libxl_xs_get_dompath(si->ctx, si->domid));
249 libxl_xs_write(si->ctx, XBT_NULL, path, "suspend", strlen("suspend"));
250 if (si->hvm) {
251 unsigned long hvm_pvdrv, hvm_s_state;
252 xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_CALLBACK_IRQ, &hvm_pvdrv);
253 xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &hvm_s_state);
254 if (!hvm_pvdrv || hvm_s_state) {
255 XL_LOG(si->ctx, XL_LOG_DEBUG, "Calling xc_domain_shutdown on the domain");
256 xc_domain_shutdown(si->ctx->xch, si->domid, SHUTDOWN_suspend);
257 }
258 }
259 XL_LOG(si->ctx, XL_LOG_DEBUG, "wait for the guest to suspend");
260 while (!strcmp(state, "suspend") && watchdog > 0) {
261 xc_domaininfo_t info;
263 usleep(100000);
264 ret = xc_domain_getinfolist(si->ctx->xch, si->domid, 1, &info);
265 if (ret == 1 && info.domain == si->domid && info.flags & XEN_DOMINF_shutdown) {
266 int shutdown_reason;
268 shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
269 if (shutdown_reason == SHUTDOWN_suspend)
270 return 1;
271 }
272 state = libxl_xs_read(si->ctx, XBT_NULL, path);
273 watchdog--;
274 }
275 if (!strcmp(state, "suspend")) {
276 XL_LOG(si->ctx, XL_LOG_ERROR, "guest didn't suspend in time");
277 libxl_xs_write(si->ctx, XBT_NULL, path, "", 1);
278 }
279 return 1;
280 }
282 int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd,
283 int hvm, int live, int debug)
284 {
285 int flags;
286 int port;
287 struct save_callbacks callbacks;
288 struct suspendinfo si;
290 flags = (live) ? XCFLAGS_LIVE : 0
291 | (debug) ? XCFLAGS_DEBUG : 0
292 | (hvm) ? XCFLAGS_HVM : 0;
294 si.domid = domid;
295 si.flags = flags;
296 si.hvm = hvm;
297 si.ctx = ctx;
298 si.suspend_eventchn = -1;
300 si.xce = xc_evtchn_open();
301 if (si.xce < 0)
302 return -1;
304 if (si.xce > 0) {
305 port = xs_suspend_evtchn_port(si.domid);
307 if (port < 0) {
308 XL_LOG(ctx, XL_LOG_WARNING, "Failed to get the suspend evtchn port");
309 } else {
310 si.suspend_eventchn = xc_suspend_evtchn_init(si.ctx->xch, si.xce, si.domid, port);
312 if (si.suspend_eventchn < 0)
313 XL_LOG(ctx, XL_LOG_WARNING, "Suspend event channel initialization failed");
314 }
315 }
317 memset(&callbacks, 0, sizeof(callbacks));
318 callbacks.suspend = core_suspend_callback;
319 callbacks.data = &si;
321 xc_domain_save(ctx->xch, fd, domid, 0, 0, flags,
322 &callbacks, hvm,
323 &core_suspend_switch_qemu_logdirty);
325 if (si.suspend_eventchn > 0)
326 xc_suspend_evtchn_release(si.xce, si.suspend_eventchn);
327 if (si.xce > 0)
328 xc_evtchn_close(si.xce);
330 return 0;
331 }
333 int save_device_model(struct libxl_ctx *ctx, uint32_t domid, int fd)
334 {
335 int fd2, c;
336 char buf[1024];
337 char *filename = libxl_sprintf(ctx, "/var/lib/xen/qemu-save.%d", domid);
339 XL_LOG(ctx, XL_LOG_DEBUG, "Saving device model state to %s", filename);
340 libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "save", strlen("save"));
341 libxl_wait_for_device_model(ctx, domid, "paused", NULL, NULL);
343 write(fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE));
344 fd2 = open(filename, O_RDONLY);
345 while ((c = read(fd2, buf, sizeof(buf))) != 0) {
346 write(fd, buf, c);
347 }
348 close(fd2);
349 unlink(filename);
350 return 0;
351 }