(lib)xl: soft reset support

Use existing create/restore path to perform 'soft reset' for HVM
domains. Tear everything down, e.g. destroy domain's device model,
remove the domain from xenstore, save toolstack record and start
over.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
This commit is contained in:
Vitaly Kuznetsov authored and Ian Campbell committed 2015-09-24 11:46:29 +01:00
1 parent 546678c6a6
commit c57e6ebd8c
8 files changed
+246 -27

No files matched your search

+7 -1
View File
@@ -351,6 +351,12 @@ destroy the domain.
write a "coredump" of the domain to F</var/lib/xen/dump/NAME> and then
restart the domain.
=item B<soft-reset>
Reset all Xen specific interfaces for the Xen-aware HVM domain allowing
it to reestablish these interfaces and continue executing the domain. PV
and non-Xen-aware HVM guests are not supported.
=back
The default for C<on_poweroff> is C<destroy>.
@@ -372,7 +378,7 @@ Action to take if the domain crashes. Default is C<destroy>.
=item B<on_soft_reset="ACTION">
Action to take if the domain performs 'soft reset' (e.g. does kexec).
Default is C<restart>.
Default is C<soft-reset>.
=back
+18 -4
View File
@@ -1500,6 +1500,7 @@ void libxl__domain_destroy(libxl__egc *egc, libxl__domain_destroy_state *dds)
dds->stubdom.ao = ao;
dds->stubdom.domid = stubdomid;
dds->stubdom.callback = stubdom_destroy_callback;
dds->stubdom.soft_reset = false;
libxl__destroy_domid(egc, &dds->stubdom);
} else {
dds->stubdom_finished = 1;
@@ -1508,6 +1509,7 @@ void libxl__domain_destroy(libxl__egc *egc, libxl__domain_destroy_state *dds)
dds->domain.ao = ao;
dds->domain.domid = dds->domid;
dds->domain.callback = domain_destroy_callback;
dds->domain.soft_reset = dds->soft_reset;
libxl__destroy_domid(egc, &dds->domain);
}
@@ -1688,10 +1690,14 @@ static void devices_destroy_cb(libxl__egc *egc,
/* Clean up qemu-save and qemu-resume files. They are
* intermediate files created by libxc. Unfortunately they
* don't fit in existing userdata scheme very well.
* don't fit in existing userdata scheme very well. In soft reset
* case we need to keep the file.
*/
rc = libxl__remove_file(gc, libxl__device_model_savefile(gc, domid));
if (rc < 0) goto out;
if (!dis->soft_reset) {
rc = libxl__remove_file(gc,
libxl__device_model_savefile(gc, domid));
if (rc < 0) goto out;
}
rc = libxl__remove_file(gc,
GCSPRINTF(LIBXL_DEVICE_MODEL_RESTORE_FILE".%u", domid));
if (rc < 0) goto out;
@@ -1702,7 +1708,15 @@ static void devices_destroy_cb(libxl__egc *egc,
ctx->xch = xc_interface_open(ctx->lg,0,0);
if (!ctx->xch) goto badchild;
rc = xc_domain_destroy(ctx->xch, domid);
if (!dis->soft_reset) {
rc = xc_domain_destroy(ctx->xch, domid);
} else {
rc = xc_domain_pause(ctx->xch, domid);
if (rc < 0) goto badchild;
rc = xc_domain_soft_reset(ctx->xch, domid);
if (rc < 0) goto badchild;
rc = xc_domain_unpause(ctx->xch, domid);
}
if (rc < 0) goto badchild;
_exit(0);
+15
View File
@@ -204,6 +204,13 @@
*/
#define LIBXL_HAVE_BUILDINFO_ARM_GIC_VERSION 1
/*
* LIBXL_HAVE_SOFT_RESET indicates that libxl supports performing
* 'soft reset' for domains and there is 'soft_reset' shutdown reason
* in enum libxl_shutdown_reason.
*/
#define LIBXL_HAVE_SOFT_RESET 1
/*
* libxl ABI compatibility
*
@@ -1132,6 +1139,14 @@ int static inline libxl_domain_create_restore_0x040200(
#endif
int libxl_domain_soft_reset(libxl_ctx *ctx,
libxl_domain_config *d_config,
uint32_t domid,
const libxl_asyncop_how *ao_how,
const libxl_asyncprogress_how
*aop_console_how)
LIBXL_EXTERNAL_CALLERS_ONLY;
/* A progress report will be made via ao_console_how, of type
* domain_create_console_available, when the domain's primary
* console is available and can be connected to.
+177 -19
View File
@@ -496,8 +496,6 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
/* convenience aliases */
libxl_domain_create_info *info = &d_config->c_info;
assert(!libxl_domid_valid_guest(*domid));
uuid_string = libxl__uuid2string(gc, info->uuid);
if (!uuid_string) {
rc = ERROR_NOMEM;
@@ -518,7 +516,6 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
}
flags |= XEN_DOMCTL_CDF_hap;
}
*domid = -1;
/* Ultimately, handle is an array of 16 uint8_t, same as uuid */
libxl_uuid_copy(ctx, (libxl_uuid *)handle, &info->uuid);
@@ -530,13 +527,17 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
goto out;
}
ret = xc_domain_create_config(ctx->xch, info->ssidref,
handle, flags, domid,
xc_config);
if (ret < 0) {
LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "domain creation fail");
rc = ERROR_FAIL;
goto out;
/* Valid domid here means we're soft resetting. */
if (!libxl_domid_valid_guest(*domid)) {
ret = xc_domain_create_config(ctx->xch, info->ssidref,
handle, flags, domid,
xc_config);
if (ret < 0) {
LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
"domain creation fail");
rc = ERROR_FAIL;
goto out;
}
}
rc = libxl__arch_domain_save_config(gc, d_config, xc_config);
@@ -771,9 +772,8 @@ static void initiate_domain_create(libxl__egc *egc,
libxl_domain_config *const d_config = dcs->guest_config;
libxl__domain_build_state *const state = &dcs->build_state;
const int restore_fd = dcs->restore_fd;
memset(&dcs->build_state, 0, sizeof(dcs->build_state));
domid = 0;
domid = dcs->domid_soft_reset;
if (d_config->c_info.ssid_label) {
char *s = d_config->c_info.ssid_label;
@@ -938,7 +938,7 @@ static void initiate_domain_create(libxl__egc *egc,
d_config->nics[i].devid = ++last_devid;
}
if (restore_fd >= 0) {
if (restore_fd >= 0 || dcs->domid_soft_reset != INVALID_DOMID) {
LOG(DEBUG, "restoring, not running bootloader");
domcreate_bootloader_done(egc, &dcs->bl, 0);
} else {
@@ -1011,7 +1011,7 @@ static void domcreate_bootloader_done(libxl__egc *egc,
dcs->dmss.dm.callback = domcreate_devmodel_started;
dcs->dmss.callback = domcreate_devmodel_started;
if ( restore_fd < 0 ) {
if (restore_fd < 0 && dcs->domid_soft_reset == INVALID_DOMID) {
rc = libxl__domain_build(gc, d_config, domid, state);
domcreate_rebuild_done(egc, dcs, rc);
return;
@@ -1031,8 +1031,10 @@ static void domcreate_bootloader_done(libxl__egc *egc,
dcs->srs.completion_callback = domcreate_stream_done;
dcs->srs.checkpoint_callback = remus_checkpoint_stream_done;
libxl__stream_read_start(egc, &dcs->srs);
return;
if (restore_fd >= 0) {
libxl__stream_read_start(egc, &dcs->srs);
return;
}
out:
domcreate_stream_done(egc, &dcs->srs, rc);
@@ -1121,9 +1123,12 @@ out:
libxl__file_reference_unmap(&state->pv_ramdisk);
}
esave = errno;
libxl_fd_set_nonblock(ctx, fd, 0);
errno = esave;
/* fd == -1 here means we're doing soft reset. */
if (fd != -1) {
esave = errno;
libxl_fd_set_nonblock(ctx, fd, 0);
errno = esave;
}
domcreate_rebuild_done(egc, dcs, ret);
}
@@ -1544,6 +1549,14 @@ typedef struct {
uint32_t *domid_out;
} libxl__app_domain_create_state;
typedef struct {
libxl__app_domain_create_state cdcs;
libxl__domain_destroy_state dds;
libxl__domain_suspend_state dss;
char *toolstack_buf;
uint32_t toolstack_len;
} libxl__domain_soft_reset_state;
static void domain_create_cb(libxl__egc *egc,
libxl__domain_create_state *dcs,
int rc, uint32_t domid);
@@ -1572,6 +1585,7 @@ static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config,
if (rc < 0) goto out_err;
}
cdcs->dcs.callback = domain_create_cb;
cdcs->dcs.domid_soft_reset = INVALID_DOMID;
libxl__ao_progress_gethow(&cdcs->dcs.aop_console_how, aop_console_how);
cdcs->domid_out = domid;
@@ -1584,6 +1598,135 @@ static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config,
}
static void domain_soft_reset_cb(libxl__egc *egc,
libxl__domain_destroy_state *dds,
int rc)
{
STATE_AO_GC(dds->ao);
libxl__domain_soft_reset_state *srs = CONTAINER_OF(dds, *srs, dds);
libxl__app_domain_create_state *cdcs = &srs->cdcs;
char *savefile, *restorefile;
if (rc) {
LOG(ERROR, "destruction of domain %u failed.", dds->domid);
goto error;
}
cdcs->dcs.guest_domid = dds->domid;
rc = libxl__restore_emulator_xenstore_data(&cdcs->dcs, srs->toolstack_buf,
srs->toolstack_len);
if (rc) {
LOG(ERROR, "failed to restore toolstack record.");
goto error;
}
savefile = GCSPRINTF(LIBXL_DEVICE_MODEL_SAVE_FILE".%d", dds->domid);
restorefile = GCSPRINTF(LIBXL_DEVICE_MODEL_RESTORE_FILE".%d", dds->domid);
rc = rename(savefile, restorefile);
if (rc) {
LOG(ERROR, "failed to rename dm save file.");
goto error;
}
initiate_domain_create(egc, &cdcs->dcs);
return;
error:
domcreate_complete(egc, &cdcs->dcs, rc);
}
static int do_domain_soft_reset(libxl_ctx *ctx,
libxl_domain_config *d_config,
uint32_t domid_soft_reset,
const libxl_asyncop_how *ao_how,
const libxl_asyncprogress_how
*aop_console_how)
{
AO_CREATE(ctx, 0, ao_how);
libxl__domain_soft_reset_state *srs;
libxl__app_domain_create_state *cdcs;
libxl__domain_create_state *dcs;
libxl__domain_build_state *state;
libxl__domain_suspend_state *dss;
char *dom_path, *xs_store_mfn, *xs_console_mfn;
uint32_t domid_out;
int rc;
GCNEW(srs);
cdcs = &srs->cdcs;
dcs = &cdcs->dcs;
state = &dcs->build_state;
dss = &srs->dss;
srs->cdcs.dcs.ao = ao;
srs->cdcs.dcs.guest_config = d_config;
libxl_domain_config_init(&srs->cdcs.dcs.guest_config_saved);
libxl_domain_config_copy(ctx, &srs->cdcs.dcs.guest_config_saved,
d_config);
cdcs->dcs.restore_fd = -1;
cdcs->dcs.domid_soft_reset = domid_soft_reset;
cdcs->dcs.callback = domain_create_cb;
libxl__ao_progress_gethow(&srs->cdcs.dcs.aop_console_how,
aop_console_how);
cdcs->domid_out = &domid_out;
dom_path = libxl__xs_get_dompath(gc, domid_soft_reset);
if (!dom_path) {
LOG(ERROR, "failed to read domain path");
rc = ERROR_FAIL;
goto out;
}
xs_store_mfn = xs_read(ctx->xsh, XBT_NULL,
GCSPRINTF("%s/store/ring-ref", dom_path),
NULL);
state->store_mfn = xs_store_mfn ? atol(xs_store_mfn): 0;
free(xs_store_mfn);
xs_console_mfn = xs_read(ctx->xsh, XBT_NULL,
GCSPRINTF("%s/console/ring-ref", dom_path),
NULL);
state->console_mfn = xs_console_mfn ? atol(xs_console_mfn): 0;
free(xs_console_mfn);
dss->ao = ao;
dss->domid = domid_soft_reset;
dss->dm_savefile = GCSPRINTF(LIBXL_DEVICE_MODEL_SAVE_FILE".%d",
domid_soft_reset);
rc = libxl__save_emulator_xenstore_data(dss, &srs->toolstack_buf,
&srs->toolstack_len);
if (rc) {
LOG(ERROR, "failed to save toolstack record.");
goto out;
}
rc = libxl__domain_suspend_device_model(gc, dss);
if (rc) {
LOG(ERROR, "failed to suspend device model.");
goto out;
}
/*
* Ask all backends to disconnect by removing the domain from
* xenstore. On the creation path the domain will be introduced to
* xenstore again with probably different store/console/...
* channels.
*/
xs_release_domain(ctx->xsh, cdcs->dcs.domid_soft_reset);
srs->dds.ao = ao;
srs->dds.domid = domid_soft_reset;
srs->dds.callback = domain_soft_reset_cb;
srs->dds.soft_reset = true;
libxl__domain_destroy(egc, &srs->dds);
return AO_INPROGRESS;
out:
return AO_CREATE_FAIL(rc);
}
static void domain_create_cb(libxl__egc *egc,
libxl__domain_create_state *dcs,
int rc, uint32_t domid)
@@ -1626,6 +1769,21 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
ao_how, aop_console_how);
}
int libxl_domain_soft_reset(libxl_ctx *ctx,
libxl_domain_config *d_config,
uint32_t domid,
const libxl_asyncop_how *ao_how,
const libxl_asyncprogress_how
*aop_console_how)
{
libxl_domain_build_info *const info = &d_config->b_info;
if (info->type != LIBXL_DOMAIN_TYPE_HVM) return ERROR_INVAL;
return do_domain_soft_reset(ctx, d_config, domid, ao_how,
aop_console_how);
}
/*
* Local variables:
* mode: C
+4
View File
@@ -111,6 +111,7 @@
#define STUBDOM_SPECIAL_CONSOLES 3
#define TAP_DEVICE_SUFFIX "-emu"
#define DOMID_XS_PATH "domid"
#define INVALID_DOMID ~0
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -3226,6 +3227,7 @@ struct libxl__destroy_domid_state {
/* private to implementation */
libxl__devices_remove_state drs;
libxl__ev_child destroyer;
bool soft_reset;
};
struct libxl__domain_destroy_state {
@@ -3240,6 +3242,7 @@ struct libxl__domain_destroy_state {
int stubdom_finished;
libxl__destroy_domid_state domain;
int domain_finished;
bool soft_reset;
};
/*
@@ -3405,6 +3408,7 @@ struct libxl__domain_create_state {
int restore_fd, libxc_fd;
int restore_fdfl; /* original flags of restore_fd */
libxl_domain_restore_params restore_params;
uint32_t domid_soft_reset;
libxl__domain_create_cb *callback;
libxl_asyncprogress_how aop_console_how;
/* private to domain_create */
+2
View File
@@ -138,6 +138,8 @@ libxl_action_on_shutdown = Enumeration("action_on_shutdown", [
(5, "COREDUMP_DESTROY"),
(6, "COREDUMP_RESTART"),
(7, "SOFT_RESET"),
], init_val = "LIBXL_ACTION_ON_SHUTDOWN_DESTROY")
libxl_trigger = Enumeration("trigger", [
+1
View File
@@ -194,6 +194,7 @@ typedef enum {
DOMAIN_RESTART_NONE = 0, /* No domain restart */
DOMAIN_RESTART_NORMAL, /* Domain should be restarted */
DOMAIN_RESTART_RENAME, /* Domain should be renamed and restarted */
DOMAIN_RESTART_SOFT_RESET, /* Soft reset should be performed */
} domain_restart_type;
extern void printf_info_sexp(int domid, libxl_domain_config *d_config, FILE *fh);
+22 -3
View File
@@ -133,6 +133,8 @@ static const char *action_on_shutdown_names[] = {
[LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY] = "coredump-destroy",
[LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART] = "coredump-restart",
[LIBXL_ACTION_ON_SHUTDOWN_SOFT_RESET] = "soft-reset",
};
/* Optional data, in order:
@@ -1423,7 +1425,7 @@ static void parse_config_data(const char *config_source,
}
if (xlu_cfg_get_string (config, "on_soft_reset", &buf, 0))
buf = "restart";
buf = "soft-reset";
if (!parse_action_on_shutdown(buf, &d_config->on_soft_reset)) {
fprintf(stderr, "Unknown on_soft_reset action \"%s\" specified\n", buf);
exit(1);
@@ -2490,6 +2492,11 @@ static domain_restart_type handle_domain_death(uint32_t *r_domid,
*r_domid = INVALID_DOMID;
break;
case LIBXL_ACTION_ON_SHUTDOWN_SOFT_RESET:
reload_domain_config(*r_domid, d_config);
restart = DOMAIN_RESTART_SOFT_RESET;
break;
case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY:
case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART:
/* Already handled these above. */
@@ -2666,6 +2673,7 @@ static uint32_t create_domain(struct domain_create *dom_info)
int restore_fd_to_close = -1;
const libxl_asyncprogress_how *autoconnect_console_how;
struct save_file_header hdr;
uint32_t domid_soft_reset = INVALID_DOMID;
int restoring = (restore_file || (migrate_fd >= 0));
@@ -2880,7 +2888,13 @@ start:
* restore/migrate-receive it again.
*/
restoring = 0;
}else{
} else if (domid_soft_reset != INVALID_DOMID) {
/* Do soft reset. */
ret = libxl_domain_soft_reset(ctx, &d_config, domid_soft_reset,
0, autoconnect_console_how);
domid = domid_soft_reset;
domid_soft_reset = INVALID_DOMID;
} else {
ret = libxl_domain_create_new(ctx, &d_config, &domid,
0, autoconnect_console_how);
}
@@ -2948,8 +2962,13 @@ start:
event->u.domain_shutdown.shutdown_reason,
event->u.domain_shutdown.shutdown_reason);
switch (handle_domain_death(&domid, event, &d_config)) {
case DOMAIN_RESTART_SOFT_RESET:
domid_soft_reset = domid;
domid = INVALID_DOMID;
/* fall through */
case DOMAIN_RESTART_RENAME:
if (!preserve_domain(&domid, event, &d_config)) {
if (domid_soft_reset == INVALID_DOMID &&
!preserve_domain(&domid, event, &d_config)) {
/* If we fail then exit leaving the old domain in place. */
ret = -1;
goto out;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.