diff options
Diffstat (limited to 'tools/libxl/libxl_create.c')
-rw-r--r-- | tools/libxl/libxl_create.c | 206 |
1 files changed, 162 insertions, 44 deletions
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index b137288f1f..9ce107a689 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -558,16 +558,40 @@ static int store_libxl_entry(libxl__gc *gc, uint32_t domid, libxl_device_model_version_to_string(b_info->device_model_version)); } -static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, - libxl_console_ready cb, void *priv, - uint32_t *domid_out, int restore_fd) +/*----- main domain creation -----*/ + +/* We have a linear control flow; only one event callback is + * outstanding at any time. Each initiation and callback function + * arranges for the next to be called, as the very last thing it + * does. (If that particular sub-operation is not needed, a + * function will call the next event callback directly.) + */ + +/* Event callbacks, in this order: */ +static void domcreate_devmodel_started(libxl__egc *egc, + libxl__dm_spawn_state *dmss, + int rc); + +/* Our own function to clean up and call the user's callback. + * The final call in the sequence. */ +static void domcreate_complete(libxl__egc *egc, + libxl__domain_create_state *dcs, + int rc); + +static void initiate_domain_create(libxl__egc *egc, + libxl__domain_create_state *dcs) { + STATE_AO_GC(dcs->ao); libxl_ctx *ctx = libxl__gc_owner(gc); - libxl__spawner_starting *dm_starting = 0; - libxl__domain_build_state state[1]; uint32_t domid; int i, ret; + /* convenience aliases */ + libxl_domain_config *const d_config = dcs->guest_config; + const int restore_fd = dcs->restore_fd; + const libxl_console_ready cb = dcs->console_cb; + void *const priv = dcs->console_cb_priv; + domid = 0; ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info); @@ -580,9 +604,12 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, goto error_out; } + dcs->guest_domid = domid; + dcs->dmss.dm.guest_domid = 0; /* means we haven't spawned */ + if ( d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV && cb ) { - if ( (*cb)(ctx, domid, priv) ) - goto error_out; + ret = (*cb)(ctx, domid, priv); + if (ret) goto error_out; } ret = libxl__domain_build_info_setdefault(gc, &d_config->b_info); @@ -606,7 +633,17 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, } } - memset(state, 0, sizeof(*state)); + memset(&dcs->build_state, 0, sizeof(dcs->build_state)); + libxl__domain_build_state *state = &dcs->build_state; + + /* We might be going to call libxl__spawn_local_dm, or _spawn_stub_dm. + * Fill in any field required by either, including both relevant + * callbacks (_spawn_stub_dm will overwrite our trespass if needed). */ + dcs->dmss.dm.spawn.ao = ao; + dcs->dmss.dm.guest_config = dcs->guest_config; + dcs->dmss.dm.build_state = &dcs->build_state; + dcs->dmss.dm.callback = domcreate_devmodel_started; + dcs->dmss.callback = domcreate_devmodel_started; if ( restore_fd >= 0 ) { ret = domain_restore(gc, &d_config->b_info, domid, restore_fd, state); @@ -656,14 +693,12 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, libxl_device_vkb_add(ctx, domid, &vkb); libxl_device_vkb_dispose(&vkb); - ret = libxl__create_device_model(gc, domid, d_config, - state, &dm_starting); - if (ret < 0) { - LIBXL__LOG(ctx, LIBXL__LOG_ERROR, - "failed to create device model: %d", ret); - goto error_out; - } - break; + dcs->dmss.dm.guest_domid = domid; + if (libxl_defbool_val(d_config->b_info.device_model_stubdomain)) + libxl__spawn_stub_dm(egc, &dcs->dmss); + else + libxl__spawn_local_dm(egc, &dcs->dmss.dm); + return; } case LIBXL_DOMAIN_TYPE_PV: { @@ -687,26 +722,52 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, libxl__device_console_dispose(&console); if (need_qemu) { - libxl__create_xenpv_qemu(gc, domid, d_config, state, &dm_starting); + dcs->dmss.dm.guest_domid = domid; + libxl__spawn_local_dm(egc, &dcs->dmss.dm); + return; + } else { + assert(!dcs->dmss.dm.guest_domid); + domcreate_devmodel_started(egc, &dcs->dmss.dm, 0); + return; } - break; } default: ret = ERROR_INVAL; goto error_out; } + abort(); /* not reached */ + + error_out: + assert(ret); + domcreate_complete(egc, dcs, ret); +} + +static void domcreate_devmodel_started(libxl__egc *egc, + libxl__dm_spawn_state *dmss, + int ret) +{ + libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, dmss.dm); + STATE_AO_GC(dmss->spawn.ao); + int i; + libxl_ctx *ctx = CTX; + int domid = dcs->guest_domid; + + /* convenience aliases */ + libxl_domain_config *const d_config = dcs->guest_config; + const libxl_console_ready cb = dcs->console_cb; + void *const priv = dcs->console_cb_priv; + + if (ret) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, + "device model did not start: %d", ret); + goto error_out; + } - if (dm_starting) { + if (dcs->dmss.dm.guest_domid) { if (d_config->b_info.device_model_version == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) { libxl__qmp_initializations(gc, domid, d_config); } - ret = libxl__confirm_device_model_startup(gc, state, dm_starting); - if (ret < 0) { - LIBXL__LOG(ctx, LIBXL__LOG_ERROR, - "device model did not start: %d", ret); - goto error_out; - } } for (i = 0; i < d_config->num_pcidevs; i++) @@ -734,38 +795,95 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, if ( cb && (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM || (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV && d_config->b_info.u.pv.bootloader ))) { - if ( (*cb)(ctx, domid, priv) ) - goto error_out; + ret = (*cb)(ctx, domid, priv); + if (ret) goto error_out; } - *domid_out = domid; - return 0; + domcreate_complete(egc, dcs, 0); + return; error_out: - if (domid) - libxl_domain_destroy(ctx, domid); + assert(ret); + domcreate_complete(egc, dcs, ret); +} - return ret; +static void domcreate_complete(libxl__egc *egc, + libxl__domain_create_state *dcs, + int rc) +{ + STATE_AO_GC(dcs->ao); + + 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->guest_domid = -1; + } + dcs->callback(egc, dcs, rc, dcs->guest_domid); } +/*----- application-facing domain creation interface -----*/ + +typedef struct { + libxl__domain_create_state dcs; + uint32_t *domid_out; +} libxl__app_domain_create_state; + +static void domain_create_cb(libxl__egc *egc, + libxl__domain_create_state *dcs, + int rc, uint32_t domid); + +static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config, + libxl_console_ready cb, void *priv, uint32_t *domid, + int restore_fd, const libxl_asyncop_how *ao_how) +{ + AO_CREATE(ctx, 0, ao_how); + libxl__app_domain_create_state *cdcs; + + GCNEW(cdcs); + cdcs->dcs.ao = ao; + cdcs->dcs.guest_config = d_config; + cdcs->dcs.restore_fd = restore_fd; + cdcs->dcs.console_cb = cb; + cdcs->dcs.console_cb_priv = priv; + cdcs->dcs.callback = domain_create_cb; + cdcs->domid_out = domid; + + initiate_domain_create(egc, &cdcs->dcs); + + return AO_INPROGRESS; +} + +static void domain_create_cb(libxl__egc *egc, + libxl__domain_create_state *dcs, + int rc, uint32_t domid) +{ + libxl__app_domain_create_state *cdcs = CONTAINER_OF(dcs, *cdcs, dcs); + STATE_AO_GC(cdcs->dcs.ao); + + if (!rc) + *cdcs->domid_out = domid; + + libxl__ao_complete(egc, ao, rc); +} + int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config, - libxl_console_ready cb, void *priv, uint32_t *domid) + libxl_console_ready cb, void *priv, + uint32_t *domid, + const libxl_asyncop_how *ao_how) { - GC_INIT(ctx); - int rc; - rc = do_domain_create(gc, d_config, cb, priv, domid, -1); - GC_FREE; - return rc; + return do_domain_create(ctx, d_config, cb, priv, domid, -1, ao_how); } int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config, - libxl_console_ready cb, void *priv, uint32_t *domid, int restore_fd) + libxl_console_ready cb, void *priv, + uint32_t *domid, int restore_fd, + const libxl_asyncop_how *ao_how) { - GC_INIT(ctx); - int rc; - rc = do_domain_create(gc, d_config, cb, priv, domid, restore_fd); - GC_FREE; - return rc; + return do_domain_create(ctx, d_config, cb, priv, domid, restore_fd, ao_how); } /* |