/* * Remove information about a usb device for this domain from Xenstore */ int xenstore_destroy_usb(dominfo_t *domp, usbinfo_t *usbp) { char value[32]; char *bepath; char *fepath; int i; xd_log(LOG_INFO, "Deleting VUSB node %d for %d.%d", usbp->usb_virtid, usbp->usb_bus, usbp->usb_device); bepath = xs_dev_bepath(domp, "vusb", usbp->usb_virtid); fepath = xs_dev_fepath(domp, "vusb", usbp->usb_virtid); /* Notify the backend that the device is being shut down */ xs_set_keyval(XBT_NULL, bepath, "online", "0"); xs_set_keyval(XBT_NULL, bepath, "physical-device", "0.0"); snprintf(value, sizeof (value), "%d", XB_CLOSING); xs_set_keyval(XBT_NULL, bepath, "state", value); for (i = 0; i < 30; ++i) { usleep(100000); if (test_offline(domp, usbp)) { xs_rm(xs_handle, XBT_NULL, fepath); xs_rm(xs_handle, XBT_NULL, bepath); break; } } free(bepath); free(fepath); return (0); }
/* Remove the backend area in xenbus since the framebuffer really is going away. */ void xenfb_shutdown(struct xenfb *xenfb) { fprintf(stderr, "FB: Shutting down backend\n"); xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); xenfb_detach_dom(xenfb); if (xenfb->xc >= 0) xc_interface_close(xenfb->xc); if (xenfb->evt_xch >= 0) xc_evtchn_close(xenfb->evt_xch); if (xenfb->xsh) xs_daemon_close(xenfb->xsh); free(xenfb); }
/** * \brief Backend XenBus method implementing responses to local * XenStore changes. * * \param bus The XenBus bus parent of child. * \param child The XenBus child whose peer stat has changed. * \param_path The tree relative sub-path to the modified node. The empty * string indicates the root of the tree was destroyed. */ static void xenbusb_back_localend_changed(device_t bus, device_t child, const char *path) { xenbusb_localend_changed(bus, child, path); if (strcmp(path, "/state") != 0 && strcmp(path, "/online") != 0) return; if (xenbus_get_state(child) != XenbusStateClosed || xenbus_dev_is_online(child) != 0) return; /* * Cleanup the hotplug entry in the XenStore if * present. The control domain expects any userland * component associated with this device to destroy * this node in order to signify it is safe to * teardown the device. However, not all backends * rely on userland components, and those that * do should either use a communication channel * other than the XenStore, or ensure the hotplug * data is already cleaned up. * * This removal ensures that no matter what path * is taken to mark a back-end closed, the control * domain will understand that it is closed. */ xs_rm(XST_NIL, xenbus_get_node(child), "hotplug-status"); }
bool xenbus_create_request_node(void) { bool ret; struct xs_permissions perms; assert(xsh != NULL); xs_rm(xsh, XBT_NULL, WATCH_NODE); ret = xs_mkdir(xsh, XBT_NULL, WATCH_NODE); if (!ret) { printf("failed to created %s\n", WATCH_NODE); return false; } perms.id = 0; perms.perms = XS_PERM_WRITE; ret = xs_set_permissions(xsh, XBT_NULL, WATCH_NODE, &perms, 1); if (!ret) { printf("failed to set write permission on %s\n", WATCH_NODE); return false; } perms.perms = XS_PERM_READ; ret = xs_set_permissions(xsh, XBT_NULL, ROOT_NODE, &perms, 1); if (!ret) { printf("failed to set read permission on %s\n", ROOT_NODE); } return ret; }
int libvchan_wait(libvchan_t *ctrl) { int ret = -2; /* invalid, so can be distinguished from real libxenvchan_wait return code */ struct xs_handle *xs; if (ctrl->xenvchan->is_server && libxenvchan_is_open(ctrl->xenvchan) == 2) { /* In case of vchan server waiting for a client, we'll not receive any * notification if the remote domain dies before connecting. Because of * that, check periodically if remote domain is still alive while * waiting for a connection. Actually this doesn't cover all the cases * - if remote domain is still alive, but remote process dies before * connecting, we'll also not receive any notification. But this, in * most cases, can be solved by application using libvchan. * * During normal operation this shouldn't be long - in most cases vchan * client will connect almost instantly. So this sleep(10) loop will * not hurt. Alternativelly it could be implemented with * xs_watch("@releaseDomain"), but such approach will slow down most * common execution path (xs_open+xs_watch even if client connects * right away). */ while (ret == -2 && libxenvchan_is_open(ctrl->xenvchan) == 2) { fd_set rd_set; struct timeval tv = { 10, 0 }; int vchan_fd = libxenvchan_fd_for_select(ctrl->xenvchan); FD_ZERO(&rd_set); FD_SET(vchan_fd, &rd_set); switch (select(vchan_fd+1, &rd_set, NULL, NULL, &tv)) { case 0: if (!libvchan__check_domain_alive(ctrl->xc_handle, ctrl->remote_domain)) return -1; break; case 1: /* break the loop */ ret = -1; break; default: if (errno == EINTR) break; perror("select"); return -1; } } } ret = libxenvchan_wait(ctrl->xenvchan); if (ctrl->xs_path) { /* remove xenstore entry at first client connection */ xs = xs_open(0); if (xs) { /* if xenstore connection failed just do not remove entries, but do * not abort whole function, especially still free the memory */ xs_rm(xs, 0, ctrl->xs_path); xs_close(xs); } free(ctrl->xs_path); ctrl->xs_path = NULL; } return ret; }
void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid, const char *node, Error **errp) { trace_xs_node_destroy(node); if (!xs_rm(xsh, tid, node)) { error_setg_errno(errp, errno, "failed to destroy node '%s'", node); } }
ivc_connection_t *makeConnection(libIVC_t *iface, char *name, ivc_contype_t type, float per) { char *key, *val, *rdomstr = NULL, *rrefstr = NULL, *rpstr = NULL; uint32_t me, other, num_refs, *grants; struct xs_permissions perms; ivc_connection_t *res; evtchn_port_t port; unsigned int len; void *buffer; /* me <- xsGetDomId */ me = getMyDomId(iface); /* removePath xs targetPath */ ASPRINTF(&key, "/rendezvous/%s", name); xs_rm(iface->xs, 0, key); /* xsMakeDirectory xs targetPath */ xs_mkdir(iface->xs, 0, key); /* xsSetPermissions xs targetPath [ReadWritePerm me] */ perms.id = me; perms.perms = XS_PERM_READ | XS_PERM_WRITE; xs_set_permissions(iface->xs, 0, key, &perms, 1); /* xsWrite xs (targetPath ++ "/LeftDomId") (show me) */ free(key), ASPRINTF(&key, "/rendezvous/%s/LeftDomId", name); ASPRINTF(&val, "dom%d", me); xs_write(iface->xs, 0, key, val, strlen(val)); /* other <- read <$> waitForKey xs (targetPAth ++ "/RightDomId") */ free(key), ASPRINTF(&key, "/rendezvous/%s/RightDomId", name); while(!rdomstr) { rdomstr = xs_read(iface->xs, 0, key, &len); }; sscanf(rdomstr, "dom%d", &other); /* grants <- read <$> waitForKey xs (targetPAth ++ "/RightGrantRefs") */ free(key), ASPRINTF(&key, "/rendezvous/%s/RightGrantRefs", name); while(!rrefstr) { rrefstr = xs_read(iface->xs, 0, key, &len); } grants = parseRefs(rrefstr, &num_refs); buffer = xc_gnttab_map_domain_grant_refs(iface->gt, num_refs, other, grants, PROT_READWRITE); assert(buffer); /* ports <- read <$> waitForKey xs (targetPAth ++ "/RightPorts") */ free(key), ASPRINTF(&key, "/rendezvous/%s/RightPorts", name); while(!rpstr) { rpstr = xs_read(iface->xs, 0, key, &len); } sscanf(rpstr, "[echan:%d]", &port); port = xc_evtchn_bind_interdomain(iface->ec, other, port); assert(port >= 0); /* res <- acceptConnection other grants ports extra */ res = buildChannel(iface, other, type, port, buffer, num_refs * 4096, per, 0); /* xsWrite xs (targetPath ++ "/LeftConnectionConfirmed") "True" */ free(key), ASPRINTF(&key, "/rendezvous/%s/LeftConnectionConfirmed", name); free(val), ASPRINTF(&val, "True"); xs_write(iface->xs, 0, key, val, strlen(val)); /* return res */ return res; }
static int do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth) { if (xs_rm(xsh, xth, path)) { return 0; } else { warnx("could not remove path %s", path); return 1; } }
int generic_remove_xs_entry(struct xs_handle *h, char *path) { int ret = 0; if (xs_exists(h, path)) { if (!xs_rm(h, XBT_NULL, path)) { printf("Failed to remove xs entry %s\n", path); goto out; } } ret = 1; out: return ret; }
ivc_connection_t *acceptConnection(libIVC_t *iface, char *name, ivc_contype_t type, uint32_t num_pages, float per) { char *key, *val, *domStr = NULL; uint32_t me, other, *gs, ps; unsigned int len; void *buffer; /* we can only do this if we create grant references */ if(!iface->gs) return NULL; /* other <- read `fmap` waitForKey xs (targetPath ++ "/LeftDomId) */ ASPRINTF(&key, "/rendezvous/%s/LeftDomId", name); while(!domStr) { domStr = xs_read(iface->xs, 0, key, &len); } sscanf(domStr, "dom%d", &other); /* me <- xsGetDomId */ me = getMyDomId(iface); /* (gs, ps, confirm) <- makeConnection other extra */ gs = calloc(num_pages, sizeof(uint32_t)); buffer = xc_gntshr_share_pages(iface->gs, other, num_pages, gs, 1); assert(buffer); ps = xc_evtchn_bind_unbound_port(iface->ec, other); assert(ps); /* xsWrite xs (targetPath ++ "/RightDomId") (show me) */ free(key), ASPRINTF(&key, "/rendezvous/%s/RightDomId", name); free(val), ASPRINTF(&val, "dom%d", me); xs_write(iface->xs, 0, key, val, strlen(val)); /* xsWrite xs (targetPath ++ "/RightGrantRefs") (show gs) */ free(key), ASPRINTF(&key, "/rendezvous/%s/RightGrantRefs", name); free(val), val = showGrantRefList(gs, num_pages); xs_write(iface->xs, 0, key, val, strlen(val)); /* xsWrite xs (targetPath ++ "/RightPorts") (show ps) */ free(key), ASPRINTF(&key, "/rendezvous/%s/RightPorts", name); free(val), ASPRINTF(&val, "[echan:%d]", ps); xs_write(iface->xs, 0, key, val, strlen(val)); /* _ <- waitForKey xs (targetPath ++ "/LeftConnectionConfirmed") */ free(key), ASPRINTF(&key, "/rendezvous/%s/LeftConnectionConfirmed", name); free(val), val = NULL; while(!val) { val = xs_read(iface->xs, 0, key, &len); } /* removePath xs targetPath */ free(key), ASPRINTF(&key, "/rendezvous/%s", name); xs_rm(iface->xs, 0, key); /* confirm */ return buildChannel(iface, other, type, ps, buffer, 4096 * num_pages, per, 1); }
void libvchan_close(libvchan_t *ctrl) { struct xs_handle *xs; libxenvchan_close(ctrl->xenvchan); if (ctrl->xs_path) { /* remove xenstore entry in case of no client connected */ xs = xs_open(0); if (xs) { /* if xenstore connection failed just do not remove entries, but do * not abort whole function, especially still free the memory */ xs_rm(xs, 0, ctrl->xs_path); xs_close(xs); } free(ctrl->xs_path); } free(ctrl); }
static void xen_cleanup() { char keybuf[64]; /*XXX hardcoded*/ munmap((void*)gref.index, 4096); set_state(XenbusStateClosing); /* send one last event to unblock the backend */ xc_evtchn_notify(xce, xen_evtchn_port); /* close xen interfaces */ xc_evtchn_close(xce); xc_interface_close(xch); /* delete xenstore keys */ publish_param_int("state", XenbusStateClosed); snprintf(keybuf, sizeof(keybuf), "device/audio/%d", device_id); xs_rm(xsh, 0, keybuf); xs_daemon_close(xsh); }
int remove_xs_entry(struct xs_handle *h, char *dom_uuid, char *dom_path) { char *path = NULL; int ret = 0; if (asprintf(&path, "/vss/%s/%s",dom_uuid, dom_path)==-1) goto out; if (xs_exists(h, path)) { if (!xs_rm(h, XBT_NULL, path)) { printf("Failed to remove xs entry %s\n", path); goto out; } } ret = 1; out: free(path); return ret; }
//Shutdown a domain by signalling this via xenstored void shutdown_domain(char *domname) { int domid; char *vm_uuid = NULL; char vmpath[64]; struct xs_handle *xsh = NULL; domid = atoi(domname); if (domid == 0) { perror("Error, dom 0 could not be shutdown\n"); return; } xsh = xs_daemon_open(); if (!xsh) { perror("Couldn't get xsh handle."); return; } //if self._stateGet() in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,): // raise XendError('Domain cannot be shutdown') vm_uuid = domid_to_vm_uuid(xsh, domid); snprintf(vmpath, sizeof(vmpath), "%s/xend/previous_restart_time", vm_uuid); free(vm_uuid); xs_rm(xsh, XBT_NULL, vmpath); memset(vmpath, '\0', 64); snprintf(vmpath, sizeof(vmpath), "/local/domain/%u/control/shutdown", domid); xs_write(xsh, XBT_NULL, vmpath, "poweroff", 9); //TODO: How about HVM domain //HVM domain shuts itself down only if it has PV drivers //if self.info.is_hvm(): // hvm_pvdrv = xc.hvm_get_param(self.domid, HVM_PARAM_CALLBACK_IRQ) // if not hvm_pvdrv: // code = REVERSE_DOMAIN_SHUTDOWN_REASONS[reason] free(xsh); return; }
int libxl__destroy_device_model(libxl_ctx *ctx, uint32_t domid) { libxl__gc gc = LIBXL_INIT_GC(ctx); char *pid; int ret; pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid)); if (!pid) { int stubdomid = libxl_get_stubdom_id(ctx, domid); if (!stubdomid) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't find device model's pid"); ret = ERROR_INVAL; goto out; } LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device model is a stubdom, domid=%d\n", stubdomid); ret = libxl_domain_destroy(ctx, stubdomid, 0); if (ret) goto out; } else { ret = kill(atoi(pid), SIGHUP); if (ret < 0 && errno == ESRCH) { LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model already exited"); ret = 0; } else if (ret == 0) { LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model signaled"); ret = 0; } else { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to kill Device Model [%d]", atoi(pid)); ret = ERROR_FAIL; goto out; } } xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", domid)); out: libxl__free_all(&gc); return ret; }
int destroy_domain(char *domname) { int domid, rcode, i, DMid, status; int __attribute__((__unused__)) ret; #ifdef XENCTRL_HAS_XC_INTERFACE xc_interface *xc_handle = NULL; #else int xc_handle = 0; #endif unsigned int len; char *s; char path[256]; struct xs_handle *xsh = NULL; FILE *f; char buf[256]; char *backend; xsh = xs_daemon_open(); if (!xsh) { perror("Couldn't get xsh handle."); rcode = 1; goto out; } domid = getDomidByName(xsh, domname); if (domid < 1) { perror("Error,Can't destroy domId, domId should > 0\n"); rcode = 1; goto out; } #ifdef XENCTRL_HAS_XC_INTERFACE xc_handle = xc_interface_open(NULL, NULL, 0); if (xc_handle == NULL) { #else xc_handle = xc_interface_open(); if (xc_handle < 0) { #endif perror("Couldn't open xc handle."); rcode = 1; goto out; } /* TODO PCI clean paths = self._prepare_phantom_paths() if self.dompath is not None: self._cleanup_phantom_devs(paths) xc_domain_destroy_hook(xc_handle, domid); */ xc_domain_pause(xc_handle, domid); rcode = xc_domain_destroy(xc_handle, domid); // free Device Model sprintf(path,"/local/domain/%d/image/device-model-pid", domid); s = xs_read(xsh, XBT_NULL, path, &len); if( s != NULL) { DMid = atoi(s); free(s); DEBUG("Deivce Model Id is %d\n", DMid); } else { rcode = 1; DEBUG("can't read Deivce Model Id\n"); goto out; } kill(DMid, SIGHUP); for( i=0; i< 100; i++) { if(DMid == waitpid(DMid, &status, WNOHANG)) break; sleep(0.1); } if( i == 100) { DEBUG("DeviceModel %d took more than 10s " "to terminate: sending SIGKILL\n", DMid); kill(DMid, SIGKILL); waitpid(DMid, &status, 0); } sprintf(path,"/local/domain/0/device-model/%i", domid); xs_rm(xsh, XBT_NULL, path); // unlink pipe sprintf(path,"/var/run/tap/qemu-read-%d", domid); ret = unlink(path); sprintf(path,"/var/run/tap/qemu-write-%d", domid); ret = unlink(path); //notify backend to reap the source assigned to this VM sprintf(path, "xenstore-ls /local/domain/%d/device > /var/tmp/xdestroy_device.%d", domid, domid); ret = system(path); sprintf(path, "/var/tmp/xdestroy_device.%d", domid); f = fopen(path, "r"); if ( f == NULL) { DEBUG(" error to open device file\n"); return -1; } DEBUG("- begin to reap\n"); while(1) { if( fgets(buf, 256, f)== NULL) break; else { if( buf[0] != 0x20) { backend = device_backend(xsh, buf, domid); if( backend != NULL) { notify_backend(xsh, backend); free(backend); } } } } DEBUG("- end to reap\n"); fclose(f); sprintf(path, "rm /var/tmp/xdestroy_device.%d", domid); ret = system(path); extra_call(domname, DMid); out: if (xsh) xs_daemon_close(xsh); if (xc_handle) xc_interface_close(xc_handle); return rcode; } int main(int argc, char **argv) { if (argc != 2) { printf("Miss destroy name\n"); return -1; } xlist(argc, argv); //shutdown_domain(argv[1]); destroy_domain(argv[1]); return 0; }
static void xs_remove(xs_transaction_t xt, char *path) { xd_log(LOG_VERBOSE_DEBUG, "XenStore removing %s", path); xs_rm(xs_handle, xt, path); }
int grefwatch_from_alloc(uint32_t *gref, void **pptr) { int rv; void *ptr; int pg_size = getpagesize(); struct ioctl_gntalloc_alloc_gref arg = { .domid = DOM0_DOMID, .flags = GNTALLOC_FLAG_WRITABLE, .count = 1 }; struct ioctl_gntalloc_dealloc_gref arg_d; struct ioctl_gntalloc_unmap_notify notify = { .action = UNMAP_NOTIFY_CLEAR_BYTE }; rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, &arg); if (rv) { RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__); return -1; } ptr = (void *)mmap(NULL, pg_size, PROT_READ|PROT_WRITE, MAP_SHARED, gntalloc_fd, arg.index); arg_d.index = arg.index; arg_d.count = 1; if (ptr == MAP_FAILED) { RTE_LOG(ERR, PMD, "%s: mmap failed\n", __func__); ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d); return -1; } if (pptr) *pptr = ptr; if (gref) *gref = arg.gref_ids[0]; notify.index = arg.index; rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, ¬ify); if (rv) { RTE_LOG(ERR, PMD, "%s: unmap notify failed\n", __func__); munmap(ptr, pg_size); ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d); return -1; } return 0; } void gntfree(void *va, size_t sz, uint64_t start_index) { struct ioctl_gntalloc_dealloc_gref arg_d; if (va && sz) { munmap(va, sz); arg_d.count = sz / getpagesize(); arg_d.index = start_index; ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d); } } static int xenstore_cleanup(void) { char store_path[PATH_MAX] = {0}; if (snprintf(store_path, sizeof(store_path), "%s%s", dompath, DPDK_XENSTORE_NODE) == -1) return -1; if (xs_rm(xs, XBT_NULL, store_path) == false) { RTE_LOG(ERR, PMD, "%s: failed cleanup node\n", __func__); return -1; } return 0; }
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; }
int tapback_backend_handle_otherend_watch(backend_t *backend, const char * const path) { vbd_t *device = NULL; int err = 0, state = 0; char *s = NULL, *end = NULL, *_path = NULL; ASSERT(backend); ASSERT(path); /* * Find the device that has the same front-end state path. * * There should definitely be such a device in our list, otherwise this * function would not have executed at all, since we would not be waiting * on that XenStore path. The XenStore path we wait for is: * /local/domain/<domid>/device/vbd/<devname>/state. In order to watch this * path, it means that we have received a device create request, so the * device will be there. * * TODO Instead of this linear search we could do better (hash table etc). */ tapback_backend_find_device(backend, device, device->frontend_state_path && !strcmp(device->frontend_state_path, path)); if (!device) { WARN(NULL, "path \'%s\' does not correspond to a known device\n", path); return ENODEV; } /* * Read the new front-end's state. */ s = tapback_xs_read(device->backend->xs, XBT_NULL, "%s", device->frontend_state_path); if (!s) { err = errno; /* * If the front-end XenBus node is missing, the XenBus device has been * removed: remove the XenBus back-end node. */ if (err == ENOENT) { err = asprintf(&_path, "%s/%s/%d/%d", XENSTORE_BACKEND, device->backend->name, device->domid, device->devid); if (err == -1) { err = errno; WARN(device, "failed to asprintf for %d/%d: %s\n", strerror(err)); goto out; } err = 0; if (!xs_rm(device->backend->xs, XBT_NULL, _path)) { if (errno != ENOENT) { err = errno; WARN(device, "failed to remove %s: %s\n", path, strerror(err)); } } } } else { state = strtol(s, &end, 0); if (*end != 0 || end == s) { WARN(device, "invalid XenBus state '%s'\n", s); err = EINVAL; } else err = frontend_changed(device, state); } out: free(s); free(_path); return err; }
/* * Preserves a domain but rewrites xenstore etc to make it unique so * that the domain can be restarted. * * Does not modify info so that it may be reused. */ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid) { GC_INIT(ctx); struct xs_permissions roperm[2]; xs_transaction_t t; char *preserved_name; char *uuid_string; char *vm_path; char *dom_path; int rc; preserved_name = GCSPRINTF("%s%s", info->name, name_suffix); if (!preserved_name) { GC_FREE; return ERROR_NOMEM; } uuid_string = libxl__uuid2string(gc, new_uuid); if (!uuid_string) { GC_FREE; return ERROR_NOMEM; } dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { GC_FREE; return ERROR_FAIL; } vm_path = GCSPRINTF("/vm/%s", uuid_string); if (!vm_path) { GC_FREE; return ERROR_FAIL; } roperm[0].id = 0; roperm[0].perms = XS_PERM_NONE; roperm[1].id = domid; roperm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_rm(ctx->xsh, t, vm_path); xs_mkdir(ctx->xsh, t, vm_path); xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm)); xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, strlen(vm_path)); rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t); if (rc) { GC_FREE; return rc; } xs_write(ctx->xsh, t, GCSPRINTF("%s/uuid", vm_path), uuid_string, strlen(uuid_string)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; GC_FREE; return 0; }