static void domcreate_bootloader_done(libxl__egc *egc, libxl__bootloader_state *bl, int rc) { libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl); STATE_AO_GC(bl->ao); /* convenience aliases */ const uint32_t domid = dcs->guest_domid; libxl_domain_config *const d_config = dcs->guest_config; libxl_domain_build_info *const info = &d_config->b_info; const int restore_fd = dcs->restore_fd; libxl__domain_build_state *const state = &dcs->build_state; libxl__srm_restore_autogen_callbacks *const callbacks = &dcs->shs.callbacks.restore.a; if (rc) { domcreate_rebuild_done(egc, dcs, rc); return; } /* consume bootloader outputs. state->pv_{kernel,ramdisk} have * been initialised by the bootloader already. */ state->pv_cmdline = bl->cmdline; /* 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 ) { rc = libxl__domain_build(gc, &d_config->b_info, domid, state); domcreate_rebuild_done(egc, dcs, rc); return; } /* Restore */ rc = libxl__build_pre(gc, domid, info, state); if (rc) goto out; /* read signature */ int hvm, pae, superpages; switch (info->type) { case LIBXL_DOMAIN_TYPE_HVM: hvm = 1; superpages = 1; pae = libxl_defbool_val(info->u.hvm.pae); callbacks->toolstack_restore = libxl__toolstack_restore; break; case LIBXL_DOMAIN_TYPE_PV: hvm = 0; superpages = 0; pae = 1; break; default: rc = ERROR_INVAL; goto out; } libxl__xc_domain_restore(egc, dcs, hvm, pae, superpages, 1); return; out: libxl__xc_domain_restore_done(egc, dcs, rc, 0, 0); }
/* * Returns a boolean indicating whether a further action should be set * up by the caller. This is needed to prevent mutual recursion with * stream_continue(). * * It is a bug for this function to ever call stream_continue() or * setup_read_record(). */ static bool process_record(libxl__egc *egc, libxl__stream_read_state *stream) { STATE_AO_GC(stream->ao); libxl__domain_create_state *dcs = stream->dcs; libxl__sr_record_buf *rec; bool further_action_needed = false; int rc = 0; /* Pop a record from the head of the queue. */ assert(!LIBXL_STAILQ_EMPTY(&stream->record_queue)); rec = LIBXL_STAILQ_FIRST(&stream->record_queue); LIBXL_STAILQ_REMOVE_HEAD(&stream->record_queue, entry); LOG(DEBUG, "Record: %u, length %u", rec->hdr.type, rec->hdr.length); switch (rec->hdr.type) { case REC_TYPE_END: stream_complete(egc, stream, 0); break; case REC_TYPE_LIBXC_CONTEXT: libxl__xc_domain_restore(egc, dcs, &stream->shs, 0, 0, 0); break; case REC_TYPE_EMULATOR_XENSTORE_DATA: if (dcs->guest_config->b_info.device_model_version == LIBXL_DEVICE_MODEL_VERSION_NONE) { rc = ERROR_FAIL; LOG(ERROR, "Received a xenstore emulator record when none was expected"); goto err; } if (rec->hdr.length < sizeof(libxl__sr_emulator_hdr)) { rc = ERROR_FAIL; LOG(ERROR, "Emulator xenstore data record too short to contain header"); goto err; } rc = libxl__restore_emulator_xenstore_data(dcs, rec->body + sizeof(libxl__sr_emulator_hdr), rec->hdr.length - sizeof(libxl__sr_emulator_hdr)); if (rc) goto err; /* * libxl__restore_emulator_xenstore_data() is a synchronous function. * Request that our caller queues another action for us. */ further_action_needed = true; break; case REC_TYPE_EMULATOR_CONTEXT: if (dcs->guest_config->b_info.device_model_version == LIBXL_DEVICE_MODEL_VERSION_NONE) { rc = ERROR_FAIL; LOG(ERROR, "Received an emulator context record when none was expected"); goto err; } write_emulator_blob(egc, stream, rec); break; case REC_TYPE_CHECKPOINT_END: if (!stream->in_checkpoint) { LOG(ERROR, "Unexpected CHECKPOINT_END record in stream"); rc = ERROR_FAIL; goto err; } checkpoint_done(egc, stream, 0); break; default: LOG(ERROR, "Unrecognised record 0x%08x", rec->hdr.type); rc = ERROR_FAIL; goto err; } assert(!rc); free_record(rec); return further_action_needed; err: assert(rc); free_record(rec); stream_complete(egc, stream, rc); return false; }