diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/libxl/libxl.c | 176 | ||||
-rw-r--r-- | tools/libxl/libxl.h | 3 | ||||
-rw-r--r-- | tools/libxl/libxl_create.c | 29 | ||||
-rw-r--r-- | tools/libxl/libxl_device.c | 149 | ||||
-rw-r--r-- | tools/libxl/libxl_dm.c | 85 | ||||
-rw-r--r-- | tools/libxl/libxl_internal.h | 116 | ||||
-rw-r--r-- | tools/libxl/xl_cmdimpl.c | 12 | ||||
-rw-r--r-- | tools/python/xen/lowlevel/xl/xl.c | 2 |
8 files changed, 488 insertions, 84 deletions
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index ebc314b46d..0600ce43f3 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1216,11 +1216,133 @@ void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject *evg) { GC_FREE; } -int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) +/* Callbacks for libxl_domain_destroy */ + +static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state *dds, + int rc); + +int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, + const libxl_asyncop_how *ao_how) { - GC_INIT(ctx); + AO_CREATE(ctx, domid, ao_how); + libxl__domain_destroy_state *dds; + + GCNEW(dds); + dds->ao = ao; + dds->domid = domid; + dds->callback = domain_destroy_cb; + libxl__domain_destroy(egc, dds); + + return AO_INPROGRESS; +} + +static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state *dds, + int rc) +{ + STATE_AO_GC(dds->ao); + + if (rc) + LOG(ERROR, "destruction of domain %u failed", dds->domid); + + libxl__ao_complete(egc, ao, rc); +} + +/* Callbacks for libxl__domain_destroy */ + +static void stubdom_destroy_callback(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc); + +static void domain_destroy_callback(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc); + +static void destroy_finish_check(libxl__egc *egc, + libxl__domain_destroy_state *dds); + +void libxl__domain_destroy(libxl__egc *egc, libxl__domain_destroy_state *dds) +{ + STATE_AO_GC(dds->ao); + uint32_t stubdomid = libxl_get_stubdom_id(CTX, dds->domid); + + if (stubdomid) { + dds->stubdom.ao = ao; + dds->stubdom.domid = stubdomid; + dds->stubdom.callback = stubdom_destroy_callback; + libxl__destroy_domid(egc, &dds->stubdom); + } else { + dds->stubdom_finished = 1; + } + + dds->domain.ao = ao; + dds->domain.domid = dds->domid; + dds->domain.callback = domain_destroy_callback; + libxl__destroy_domid(egc, &dds->domain); +} + +static void stubdom_destroy_callback(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc) +{ + STATE_AO_GC(dis->ao); + libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, stubdom); + const char *savefile; + + if (rc) { + LOG(ERROR, "unable to destroy stubdom with domid %u", dis->domid); + dds->rc = rc; + } + + dds->stubdom_finished = 1; + savefile = libxl__device_model_savefile(gc, dis->domid); + rc = libxl__remove_file(gc, savefile); + /* + * On suspend libxl__domain_save_device_model will have already + * unlinked the save file. + */ + if (rc) { + LOG(ERROR, "failed to remove device-model savefile %s", savefile); + } + + destroy_finish_check(egc, dds); +} + +static void domain_destroy_callback(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc) +{ + STATE_AO_GC(dis->ao); + libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, domain); + + if (rc) { + LOG(ERROR, "unable to destroy guest with domid %u", dis->domid); + dds->rc = rc; + } + + dds->domain_finished = 1; + destroy_finish_check(egc, dds); +} + +static void destroy_finish_check(libxl__egc *egc, + libxl__domain_destroy_state *dds) +{ + if (!(dds->domain_finished && dds->stubdom_finished)) + return; + + dds->callback(egc, dds, dds->rc); +} + +/* Callbacks for libxl__destroy_domid */ +static void devices_destroy_cb(libxl__egc *egc, + libxl__devices_remove_state *drs, + int rc); + +void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis) +{ + STATE_AO_GC(dis->ao); + libxl_ctx *ctx = CTX; + uint32_t domid = dis->domid; char *dom_path; - char *vm_path; char *pid; int rc, dm_present; @@ -1231,12 +1353,15 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) case ERROR_INVAL: LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "non-existant domain %d", domid); default: - return rc; + goto out; } switch (libxl__domain_type(gc, domid)) { case LIBXL_DOMAIN_TYPE_HVM: - dm_present = 1; + if (!libxl_get_stubdom_id(CTX, domid)) + dm_present = 1; + else + dm_present = 0; break; case LIBXL_DOMAIN_TYPE_PV: pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/image/device-model-pid", domid)); @@ -1267,7 +1392,37 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) libxl__qmp_cleanup(gc, domid); } - if (libxl__devices_destroy(gc, domid) < 0) + dis->drs.ao = ao; + dis->drs.domid = domid; + dis->drs.callback = devices_destroy_cb; + dis->drs.force = 1; + libxl__devices_destroy(egc, &dis->drs); + return; + +out: + assert(rc); + dis->callback(egc, dis, rc); + return; +} + +static void devices_destroy_cb(libxl__egc *egc, + libxl__devices_remove_state *drs, + int rc) +{ + STATE_AO_GC(drs->ao); + libxl__destroy_domid_state *dis = CONTAINER_OF(drs, *dis, drs); + libxl_ctx *ctx = CTX; + uint32_t domid = dis->domid; + char *dom_path; + char *vm_path; + + dom_path = libxl__xs_get_dompath(gc, domid); + if (!dom_path) { + rc = ERROR_FAIL; + goto out; + } + + if (rc < 0) LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl__devices_destroy failed for %d", domid); @@ -1280,6 +1435,10 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", dom_path); xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid)); + xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, + "/local/domain/0/device-model/%d", domid)); + xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, + "/local/domain/%d/hvmloader", domid)); libxl__userdata_destroyall(gc, domid); @@ -1290,9 +1449,10 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) goto out; } rc = 0; + out: - GC_FREE; - return rc; + dis->callback(egc, dis, rc); + return; } int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index c2d5c06154..5c819f19e1 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -527,7 +527,8 @@ int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info, int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid); int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid); -int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid); +int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, + const libxl_asyncop_how *ao_how); int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid); /* get max. number of cpus supported by hypervisor */ diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 0bfa8babee..137659f993 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -571,6 +571,12 @@ static void domcreate_complete(libxl__egc *egc, libxl__domain_create_state *dcs, int rc); +/* If creation is not successful, this callback will be executed + * when domain destruction is finished */ +static void domcreate_destruction_cb(libxl__egc *egc, + libxl__domain_destroy_state *dds, + int rc); + static void initiate_domain_create(libxl__egc *egc, libxl__domain_create_state *dcs) { @@ -999,16 +1005,31 @@ static void domcreate_complete(libxl__egc *egc, if (rc) { if (dcs->guest_domid) { - int rc2 = libxl_domain_destroy(CTX, dcs->guest_domid); - if (rc2) - LOG(ERROR, "unable to destroy domain %d following" - " failed creation", dcs->guest_domid); + dcs->dds.ao = ao; + dcs->dds.domid = dcs->guest_domid; + dcs->dds.callback = domcreate_destruction_cb; + libxl__domain_destroy(egc, &dcs->dds); + return; } dcs->guest_domid = -1; } dcs->callback(egc, dcs, rc, dcs->guest_domid); } +static void domcreate_destruction_cb(libxl__egc *egc, + libxl__domain_destroy_state *dds, + int rc) +{ + STATE_AO_GC(dds->ao); + libxl__domain_create_state *dcs = CONTAINER_OF(dds, *dcs, dds); + + if (rc) + LOG(ERROR, "unable to destroy domain %u following failed creation", + dds->domid); + + dcs->callback(egc, dcs, ERROR_FAIL, dcs->guest_domid); +} + /*----- application-facing domain creation interface -----*/ typedef struct { diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index 5a07ffb35b..a94beabf08 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -58,6 +58,48 @@ int libxl__parse_backend_path(libxl__gc *gc, return libxl__device_kind_from_string(strkind, &dev->backend_kind); } +static int libxl__num_devices(libxl__gc *gc, uint32_t domid) +{ + char *path; + unsigned int num_kinds, num_devs; + char **kinds = NULL, **devs = NULL; + int i, j, rc = 0; + libxl__device dev; + libxl__device_kind kind; + int numdevs = 0; + + path = GCSPRINTF("/local/domain/%d/device", domid); + kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds); + if (!kinds) { + if (errno != ENOENT) { + LOGE(ERROR, "unable to get xenstore device listing %s", path); + rc = ERROR_FAIL; + goto out; + } + num_kinds = 0; + } + for (i = 0; i < num_kinds; i++) { + if (libxl__device_kind_from_string(kinds[i], &kind)) + continue; + + path = GCSPRINTF("/local/domain/%d/device/%s", domid, kinds[i]); + devs = libxl__xs_directory(gc, XBT_NULL, path, &num_devs); + if (!devs) + continue; + for (j = 0; j < num_devs; j++) { + path = GCSPRINTF("/local/domain/%d/device/%s/%s/backend", + domid, kinds[i], devs[j]); + path = libxl__xs_read(gc, XBT_NULL, path); + if (path && libxl__parse_backend_path(gc, path, &dev) == 0) { + numdevs++; + } + } + } +out: + if (rc) return rc; + return numdevs; +} + int libxl__device_generic_add(libxl__gc *gc, xs_transaction_t t, libxl__device *device, char **bents, char **fents) { @@ -370,6 +412,37 @@ void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev) aodev->dev = NULL; /* Initialize timer for QEMU Bodge */ libxl__ev_time_init(&aodev->timeout); + aodev->active = 1; +} + +void libxl__prepare_ao_devices(libxl__ao *ao, libxl__ao_devices *aodevs) +{ + AO_GC; + + GCNEW_ARRAY(aodevs->array, aodevs->size); + for (int i = 0; i < aodevs->size; i++) { + aodevs->array[i].aodevs = aodevs; + libxl__prepare_ao_device(ao, &aodevs->array[i]); + } +} + +void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev) +{ + STATE_AO_GC(aodev->ao); + libxl__ao_devices *aodevs = aodev->aodevs; + int i, error = 0; + + aodev->active = 0; + for (i = 0; i < aodevs->size; i++) { + if (aodevs->array[i].active) + return; + + if (aodevs->array[i].rc) + error = aodevs->array[i].rc; + } + + aodevs->callback(egc, aodevs, error); + return; } int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) @@ -386,16 +459,35 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) return 0; } -int libxl__devices_destroy(libxl__gc *gc, uint32_t domid) +/* Callback for device destruction */ + +static void devices_remove_callback(libxl__egc *egc, libxl__ao_devices *aodevs, + int rc); + +void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs) { + STATE_AO_GC(drs->ao); libxl_ctx *ctx = libxl__gc_owner(gc); + uint32_t domid = drs->domid; char *path; - unsigned int num_kinds, num_devs; + unsigned int num_kinds, num_dev_xsentries; char **kinds = NULL, **devs = NULL; - int i, j; - libxl__device dev; + int i, j, numdev = 0, rc = 0; + libxl__device *dev; + libxl__ao_devices *aodevs = &drs->aodevs; + libxl__ao_device *aodev; libxl__device_kind kind; + aodevs->size = libxl__num_devices(gc, drs->domid); + if (aodevs->size < 0) { + LOG(ERROR, "unable to get number of devices for domain %u", drs->domid); + rc = aodevs->size; + goto out; + } + + libxl__prepare_ao_devices(drs->ao, aodevs); + aodevs->callback = devices_remove_callback; + path = libxl__sprintf(gc, "/local/domain/%d/device", domid); kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds); if (!kinds) { @@ -411,19 +503,25 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid) continue; path = libxl__sprintf(gc, "/local/domain/%d/device/%s", domid, kinds[i]); - devs = libxl__xs_directory(gc, XBT_NULL, path, &num_devs); + devs = libxl__xs_directory(gc, XBT_NULL, path, &num_dev_xsentries); if (!devs) continue; - for (j = 0; j < num_devs; j++) { + for (j = 0; j < num_dev_xsentries; j++) { path = libxl__sprintf(gc, "/local/domain/%d/device/%s/%s/backend", domid, kinds[i], devs[j]); path = libxl__xs_read(gc, XBT_NULL, path); - if (path && libxl__parse_backend_path(gc, path, &dev) == 0) { - dev.domid = domid; - dev.kind = kind; - dev.devid = atoi(devs[j]); - - libxl__device_destroy(gc, &dev); + GCNEW(dev); + if (path && libxl__parse_backend_path(gc, path, dev) == 0) { + aodev = &aodevs->array[numdev]; + dev->domid = domid; + dev->kind = kind; + dev->devid = atoi(devs[j]); + aodev->action = DEVICE_DISCONNECT; + aodev->dev = dev; + aodev->callback = libxl__ao_devices_callback; + aodev->force = drs->force; + libxl__initiate_device_remove(egc, aodev); + numdev++; } } } @@ -431,17 +529,22 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid) /* console 0 frontend directory is not under /local/domain/<domid>/device */ path = libxl__sprintf(gc, "/local/domain/%d/console/backend", domid); path = libxl__xs_read(gc, XBT_NULL, path); + GCNEW(dev); if (path && strcmp(path, "") && - libxl__parse_backend_path(gc, path, &dev) == 0) { - dev.domid = domid; - dev.kind = LIBXL__DEVICE_KIND_CONSOLE; - dev.devid = 0; + libxl__parse_backend_path(gc, path, dev) == 0) { + dev->domid = domid; + dev->kind = LIBXL__DEVICE_KIND_CONSOLE; + dev->devid = 0; - libxl__device_destroy(gc, &dev); + /* Currently console devices can be destroyed synchronously by just + * removing xenstore entries, this is what libxl__device_destroy does. + */ + libxl__device_destroy(gc, dev); } out: - return 0; + if (!numdev) drs->callback(egc, drs, rc); + return; } /* Callbacks for device related operations */ @@ -645,6 +748,16 @@ out: return; } +static void devices_remove_callback(libxl__egc *egc, libxl__ao_devices *aodevs, + int rc) +{ + libxl__devices_remove_state *drs = CONTAINER_OF(aodevs, *drs, aodevs); + STATE_AO_GC(drs->ao); + + drs->callback(egc, drs, rc); + return; +} + int libxl__wait_for_device_model(libxl__gc *gc, uint32_t domid, char *state, libxl__spawn_starting *spawning, diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index dadad76108..6a041f96b9 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -694,6 +694,10 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc, libxl__dm_spawn_state *stubdom_dmss, int rc); +static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc); + void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss) { STATE_AO_GC(sdss->dm.spawn.ao); @@ -914,12 +918,31 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc, out: if (rc) { - if (dm_domid) - libxl_domain_destroy(CTX, dm_domid); + if (dm_domid) { + sdss->dis.ao = ao; + sdss->dis.domid = dm_domid; + sdss->dis.callback = spaw_stubdom_pvqemu_destroy_cb; + libxl__destroy_domid(egc, &sdss->dis); + return; + } } sdss->callback(egc, &sdss->dm, rc); } +static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc) +{ + libxl__stub_dm_spawn_state *sdss = CONTAINER_OF(dis, *sdss, dis); + STATE_AO_GC(sdss->dis.ao); + + if (rc) + LOG(ERROR, "destruction of domain %u after failed creation failed", + sdss->pvqemu.guest_domid); + + sdss->callback(egc, &sdss->dm, rc); +} + /* callbacks passed to libxl__spawn_spawn */ static void device_model_confirm(libxl__egc *egc, libxl__spawn_state *spawn, const char *xsdata); @@ -1115,55 +1138,27 @@ static void device_model_spawn_outcome(libxl__egc *egc, int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) { - libxl_ctx *ctx = libxl__gc_owner(gc); 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); - const char *savefile; - - 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", stubdomid); - ret = libxl_domain_destroy(ctx, stubdomid); - if (ret) - goto out; - - savefile = libxl__device_model_savefile(gc, domid); - ret = unlink(savefile); - /* - * On suspend libxl__domain_save_device_model will have already - * unlinked the save file. - */ - if (ret && errno == ENOENT) ret = 0; - if (ret) { - LIBXL__LOG_ERRNO(ctx, XTL_ERROR, - "failed to remove device-model savefile %s\n", - savefile); - goto out; - } + if (!pid || !atoi(pid)) { + LOG(ERROR, "could not find device-model's pid for dom %u", domid); + ret = ERROR_FAIL; + goto out; + } + ret = kill(atoi(pid), SIGHUP); + if (ret < 0 && errno == ESRCH) { + LOG(ERROR, "Device Model already exited"); + ret = 0; + } else if (ret == 0) { + LOG(DEBUG, "Device Model signaled"); + ret = 0; } 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; - } + LOGE(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)); - xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/hvmloader", domid)); out: return ret; diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 101e7fbcf5..562ca6173f 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -875,7 +875,6 @@ _hidden char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device); _hidden int libxl__parse_backend_path(libxl__gc *gc, const char *path, libxl__device *dev); _hidden int libxl__device_destroy(libxl__gc *gc, libxl__device *dev); -_hidden int libxl__devices_destroy(libxl__gc *gc, uint32_t domid); _hidden int libxl__wait_for_backend(libxl__gc *gc, char *be_path, char *state); /* @@ -1978,6 +1977,7 @@ typedef enum { } libxl__device_action; typedef struct libxl__ao_device libxl__ao_device; +typedef struct libxl__ao_devices libxl__ao_devices; typedef void libxl__device_callback(libxl__egc*, libxl__ao_device*); /* This functions sets the necessary libxl__ao_device struct values to use @@ -1996,6 +1996,20 @@ typedef void libxl__device_callback(libxl__egc*, libxl__ao_device*); */ _hidden void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev); +/* Prepare a bunch of devices for addition/removal. Every ao_device in + * ao_devices is set to 'active', and the ao_device 'base' field is set to + * the one pointed by aodevs. + */ +_hidden void libxl__prepare_ao_devices(libxl__ao *ao, + libxl__ao_devices *aodevs); + +/* Generic callback to use when adding/removing several devices, this will + * check if the given aodev is the last one, and call the callback in the + * parent libxl__ao_devices struct, passing the appropriate error if found. + */ +_hidden void libxl__ao_devices_callback(libxl__egc *egc, + libxl__ao_device *aodev); + struct libxl__ao_device { /* filled in by user */ libxl__ao *ao; @@ -2004,10 +2018,27 @@ struct libxl__ao_device { int force; libxl__device_callback *callback; /* private for implementation */ + int active; int rc; libxl__ev_devstate backend_ds; /* Bodge for Qemu devices */ libxl__ev_time timeout; + /* Used internally to have a reference to the upper libxl__ao_devices + * struct when present */ + libxl__ao_devices *aodevs; +}; + +/* Helper struct to simply the plug/unplug of multiple devices at the same + * time. + * + * This structure holds several devices, and the callback is only called + * when all the devices inside of the array have finished. + */ +typedef void libxl__devices_callback(libxl__egc*, libxl__ao_devices*, int rc); +struct libxl__ao_devices { + libxl__ao_device *array; + int size; + libxl__devices_callback *callback; }; /* @@ -2098,6 +2129,86 @@ struct libxl__ao_device { _hidden void libxl__initiate_device_remove(libxl__egc *egc, libxl__ao_device *aodev); +/*----- Domain destruction -----*/ + +/* Domain destruction has been split into two functions: + * + * libxl__domain_destroy is the main destroy function, which detects + * stubdoms and calls libxl__destroy_domid on the domain and its + * stubdom if present, creating a different libxl__destroy_domid_state + * for each one of them. + * + * libxl__destroy_domid actually destroys the domain, but it + * doesn't check for stubdomains, since that would involve + * recursion, which we want to avoid. + */ + +typedef struct libxl__domain_destroy_state libxl__domain_destroy_state; +typedef struct libxl__destroy_domid_state libxl__destroy_domid_state; +typedef struct libxl__devices_remove_state libxl__devices_remove_state; + +typedef void libxl__domain_destroy_cb(libxl__egc *egc, + libxl__domain_destroy_state *dds, + int rc); + +typedef void libxl__domid_destroy_cb(libxl__egc *egc, + libxl__destroy_domid_state *dis, + int rc); + +typedef void libxl__devices_remove_callback(libxl__egc *egc, + libxl__devices_remove_state *drs, + int rc); + +struct libxl__devices_remove_state { + /* filled in by user */ + libxl__ao *ao; + uint32_t domid; + libxl__devices_remove_callback *callback; + int force; /* libxl_device_TYPE_destroy rather than _remove */ + /* private */ + libxl__ao_devices aodevs; + int num_devices; +}; + +struct libxl__destroy_domid_state { + /* filled in by user */ + libxl__ao *ao; + uint32_t domid; + libxl__domid_destroy_cb *callback; + /* private to implementation */ + libxl__devices_remove_state drs; +}; + +struct libxl__domain_destroy_state { + /* filled by the user */ + libxl__ao *ao; + uint32_t domid; + libxl__domain_destroy_cb *callback; + /* Private */ + int rc; + uint32_t stubdomid; + libxl__destroy_domid_state stubdom; + int stubdom_finished; + libxl__destroy_domid_state domain; + int domain_finished; +}; + +/* + * Entry point for domain destruction + * This function checks for stubdom presence and then calls + * libxl__destroy_domid on the passed domain and its stubdom if found. + */ +_hidden void libxl__domain_destroy(libxl__egc *egc, + libxl__domain_destroy_state *dds); + +/* Used to destroy a domain with the passed id (it doesn't check for stubs) */ +_hidden void libxl__destroy_domid(libxl__egc *egc, + libxl__destroy_domid_state *dis); + +/* Entry point for devices destruction */ +_hidden void libxl__devices_destroy(libxl__egc *egc, + libxl__devices_remove_state *drs); + /*----- device model creation -----*/ /* First layer; wraps libxl__spawn_spawn. */ @@ -2131,6 +2242,7 @@ typedef struct { libxl_domain_config dm_config; libxl__domain_build_state dm_state; libxl__dm_spawn_state pvqemu; + libxl__destroy_domid_state dis; } libxl__stub_dm_spawn_state; _hidden void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state*); @@ -2158,6 +2270,8 @@ struct libxl__domain_create_state { /* If we're not doing stubdom, we use only dmss.dm, * for the non-stubdom device model. */ libxl__save_helper_state shs; + /* necessary if the domain creation failed and we have to destroy it */ + libxl__domain_destroy_state dds; }; /*----- Domain suspend (save) functions -----*/ diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 3b03e5d928..b9c9e2c4b5 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1400,7 +1400,7 @@ static int handle_domain_death(uint32_t *r_domid, case LIBXL_ACTION_ON_SHUTDOWN_DESTROY: LOG("Domain %d needs to be cleaned up: destroying the domain", *r_domid); - libxl_domain_destroy(ctx, *r_domid); + libxl_domain_destroy(ctx, *r_domid, 0); *r_domid = INVALID_DOMID; break; @@ -2015,7 +2015,7 @@ start: error_out: release_lock(); if (libxl_domid_valid_guest(domid)) { - libxl_domain_destroy(ctx, domid); + libxl_domain_destroy(ctx, domid, 0); domid = INVALID_DOMID; } @@ -2580,7 +2580,7 @@ static void destroy_domain(const char *p) fprintf(stderr, "Cannot destroy privileged domain 0.\n\n"); exit(-1); } - rc = libxl_domain_destroy(ctx, domid); + rc = libxl_domain_destroy(ctx, domid, 0); if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n",rc); exit(-1); } } @@ -2854,7 +2854,7 @@ static int save_domain(const char *p, const char *filename, int checkpoint, if (checkpoint) libxl_domain_resume(ctx, domid, 1); else - libxl_domain_destroy(ctx, domid); + libxl_domain_destroy(ctx, domid, 0); exit(0); } @@ -3111,7 +3111,7 @@ static void migrate_domain(const char *domain_spec, const char *rune, } fprintf(stderr, "migration sender: Target reports successful startup.\n"); - libxl_domain_destroy(ctx, domid); /* bang! */ + libxl_domain_destroy(ctx, domid, 0); /* bang! */ fprintf(stderr, "Migration successful.\n"); exit(0); @@ -3264,7 +3264,7 @@ static void migrate_receive(int debug, int daemonize, int monitor, if (rc) { fprintf(stderr, "migration target: Failure, destroying our copy.\n"); - rc2 = libxl_domain_destroy(ctx, domid); + rc2 = libxl_domain_destroy(ctx, domid, 0); if (rc2) { fprintf(stderr, "migration target: Failed to destroy our copy" " (code %d).\n", rc2); diff --git a/tools/python/xen/lowlevel/xl/xl.c b/tools/python/xen/lowlevel/xl/xl.c index b68b55ad87..553fc58871 100644 --- a/tools/python/xen/lowlevel/xl/xl.c +++ b/tools/python/xen/lowlevel/xl/xl.c @@ -437,7 +437,7 @@ static PyObject *pyxl_domain_destroy(XlObject *self, PyObject *args) int domid; if ( !PyArg_ParseTuple(args, "i", &domid) ) return NULL; - if ( libxl_domain_destroy(self->ctx, domid) ) { + if ( libxl_domain_destroy(self->ctx, domid, 0) ) { PyErr_SetString(xl_error_obj, "cannot destroy domain"); return NULL; } |