debuggers.hg

annotate tools/libxl/libxl_dom.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents 60782cefa154
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 }