static void switch_logdirty_xswatch(libxl__egc *egc, libxl__ev_xswatch *watch, const char *watch_path, const char *event_path) { libxl__logdirty_switch *lds = CONTAINER_OF(watch, *lds, watch); STATE_AO_GC(lds->ao); const char *got; xs_transaction_t t = 0; int rc; for (;;) { rc = libxl__xs_transaction_start(gc, &t); if (rc) goto out; rc = libxl__xs_read_checked(gc, t, lds->ret_path, &got); if (rc) goto out; if (!got) { rc = +1; goto out; } if (strcmp(got, lds->cmd)) { LOG(ERROR,"logdirty switch: sent command `%s' but got reply `%s'" " (xenstore paths `%s' / `%s')", lds->cmd, got, lds->cmd_path, lds->ret_path); rc = ERROR_FAIL; goto out; } rc = libxl__xs_rm_checked(gc, t, lds->cmd_path); if (rc) goto out; rc = libxl__xs_rm_checked(gc, t, lds->ret_path); if (rc) goto out; rc = libxl__xs_transaction_commit(gc, &t); if (!rc) break; if (rc<0) goto out; } out: /* rc < 0: error * rc == 0: ok, we are done * rc == +1: need to keep waiting */ libxl__xs_transaction_abort(gc, &t); if (rc <= 0) { if (rc < 0) LOG(ERROR,"logdirty switch: failed (rc=%d)",rc); switch_logdirty_done(egc,lds,rc); } }
int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info, uint32_t *domid) { libxl_ctx *ctx = libxl__gc_owner(gc); int flags, ret, rc, nb_vm; char *uuid_string; char *dom_path, *vm_path, *libxl_path; struct xs_permissions roperm[2]; struct xs_permissions rwperm[1]; struct xs_permissions noperm[1]; xs_transaction_t t = 0; xen_domain_handle_t handle; libxl_vminfo *vm_list; assert(!libxl_domid_valid_guest(*domid)); uuid_string = libxl__uuid2string(gc, info->uuid); if (!uuid_string) { rc = ERROR_NOMEM; goto out; } flags = 0; if (info->type == LIBXL_DOMAIN_TYPE_HVM) { flags |= XEN_DOMCTL_CDF_hvm_guest; flags |= libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0; flags |= libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off; } *domid = -1; /* Ultimately, handle is an array of 16 uint8_t, same as uuid */ libxl_uuid_copy((libxl_uuid *)handle, &info->uuid); ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid); if (ret < 0) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail"); rc = ERROR_FAIL; goto out; } ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid); if (ret < 0) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail"); rc = ERROR_FAIL; goto out; } dom_path = libxl__xs_get_dompath(gc, *domid); if (!dom_path) { rc = ERROR_FAIL; goto out; } vm_path = libxl__sprintf(gc, "/vm/%s", uuid_string); if (!vm_path) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths"); rc = ERROR_FAIL; goto out; } libxl_path = libxl__xs_libxl_path(gc, *domid); if (!libxl_path) { rc = ERROR_FAIL; goto out; } noperm[0].id = 0; noperm[0].perms = XS_PERM_NONE; roperm[0].id = 0; roperm[0].perms = XS_PERM_NONE; roperm[1].id = *domid; roperm[1].perms = XS_PERM_READ; rwperm[0].id = *domid; rwperm[0].perms = XS_PERM_NONE; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_rm(ctx->xsh, t, dom_path); libxl__xs_mkdir(gc, t, dom_path, roperm, ARRAY_SIZE(roperm)); xs_rm(ctx->xsh, t, vm_path); libxl__xs_mkdir(gc, t, vm_path, roperm, ARRAY_SIZE(roperm)); xs_rm(ctx->xsh, t, libxl_path); libxl__xs_mkdir(gc, t, libxl_path, noperm, ARRAY_SIZE(noperm)); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, strlen(vm_path)); rc = libxl__domain_rename(gc, *domid, 0, info->name, t); if (rc) goto out; libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/cpu", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/memory", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/device", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/control", dom_path), roperm, ARRAY_SIZE(roperm)); if (info->type == LIBXL_DOMAIN_TYPE_HVM) libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/hvmloader", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/control/shutdown", dom_path), rwperm, ARRAY_SIZE(rwperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/device/suspend/event-channel", dom_path), rwperm, ARRAY_SIZE(rwperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/data", dom_path), rwperm, ARRAY_SIZE(rwperm)); if (info->type == LIBXL_DOMAIN_TYPE_HVM) libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/hvmloader/generation-id-address", dom_path), rwperm, ARRAY_SIZE(rwperm)); vm_list = libxl_list_vm(ctx, &nb_vm); if (!vm_list) { LOG(ERROR, "cannot get number of running guests"); rc = ERROR_FAIL; goto out; } libxl_vminfo_list_free(vm_list, nb_vm); int hotplug_setting = libxl__hotplug_settings(gc, t); if (hotplug_setting < 0) { LOG(ERROR, "unable to get current hotplug scripts execution setting"); rc = ERROR_FAIL; goto out; } if (libxl_defbool_val(info->run_hotplug_scripts) != hotplug_setting && (nb_vm - 1)) { LOG(ERROR, "cannot change hotplug execution option once set, " "please shutdown all guests before changing it"); rc = ERROR_FAIL; goto out; } if (libxl_defbool_val(info->run_hotplug_scripts)) { rc = libxl__xs_write_checked(gc, t, DISABLE_UDEV_PATH, "1"); if (rc) { LOGE(ERROR, "unable to write %s = 1", DISABLE_UDEV_PATH); goto out; } } else { rc = libxl__xs_rm_checked(gc, t, DISABLE_UDEV_PATH); if (rc) { LOGE(ERROR, "unable to delete %s", DISABLE_UDEV_PATH); goto out; } } xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/name", vm_path), info->name, strlen(info->name)); libxl__xs_writev(gc, t, dom_path, info->xsdata); libxl__xs_writev(gc, t, libxl__sprintf(gc, "%s/platform", dom_path), info->platformdata); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-xs_reset_watches", dom_path), "1", 1); if (!xs_transaction_end(ctx->xsh, t, 0)) { if (errno == EAGAIN) { t = 0; goto retry_transaction; } LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "domain creation " "xenstore transaction commit failed"); rc = ERROR_FAIL; goto out; } t = 0; rc = 0; out: if (t) xs_transaction_end(ctx->xsh, t, 1); return rc; }
static void domain_suspend_switch_qemu_xen_traditional_logdirty (libxl__egc *egc, int domid, unsigned enable, libxl__logdirty_switch *lds) { STATE_AO_GC(lds->ao); int rc; xs_transaction_t t = 0; const char *got; if (!lds->cmd_path) { uint32_t dm_domid = libxl_get_stubdom_id(CTX, domid); lds->cmd_path = DEVICE_MODEL_XS_PATH(gc, dm_domid, domid, "/logdirty/cmd"); lds->ret_path = DEVICE_MODEL_XS_PATH(gc, dm_domid, domid, "/logdirty/ret"); } lds->cmd = enable ? "enable" : "disable"; rc = libxl__ev_xswatch_register(gc, &lds->watch, switch_logdirty_xswatch, lds->ret_path); if (rc) goto out; rc = libxl__ev_time_register_rel(ao, &lds->timeout, switch_logdirty_timeout, 10*1000); if (rc) goto out; for (;;) { rc = libxl__xs_transaction_start(gc, &t); if (rc) goto out; rc = libxl__xs_read_checked(gc, t, lds->cmd_path, &got); if (rc) goto out; if (got) { const char *got_ret; rc = libxl__xs_read_checked(gc, t, lds->ret_path, &got_ret); if (rc) goto out; if (!got_ret || strcmp(got, got_ret)) { LOG(ERROR,"controlling logdirty: qemu was already sent" " command `%s' (xenstore path `%s') but result is `%s'", got, lds->cmd_path, got_ret ? got_ret : "<none>"); rc = ERROR_FAIL; goto out; } rc = libxl__xs_rm_checked(gc, t, lds->cmd_path); if (rc) goto out; } rc = libxl__xs_rm_checked(gc, t, lds->ret_path); if (rc) goto out; rc = libxl__xs_write_checked(gc, t, lds->cmd_path, lds->cmd); if (rc) goto out; rc = libxl__xs_transaction_commit(gc, &t); if (!rc) break; if (rc<0) goto out; } /* OK, wait for some callback */ return; out: LOG(ERROR,"logdirty switch failed (rc=%d), abandoning suspend",rc); libxl__xs_transaction_abort(gc, &t); switch_logdirty_done(egc,lds,rc); }