debuggers.hg

annotate tools/libxl/libxl_dom.c @ 22624:60782cefa154

libxc: convert evtchn interfaces to use an opaque handle type

This makes the interface consistent with the changes made to the main
interface in 21483:779c0ef9682c.

Also fix some references to "struct xc_interface" which should have
been simply "xc_interface" in tools/xenpaging, and update QEMU_TAG to
pull in the corresponding qemu change.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Ian Campbell <ian.campbell@citrix.com>
date Thu Dec 23 15:25:57 2010 +0000 (2010-12-23)
parents ab785e37499c
children 4fea7664a6fb
rev   line source
keir@20462 1 /*
keir@20462 2 * Copyright (C) 2009 Citrix Ltd.
keir@20462 3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
keir@20462 4 *
keir@20462 5 * This program is free software; you can redistribute it and/or modify
keir@20462 6 * it under the terms of the GNU Lesser General Public License as published
keir@20462 7 * by the Free Software Foundation; version 2.1 only. with the special
keir@20462 8 * exception on linking described in file LICENSE.
keir@20462 9 *
keir@20462 10 * This program is distributed in the hope that it will be useful,
keir@20462 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
keir@20462 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
keir@20462 13 * GNU Lesser General Public License for more details.
keir@20462 14 */
keir@20462 15
keir@20513 16 #include "libxl_osdeps.h"
keir@20513 17
keir@20509 18 #include <stdio.h>
keir@21190 19 #include <assert.h>
keir@21190 20 #include <glob.h>
keir@20462 21 #include <inttypes.h>
keir@20462 22 #include <string.h>
ian@22166 23 #include <sys/mman.h>
keir@20468 24 #include <sys/time.h> /* for struct timeval */
gianni@22389 25 #include <sys/stat.h> /* for stat */
keir@20468 26 #include <unistd.h> /* for sleep(2) */
keir@20462 27
keir@20513 28 #include <xenctrl.h>
keir@20513 29 #include <xc_dom.h>
keir@20513 30 #include <xenguest.h>
keir@20779 31 #include <fcntl.h>
keir@20513 32
ian@22166 33 #include <xen/hvm/hvm_info_table.h>
ian@22166 34
keir@20513 35 #include "libxl.h"
keir@20513 36 #include "libxl_internal.h"
keir@20513 37
ian@22165 38 int libxl__domain_is_hvm(libxl_ctx *ctx, uint32_t domid)
keir@20462 39 {
keir@20462 40 xc_domaininfo_t info;
keir@20462 41 int ret;
keir@20462 42
keir@20462 43 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
keir@20462 44 if (ret != 1)
keir@20462 45 return -1;
keir@20462 46 if (info.domain != domid)
keir@20462 47 return -1;
keir@20462 48 return !!(info.flags & XEN_DOMINF_hvm_guest);
keir@20462 49 }
keir@20462 50
ian@22165 51 int libxl__domain_shutdown_reason(libxl_ctx *ctx, uint32_t domid)
keir@20786 52 {
keir@20786 53 xc_domaininfo_t info;
keir@20786 54 int ret;
keir@20786 55
keir@20786 56 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
keir@20786 57 if (ret != 1)
keir@20786 58 return -1;
keir@20786 59 if (info.domain != domid)
keir@20786 60 return -1;
keir@20786 61 if (!(info.flags & XEN_DOMINF_shutdown))
keir@20786 62 return -1;
ian@22165 63
ian@22165 64 return (info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
keir@20786 65 }
keir@20786 66
ian@22165 67 int libxl__build_pre(libxl_ctx *ctx, uint32_t domid,
keir@20462 68 libxl_domain_build_info *info, libxl_domain_build_state *state)
keir@20462 69 {
keir@20462 70 xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus);
keir@20647 71 xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + LIBXL_MAXMEM_CONSTANT);
keir@20632 72 xc_domain_set_memmap_limit(ctx->xch, domid,
keir@20632 73 (info->hvm) ? info->max_memkb :
keir@20632 74 (info->max_memkb + info->u.pv.slack_memkb));
keir@21144 75 xc_domain_set_tsc_info(ctx->xch, domid, info->tsc_mode, 0, 0, 0);
Ian@21802 76 if ( info->disable_migrate )
Ian@21802 77 xc_domain_disable_migrate(ctx->xch, domid);
keir@20509 78
keir@20509 79 if (info->hvm) {
keir@20509 80 unsigned long shadow;
keir@20509 81 shadow = (info->shadow_memkb + 1023) / 1024;
keir@20509 82 xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL);
keir@20509 83 }
keir@20462 84
keir@20462 85 state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
keir@20462 86 state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
keir@20462 87 return 0;
keir@20462 88 }
keir@20462 89
ian@22165 90 int libxl__build_post(libxl_ctx *ctx, uint32_t domid,
keir@20462 91 libxl_domain_build_info *info, libxl_domain_build_state *state,
keir@20462 92 char **vms_ents, char **local_ents)
keir@20462 93 {
ian@22167 94 libxl__gc gc = LIBXL_INIT_GC(ctx);
keir@20462 95 char *dom_path, *vm_path;
keir@20462 96 xs_transaction_t t;
keir@20462 97 char **ents;
keir@20582 98 int i;
keir@20462 99
kuwa@22425 100 libxl_cpuid_apply_policy(ctx, domid);
kuwa@22425 101 if (info->cpuid != NULL)
kuwa@22425 102 libxl_cpuid_set(ctx, domid, info->cpuid);
keir@20806 103
ian@22164 104 ents = libxl__calloc(&gc, 12 + (info->max_vcpus * 2) + 2, sizeof(char *));
keir@20516 105 ents[0] = "memory/static-max";
ian@22164 106 ents[1] = libxl__sprintf(&gc, "%d", info->max_memkb);
keir@20516 107 ents[2] = "memory/target";
stefano@22251 108 ents[3] = libxl__sprintf(&gc, "%d", info->target_memkb - info->video_memkb);
keir@21423 109 ents[4] = "memory/videoram";
ian@22164 110 ents[5] = libxl__sprintf(&gc, "%d", info->video_memkb);
keir@21423 111 ents[6] = "domid";
ian@22164 112 ents[7] = libxl__sprintf(&gc, "%d", domid);
keir@21423 113 ents[8] = "store/port";
ian@22164 114 ents[9] = libxl__sprintf(&gc, "%"PRIu32, state->store_port);
keir@21423 115 ents[10] = "store/ring-ref";
ian@22164 116 ents[11] = libxl__sprintf(&gc, "%lu", state->store_mfn);
keir@20582 117 for (i = 0; i < info->max_vcpus; i++) {
ian@22164 118 ents[12+(i*2)] = libxl__sprintf(&gc, "cpu/%d/availability", i);
keir@21570 119 ents[12+(i*2)+1] = (i && info->cur_vcpus && !(info->cur_vcpus & (1 << i)))
keir@20584 120 ? "offline" : "online";
keir@20582 121 }
keir@20462 122
ian@22164 123 dom_path = libxl__xs_get_dompath(&gc, domid);
juergen@22549 124 if (!dom_path) {
juergen@22549 125 libxl__free_all(&gc);
keir@20512 126 return ERROR_FAIL;
juergen@22549 127 }
keir@20512 128
ian@22164 129 vm_path = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path), NULL);
keir@20462 130 retry_transaction:
keir@20462 131 t = xs_transaction_start(ctx->xsh);
keir@20462 132
ian@22164 133 libxl__xs_writev(&gc, t, dom_path, ents);
ian@22164 134 libxl__xs_writev(&gc, t, dom_path, local_ents);
ian@22164 135 libxl__xs_writev(&gc, t, vm_path, vms_ents);
keir@20462 136
keir@20462 137 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20462 138 if (errno == EAGAIN)
keir@20462 139 goto retry_transaction;
keir@20462 140 xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
keir@20516 141 free(vm_path);
ian@22164 142 libxl__free_all(&gc);
keir@20462 143 return 0;
keir@20462 144 }
keir@20462 145
ian@22165 146 int libxl__build_pv(libxl_ctx *ctx, uint32_t domid,
keir@20462 147 libxl_domain_build_info *info, libxl_domain_build_state *state)
keir@20462 148 {
keir@20509 149 struct xc_dom_image *dom;
keir@20509 150 int ret;
keir@20509 151 int flags = 0;
keir@20509 152
Ian@21848 153 xc_dom_loginit(ctx->xch);
Ian@21848 154
keir@21529 155 dom = xc_dom_allocate(ctx->xch, info->u.pv.cmdline, info->u.pv.features);
keir@20509 156 if (!dom) {
ian@22165 157 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_allocate failed");
Ian@21848 158 return ERROR_FAIL;
Ian@21848 159 }
Ian@21848 160
Ian@21848 161 if (info->kernel.mapped) {
Ian@21848 162 if ( (ret = xc_dom_kernel_mem(dom, info->kernel.data, info->kernel.size)) != 0) {
ian@22165 163 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_kernel_mem failed");
Ian@21848 164 goto out;
Ian@21848 165 }
Ian@21848 166 } else {
Ian@21848 167 if ( (ret = xc_dom_kernel_file(dom, info->kernel.path)) != 0) {
ian@22165 168 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_kernel_file failed");
Ian@21848 169 goto out;
Ian@21848 170 }
Ian@21848 171 }
Ian@21848 172
Ian@21848 173 if ( info->u.pv.ramdisk.path && strlen(info->u.pv.ramdisk.path) ) {
Ian@21848 174 if (info->u.pv.ramdisk.mapped) {
Ian@21848 175 if ( (ret = xc_dom_ramdisk_mem(dom, info->u.pv.ramdisk.data, info->u.pv.ramdisk.size)) != 0 ) {
ian@22165 176 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_ramdisk_mem failed");
Ian@21848 177 goto out;
Ian@21848 178 }
Ian@21848 179 } else {
Ian@21848 180 if ( (ret = xc_dom_ramdisk_file(dom, info->u.pv.ramdisk.path)) != 0 ) {
ian@22165 181 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_ramdisk_file failed");
Ian@21848 182 goto out;
Ian@21848 183 }
Ian@21848 184 }
keir@20509 185 }
Ian@21848 186
Ian@21848 187 dom->flags = flags;
Ian@21848 188 dom->console_evtchn = state->console_port;
Ian@21848 189 dom->xenstore_evtchn = state->store_port;
Ian@21848 190
Ian@21848 191 if ( (ret = xc_dom_boot_xen_init(dom, ctx->xch, domid)) != 0 ) {
ian@22165 192 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_boot_xen_init failed");
Ian@21848 193 goto out;
Ian@21848 194 }
Ian@21848 195 if ( (ret = xc_dom_parse_image(dom)) != 0 ) {
ian@22165 196 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_parse_image failed");
Ian@21848 197 goto out;
Ian@21848 198 }
Ian@21848 199 if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) {
ian@22165 200 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_mem_init failed");
Ian@21848 201 goto out;
keir@20509 202 }
Ian@21848 203 if ( (ret = xc_dom_boot_mem_init(dom)) != 0 ) {
ian@22165 204 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_boot_mem_init failed");
Ian@21848 205 goto out;
Ian@21848 206 }
Ian@21848 207 if ( (ret = xc_dom_build_image(dom)) != 0 ) {
ian@22165 208 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_build_image failed");
Ian@21848 209 goto out;
Ian@21848 210 }
Ian@21848 211 if ( (ret = xc_dom_boot_image(dom)) != 0 ) {
ian@22165 212 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_boot_image failed");
Ian@21848 213 goto out;
Ian@21848 214 }
Ian@21848 215
Ian@21848 216 state->console_mfn = xc_dom_p2m_host(dom, dom->console_pfn);
Ian@21848 217 state->store_mfn = xc_dom_p2m_host(dom, dom->xenstore_pfn);
Ian@21848 218
Ian@21848 219 ret = 0;
Ian@21848 220 out:
keir@20509 221 xc_dom_release(dom);
Ian@21888 222 return ret == 0 ? 0 : ERROR_FAIL;
keir@20462 223 }
keir@20462 224
ian@22166 225 static int hvm_build_set_params(xc_interface *handle, uint32_t domid,
ian@22166 226 libxl_domain_build_info *info,
ian@22166 227 int store_evtchn, unsigned long *store_mfn,
ian@22166 228 int console_evtchn, unsigned long *console_mfn)
ian@22166 229 {
ian@22166 230 struct hvm_info_table *va_hvm;
ian@22166 231 uint8_t *va_map, sum;
ian@22166 232 int i;
ian@22166 233
ian@22166 234 va_map = xc_map_foreign_range(handle, domid,
ian@22166 235 XC_PAGE_SIZE, PROT_READ | PROT_WRITE,
ian@22166 236 HVM_INFO_PFN);
ian@22166 237 if (va_map == NULL)
ian@22166 238 return -1;
ian@22166 239
ian@22166 240 va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
ian@22166 241 va_hvm->acpi_enabled = info->u.hvm.acpi;
ian@22166 242 va_hvm->apic_mode = info->u.hvm.apic;
ian@22166 243 va_hvm->nr_vcpus = info->max_vcpus;
ian@22166 244 memcpy(va_hvm->vcpu_online, &info->cur_vcpus, sizeof(info->cur_vcpus));
ian@22166 245 for (i = 0, sum = 0; i < va_hvm->length; i++)
ian@22166 246 sum += ((uint8_t *) va_hvm)[i];
ian@22166 247 va_hvm->checksum -= sum;
ian@22166 248 munmap(va_map, XC_PAGE_SIZE);
ian@22166 249
ian@22166 250 xc_get_hvm_param(handle, domid, HVM_PARAM_STORE_PFN, store_mfn);
ian@22166 251 xc_get_hvm_param(handle, domid, HVM_PARAM_CONSOLE_PFN, console_mfn);
ian@22166 252 xc_set_hvm_param(handle, domid, HVM_PARAM_PAE_ENABLED, info->u.hvm.pae);
ian@22166 253 #if defined(__i386__) || defined(__x86_64__)
ian@22166 254 xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, info->u.hvm.viridian);
ian@22166 255 xc_set_hvm_param(handle, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) info->u.hvm.hpet);
ian@22166 256 #endif
ian@22166 257 xc_set_hvm_param(handle, domid, HVM_PARAM_TIMER_MODE, (unsigned long) info->u.hvm.timer_mode);
ian@22166 258 xc_set_hvm_param(handle, domid, HVM_PARAM_VPT_ALIGN, (unsigned long) info->u.hvm.vpt_align);
ian@22166 259 xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn);
ian@22166 260 xc_set_hvm_param(handle, domid, HVM_PARAM_CONSOLE_EVTCHN, console_evtchn);
ian@22166 261 return 0;
ian@22166 262 }
ian@22166 263
ian@22165 264 int libxl__build_hvm(libxl_ctx *ctx, uint32_t domid,
keir@20462 265 libxl_domain_build_info *info, libxl_domain_build_state *state)
keir@20462 266 {
ian@22167 267 libxl__gc gc = LIBXL_INIT_GC(ctx);
gianni@22023 268 int ret, rc = ERROR_INVAL;
keir@20462 269
Ian@21848 270 if (info->kernel.mapped) {
ian@22165 271 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "libxl__build_hvm kernel cannot be mmapped");
gianni@22023 272 goto out;
Ian@21848 273 }
Ian@21848 274
gianni@22023 275 rc = ERROR_FAIL;
keir@21353 276 ret = xc_hvm_build_target_mem(
keir@21353 277 ctx->xch,
keir@21353 278 domid,
keir@21353 279 (info->max_memkb - info->video_memkb) / 1024,
keir@21353 280 (info->target_memkb - info->video_memkb) / 1024,
ian@22164 281 libxl__abs_path(&gc, (char *)info->kernel.path,
keir@21353 282 libxl_xenfirmwaredir_path()));
keir@20462 283 if (ret) {
ian@22165 284 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm building failed");
gianni@22023 285 goto out;
keir@20462 286 }
keir@21570 287 ret = hvm_build_set_params(ctx->xch, domid, info, state->store_port,
sstabellini@21977 288 &state->store_mfn, state->console_port, &state->console_mfn);
keir@20462 289 if (ret) {
ian@22165 290 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm build set params failed");
gianni@22023 291 goto out;
keir@20462 292 }
gianni@22023 293 rc = 0;
gianni@22023 294 out:
ian@22164 295 libxl__free_all(&gc);
keir@20462 296 return 0;
keir@20462 297 }
keir@20462 298
ian@22165 299 int libxl__domain_restore_common(libxl_ctx *ctx, uint32_t domid,
keir@20462 300 libxl_domain_build_info *info, libxl_domain_build_state *state,
keir@20462 301 int fd)
keir@20462 302 {
keir@20462 303 /* read signature */
gianni@21892 304 int rc;
gianni@21892 305 rc = xc_domain_restore(ctx->xch, fd, domid,
keir@21660 306 state->store_port, &state->store_mfn,
keir@21660 307 state->console_port, &state->console_mfn,
keir@21660 308 info->hvm, info->u.hvm.pae, 0);
ian@22106 309 if ( rc ) {
ian@22165 310 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "restoring domain");
gianni@21892 311 return ERROR_FAIL;
gianni@21892 312 }
gianni@21892 313 return 0;
keir@20462 314 }
keir@20462 315
keir@20565 316 struct suspendinfo {
ian@22167 317 libxl__gc *gc;
ian@22624 318 xc_evtchn *xce; /* event channel handle */
keir@20462 319 int suspend_eventchn;
keir@20462 320 int domid;
keir@20462 321 int hvm;
keir@20462 322 unsigned int flags;
keir@20565 323 };
keir@20462 324
ian@22321 325 static int libxl__domain_suspend_common_switch_qemu_logdirty(int domid, unsigned int enable, void *data)
keir@20565 326 {
ian@22321 327 struct suspendinfo *si = data;
ian@22321 328 libxl_ctx *ctx = libxl__gc_owner(si->gc);
ian@22321 329 char *path;
ian@22321 330 bool rc;
keir@20565 331
ian@22321 332 path = libxl__sprintf(si->gc, "/local/domain/0/device-model/%u/logdirty/cmd", domid);
ian@22321 333 if (!path)
ian@22321 334 return 1;
keir@20462 335
keir@20565 336 if (enable)
ian@22321 337 rc = xs_write(ctx->xsh, XBT_NULL, path, "enable", strlen("enable"));
keir@20565 338 else
ian@22321 339 rc = xs_write(ctx->xsh, XBT_NULL, path, "disable", strlen("disable"));
keir@20462 340
ian@22321 341 return rc ? 0 : 1;
keir@20462 342 }
keir@20462 343
ian@22165 344 static int libxl__domain_suspend_common_callback(void *data)
keir@20462 345 {
keir@20468 346 struct suspendinfo *si = data;
keir@20462 347 unsigned long s_state = 0;
keir@20462 348 int ret;
keir@20565 349 char *path, *state = "suspend";
keir@20565 350 int watchdog = 60;
ian@22167 351 libxl_ctx *ctx = libxl__gc_owner(si->gc);
keir@20462 352
keir@20468 353 if (si->hvm)
gianni@22023 354 xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &s_state);
keir@20468 355 if ((s_state == 0) && (si->suspend_eventchn >= 0)) {
keir@20565 356 ret = xc_evtchn_notify(si->xce, si->suspend_eventchn);
keir@20462 357 if (ret < 0) {
ian@22165 358 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "xc_evtchn_notify failed ret=%d", ret);
keir@20462 359 return 0;
keir@20462 360 }
gianni@22023 361 ret = xc_await_suspend(ctx->xch, si->xce, si->suspend_eventchn);
keir@20462 362 if (ret < 0) {
ian@22165 363 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "xc_await_suspend failed ret=%d", ret);
keir@20462 364 return 0;
keir@20462 365 }
keir@20462 366 return 1;
keir@20462 367 }
ian@22164 368 path = libxl__sprintf(si->gc, "%s/control/shutdown", libxl__xs_get_dompath(si->gc, si->domid));
ian@22164 369 libxl__xs_write(si->gc, XBT_NULL, path, "suspend");
keir@20565 370 if (si->hvm) {
keir@20565 371 unsigned long hvm_pvdrv, hvm_s_state;
gianni@22023 372 xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_CALLBACK_IRQ, &hvm_pvdrv);
gianni@22023 373 xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &hvm_s_state);
keir@20565 374 if (!hvm_pvdrv || hvm_s_state) {
ian@22165 375 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Calling xc_domain_shutdown on the domain");
gianni@22023 376 xc_domain_shutdown(ctx->xch, si->domid, SHUTDOWN_suspend);
keir@20565 377 }
keir@20565 378 }
ian@22165 379 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "wait for the guest to suspend");
keir@20565 380 while (!strcmp(state, "suspend") && watchdog > 0) {
keir@20785 381 xc_domaininfo_t info;
keir@20785 382
keir@20565 383 usleep(100000);
gianni@22023 384 ret = xc_domain_getinfolist(ctx->xch, si->domid, 1, &info);
keir@20785 385 if (ret == 1 && info.domain == si->domid && info.flags & XEN_DOMINF_shutdown) {
keir@20785 386 int shutdown_reason;
keir@20785 387
keir@20785 388 shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
keir@20785 389 if (shutdown_reason == SHUTDOWN_suspend)
keir@20785 390 return 1;
keir@20565 391 }
ian@22164 392 state = libxl__xs_read(si->gc, XBT_NULL, path);
keir@20565 393 watchdog--;
keir@20565 394 }
keir@20565 395 if (!strcmp(state, "suspend")) {
ian@22165 396 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "guest didn't suspend in time");
ian@22164 397 libxl__xs_write(si->gc, XBT_NULL, path, "");
keir@20565 398 }
keir@20565 399 return 1;
keir@20462 400 }
keir@20462 401
ian@22165 402 int libxl__domain_suspend_common(libxl_ctx *ctx, uint32_t domid, int fd,
keir@20468 403 int hvm, int live, int debug)
keir@20462 404 {
ian@22167 405 libxl__gc gc = LIBXL_INIT_GC(ctx);
keir@20462 406 int flags;
keir@20462 407 int port;
keir@20565 408 struct save_callbacks callbacks;
keir@20565 409 struct suspendinfo si;
gianni@22023 410 int rc = ERROR_FAIL;
keir@20462 411
keir@20462 412 flags = (live) ? XCFLAGS_LIVE : 0
keir@20565 413 | (debug) ? XCFLAGS_DEBUG : 0
keir@20565 414 | (hvm) ? XCFLAGS_HVM : 0;
keir@20462 415
keir@20462 416 si.domid = domid;
keir@20462 417 si.flags = flags;
keir@20462 418 si.hvm = hvm;
gianni@22023 419 si.gc = &gc;
keir@20565 420 si.suspend_eventchn = -1;
keir@20462 421
ian@22624 422 si.xce = xc_evtchn_open(NULL, 0);
ian@22624 423 if (si.xce == NULL)
gianni@22023 424 goto out;
ian@22624 425 else
ian@22624 426 {
keir@20462 427 port = xs_suspend_evtchn_port(si.domid);
keir@20462 428
ian@22145 429 if (port >= 0) {
gianni@22023 430 si.suspend_eventchn = xc_suspend_evtchn_init(ctx->xch, si.xce, si.domid, port);
keir@20462 431
keir@20565 432 if (si.suspend_eventchn < 0)
ian@22165 433 LIBXL__LOG(ctx, LIBXL__LOG_WARNING, "Suspend event channel initialization failed");
keir@20462 434 }
keir@20462 435 }
keir@20462 436
keir@20565 437 memset(&callbacks, 0, sizeof(callbacks));
ian@22165 438 callbacks.suspend = libxl__domain_suspend_common_callback;
ian@22321 439 callbacks.switch_qemu_logdirty = libxl__domain_suspend_common_switch_qemu_logdirty;
keir@20468 440 callbacks.data = &si;
keir@20468 441
ian@22371 442 rc = xc_domain_save(ctx->xch, fd, domid, 0, 0, flags, &callbacks, hvm);
ian@22371 443 if ( rc ) {
ian@22371 444 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "saving domain");
ian@22371 445 rc = ERROR_FAIL;
ian@22371 446 }
keir@20462 447
keir@20462 448 if (si.suspend_eventchn > 0)
gianni@22023 449 xc_suspend_evtchn_release(ctx->xch, si.xce, domid, si.suspend_eventchn);
ian@22624 450 if (si.xce != NULL)
keir@20462 451 xc_evtchn_close(si.xce);
keir@20462 452
gianni@22023 453 out:
ian@22321 454 libxl__free_all(&gc);
gianni@22023 455 return rc;
keir@20462 456 }
keir@20565 457
ian@22165 458 int libxl__domain_save_device_model(libxl_ctx *ctx, uint32_t domid, int fd)
keir@20779 459 {
ian@22167 460 libxl__gc gc = LIBXL_INIT_GC(ctx);
keir@20779 461 int fd2, c;
keir@20779 462 char buf[1024];
ian@22164 463 char *filename = libxl__sprintf(&gc, "/var/lib/xen/qemu-save.%d", domid);
ian@22371 464 struct stat st;
ian@22371 465 uint32_t qemu_state_len;
keir@20779 466
ian@22165 467 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Saving device model state to %s", filename);
ian@22164 468 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "save");
ian@22164 469 libxl__wait_for_device_model(ctx, domid, "paused", NULL, NULL);
keir@20779 470
ian@22371 471 if (stat(filename, &st) < 0)
ian@22371 472 {
ian@22371 473 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to stat qemu save file\n");
juergen@22549 474 libxl__free_all(&gc);
ian@22371 475 return ERROR_FAIL;
ian@22371 476 }
ian@22371 477
ian@22371 478 qemu_state_len = st.st_size;
ian@22371 479 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Qemu state is %d bytes\n", qemu_state_len);
ian@22371 480
keir@21417 481 c = libxl_write_exactly(ctx, fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE),
keir@21417 482 "saved-state file", "qemu signature");
juergen@22549 483 if (c) {
juergen@22549 484 libxl__free_all(&gc);
keir@21417 485 return c;
juergen@22549 486 }
ian@22371 487
ian@22371 488 c = libxl_write_exactly(ctx, fd, &qemu_state_len, sizeof(qemu_state_len),
ian@22371 489 "saved-state file", "saved-state length");
juergen@22549 490 if (c) {
juergen@22549 491 libxl__free_all(&gc);
ian@22371 492 return c;
juergen@22549 493 }
ian@22371 494
keir@20779 495 fd2 = open(filename, O_RDONLY);
keir@20779 496 while ((c = read(fd2, buf, sizeof(buf))) != 0) {
keir@21417 497 if (c < 0) {
keir@21417 498 if (errno == EINTR)
keir@21417 499 continue;
ian@22164 500 libxl__free_all(&gc);
keir@21417 501 return errno;
keir@21417 502 }
keir@21417 503 c = libxl_write_exactly(
keir@21417 504 ctx, fd, buf, c, "saved-state file", "qemu state");
gianni@22023 505 if (c) {
ian@22164 506 libxl__free_all(&gc);
keir@21417 507 return c;
gianni@22023 508 }
keir@20779 509 }
keir@20779 510 close(fd2);
keir@20779 511 unlink(filename);
ian@22164 512 libxl__free_all(&gc);
keir@20779 513 return 0;
keir@20779 514 }
keir@21188 515
ian@22167 516 char *libxl__uuid2string(libxl__gc *gc, const libxl_uuid uuid)
gianni@22023 517 {
ian@22164 518 char *s = libxl__sprintf(gc, LIBXL_UUID_FMT, LIBXL_UUID_BYTES(uuid));
gianni@22047 519 if (!s)
ian@22167 520 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, "cannot allocate for uuid");
gianni@22047 521 return s;
keir@21188 522 }
keir@21190 523
ian@22167 524 static const char *userdata_path(libxl__gc *gc, uint32_t domid,
keir@21190 525 const char *userdata_userid,
gianni@22023 526 const char *wh)
gianni@22023 527 {
ian@22167 528 libxl_ctx *ctx = libxl__gc_owner(gc);
keir@21190 529 char *path, *uuid_string;
ian@21930 530 libxl_dominfo info;
keir@21190 531 int rc;
keir@21190 532
keir@21190 533 rc = libxl_domain_info(ctx, &info, domid);
keir@21190 534 if (rc) {
ian@22165 535 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to find domain info"
keir@21531 536 " for domain %"PRIu32, domid);
gianni@21892 537 return NULL;
keir@21190 538 }
ian@22164 539 uuid_string = libxl__sprintf(gc, LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid));
keir@21190 540
ian@22164 541 path = libxl__sprintf(gc, "/var/lib/xen/"
ian@22154 542 "userdata-%s.%u.%s.%s",
ian@22154 543 wh, domid, uuid_string, userdata_userid);
keir@21190 544 if (!path)
ian@22165 545 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to allocate for"
keir@21190 546 " userdata path");
keir@21190 547 return path;
keir@21190 548 }
keir@21190 549
ian@21930 550 static int userdata_delete(libxl_ctx *ctx, const char *path) {
keir@21190 551 int r;
keir@21190 552 r = unlink(path);
keir@21190 553 if (r) {
ian@22165 554 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "remove failed for %s", path);
keir@21190 555 return errno;
keir@21190 556 }
keir@21190 557 return 0;
keir@21190 558 }
keir@21190 559
gianni@22023 560 void libxl__userdata_destroyall(libxl_ctx *ctx, uint32_t domid)
gianni@22023 561 {
ian@22167 562 libxl__gc gc = LIBXL_INIT_GC(ctx);
keir@21190 563 const char *pattern;
keir@21190 564 glob_t gl;
keir@21190 565 int r, i;
keir@21190 566
gianni@22023 567 pattern = userdata_path(&gc, domid, "*", "?");
gianni@22023 568 if (!pattern)
gianni@22023 569 goto out;
keir@21190 570
keir@21190 571 gl.gl_pathc = 0;
keir@21190 572 gl.gl_pathv = 0;
keir@21190 573 gl.gl_offs = 0;
keir@21190 574 r = glob(pattern, GLOB_ERR|GLOB_NOSORT|GLOB_MARK, 0, &gl);
gianni@22023 575 if (r == GLOB_NOMATCH)
gianni@22023 576 goto out;
gianni@22023 577 if (r)
ian@22165 578 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "glob failed for %s", pattern);
keir@21190 579
keir@21190 580 for (i=0; i<gl.gl_pathc; i++) {
keir@21190 581 userdata_delete(ctx, gl.gl_pathv[i]);
keir@21190 582 }
keir@21190 583 globfree(&gl);
gianni@22023 584 out:
ian@22164 585 libxl__free_all(&gc);
keir@21190 586 }
keir@21190 587
ian@21930 588 int libxl_userdata_store(libxl_ctx *ctx, uint32_t domid,
keir@21190 589 const char *userdata_userid,
gianni@22023 590 const uint8_t *data, int datalen)
gianni@22023 591 {
ian@22167 592 libxl__gc gc = LIBXL_INIT_GC(ctx);
keir@21190 593 const char *filename;
keir@21190 594 const char *newfilename;
gianni@22023 595 int e, rc;
keir@21190 596 int fd = -1;
gianni@22023 597 FILE *f = NULL;
keir@21190 598 size_t rs;
keir@21190 599
gianni@22023 600 filename = userdata_path(&gc, domid, userdata_userid, "d");
gianni@22023 601 if (!filename) {
gianni@22023 602 rc = ERROR_NOMEM;
gianni@22023 603 goto out;
gianni@22023 604 }
keir@21190 605
gianni@22023 606 if (!datalen) {
gianni@22023 607 rc = userdata_delete(ctx, filename);
gianni@22023 608 goto out;
gianni@22023 609 }
keir@21190 610
gianni@22023 611 newfilename = userdata_path(&gc, domid, userdata_userid, "n");
gianni@22023 612 if (!newfilename) {
gianni@22023 613 rc = ERROR_NOMEM;
gianni@22023 614 goto out;
gianni@22023 615 }
gianni@22023 616
gianni@22023 617 rc = ERROR_FAIL;
keir@21190 618
keir@21190 619 fd= open(newfilename, O_RDWR|O_CREAT|O_TRUNC, 0600);
gianni@22023 620 if (fd<0)
gianni@22023 621 goto err;
keir@21190 622
keir@21190 623 f= fdopen(fd, "wb");
gianni@22023 624 if (!f)
gianni@22023 625 goto err;
keir@21190 626 fd = -1;
keir@21190 627
keir@21190 628 rs = fwrite(data, 1, datalen, f);
gianni@22023 629 if (rs != datalen) {
gianni@22023 630 assert(ferror(f));
gianni@22023 631 goto err;
gianni@22023 632 }
keir@21190 633
gianni@22023 634 if (fclose(f))
gianni@22023 635 goto err;
keir@21190 636 f = 0;
keir@21190 637
gianni@22023 638 if (rename(newfilename,filename))
gianni@22023 639 goto err;
keir@21190 640
gianni@22023 641 rc = 0;
keir@21190 642
gianni@22023 643 err:
keir@21190 644 e = errno;
keir@21190 645 if (f) fclose(f);
keir@21190 646 if (fd>=0) close(fd);
keir@21190 647
gianni@21892 648 errno = e;
gianni@22023 649 if ( rc )
ian@22165 650 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot write %s for %s",
keir@21190 651 newfilename, filename);
gianni@22023 652 out:
ian@22164 653 libxl__free_all(&gc);
gianni@22023 654 return rc;
keir@21190 655 }
keir@21190 656
ian@21930 657 int libxl_userdata_retrieve(libxl_ctx *ctx, uint32_t domid,
keir@21190 658 const char *userdata_userid,
gianni@22023 659 uint8_t **data_r, int *datalen_r)
gianni@22023 660 {
ian@22167 661 libxl__gc gc = LIBXL_INIT_GC(ctx);
keir@21190 662 const char *filename;
gianni@22023 663 int e, rc;
keir@21190 664 int datalen = 0;
keir@21190 665 void *data = 0;
keir@21190 666
gianni@22023 667 filename = userdata_path(&gc, domid, userdata_userid, "d");
gianni@22023 668 if (!filename) {
gianni@22023 669 rc = ERROR_NOMEM;
gianni@22023 670 goto out;
gianni@22023 671 }
keir@21190 672
keir@21190 673 e = libxl_read_file_contents(ctx, filename, data_r ? &data : 0, &datalen);
keir@21190 674
keir@21190 675 if (!e && !datalen) {
ian@22165 676 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "userdata file %s is empty", filename);
keir@21190 677 if (data_r) assert(!*data_r);
gianni@22023 678 rc = ERROR_FAIL;
gianni@22023 679 goto out;
keir@21190 680 }
keir@21190 681
keir@21190 682 if (data_r) *data_r = data;
keir@21190 683 if (datalen_r) *datalen_r = datalen;
gianni@22023 684 rc = 0;
gianni@22023 685 out:
ian@22164 686 libxl__free_all(&gc);
gianni@22023 687 return rc;
keir@21190 688 }