@@ -298,6 +298,9 @@ struct xc_sr_context
/* Sender has invoked verify mode on the stream. */
bool verify;
+
+ /* Domain context blob. */
+ struct xc_sr_blob context;
} restore;
};
@@ -1,25 +1,5 @@
#include "xg_sr_common_x86.h"
-int write_x86_tsc_info(struct xc_sr_context *ctx)
-{
- xc_interface *xch = ctx->xch;
- struct xc_sr_rec_x86_tsc_info tsc = {};
- struct xc_sr_record rec = {
- .type = REC_TYPE_X86_TSC_INFO,
- .length = sizeof(tsc),
- .data = &tsc,
- };
-
- if ( xc_domain_get_tsc_info(xch, ctx->domid, &tsc.mode,
- &tsc.nsec, &tsc.khz, &tsc.incarnation) < 0 )
- {
- PERROR("Unable to obtain TSC information");
- return -1;
- }
-
- return write_record(ctx, &rec);
-}
-
int handle_x86_tsc_info(struct xc_sr_context *ctx, struct xc_sr_record *rec)
{
xc_interface *xch = ctx->xch;
@@ -3,12 +3,6 @@
#include "xg_sr_common.h"
-/*
- * Obtains a domains TSC information from Xen and writes a X86_TSC_INFO record
- * into the stream.
- */
-int write_x86_tsc_info(struct xc_sr_context *ctx);
-
/*
* Parses a X86_TSC_INFO record and applies the result to the domain.
*/
@@ -35,9 +35,9 @@ static int read_headers(struct xc_sr_context *ctx)
return -1;
}
- if ( ihdr.version < 2 || ihdr.version > 3 )
+ if ( ihdr.version < 2 || ihdr.version > 4 )
{
- ERROR("Invalid Version: Expected 2 <= ver <= 3, Got %d",
+ ERROR("Invalid Version: Expected 2 <= ver <= 4, Got %d",
ihdr.version);
return -1;
}
@@ -529,6 +529,20 @@ static int send_checkpoint_dirty_pfn_list(struct xc_sr_context *ctx)
return rc;
}
+static int stream_complete(struct xc_sr_context *ctx)
+{
+ xc_interface *xch = ctx->xch;
+ int rc;
+
+ rc = xc_domain_setcontext(xch, ctx->domid,
+ ctx->restore.context.ptr,
+ ctx->restore.context.size);
+ if ( rc < 0 )
+ PERROR("Unable to restore domain context");
+
+ return rc;
+}
+
static int process_record(struct xc_sr_context *ctx, struct xc_sr_record *rec);
static int handle_checkpoint(struct xc_sr_context *ctx)
{
@@ -597,6 +611,10 @@ static int handle_checkpoint(struct xc_sr_context *ctx)
/* COLO */
/* We need to resume guest */
+ rc = stream_complete(ctx);
+ if ( rc )
+ goto err;
+
rc = ctx->restore.ops.stream_complete(ctx);
if ( rc )
goto err;
@@ -682,6 +700,21 @@ int handle_static_data_end(struct xc_sr_context *ctx)
return rc;
}
+/*
+ * Process a DOMAIN_CONTEXT record from the stream.
+ */
+static int handle_domain_context(struct xc_sr_context *ctx,
+ struct xc_sr_record *rec)
+{
+ xc_interface *xch = ctx->xch;
+ int rc = update_blob(&ctx->restore.context, rec->data, rec->length);
+
+ if ( rc )
+ ERROR("Unable to allocate %u bytes for domain context", rec->length);
+
+ return rc;
+}
+
static int process_record(struct xc_sr_context *ctx, struct xc_sr_record *rec)
{
xc_interface *xch = ctx->xch;
@@ -709,6 +742,10 @@ static int process_record(struct xc_sr_context *ctx, struct xc_sr_record *rec)
rc = handle_static_data_end(ctx);
break;
+ case REC_TYPE_DOMAIN_CONTEXT:
+ rc = handle_domain_context(ctx, rec);
+ break;
+
default:
rc = ctx->restore.ops.process_record(ctx, rec);
break;
@@ -860,6 +897,10 @@ static int restore(struct xc_sr_context *ctx)
* With Remus, if we reach here, there must be some error on primary,
* failover from the last checkpoint state.
*/
+ rc = stream_complete(ctx);
+ if ( rc )
+ goto err;
+
rc = ctx->restore.ops.stream_complete(ctx);
if ( rc )
goto err;
@@ -13,7 +13,7 @@ static int write_headers(struct xc_sr_context *ctx, uint16_t guest_type)
struct xc_sr_ihdr ihdr = {
.marker = IHDR_MARKER,
.id = htonl(IHDR_ID),
- .version = htonl(3),
+ .version = htonl(4),
.options = htons(IHDR_OPT_LITTLE_ENDIAN),
};
struct xc_sr_dhdr dhdr = {
@@ -44,6 +44,52 @@ static int write_headers(struct xc_sr_context *ctx, uint16_t guest_type)
return 0;
}
+/*
+ * Writes a DOMAIN_CONTEXT record into the stream.
+ */
+static int write_domain_context_record(struct xc_sr_context *ctx)
+{
+ xc_interface *xch = ctx->xch;
+ struct xc_sr_record rec = {
+ .type = REC_TYPE_DOMAIN_CONTEXT,
+ };
+ size_t len = 0;
+ int rc;
+
+ rc = xc_domain_getcontext(xch, ctx->domid, NULL, &len);
+ if ( rc < 0 )
+ {
+ PERROR("can't get record length for dom %u\n", ctx->domid);
+ goto out;
+ }
+
+ rec.data = malloc(len);
+
+ rc = -1;
+ if ( !rec.data )
+ {
+ PERROR("can't allocate %lu bytes\n", len);
+ goto out;
+ }
+
+ rc = xc_domain_getcontext(xch, ctx->domid, rec.data, &len);
+ if ( rc < 0 )
+ {
+ PERROR("can't get domain record for dom %u\n", ctx->domid);
+ goto out;
+ }
+
+ rec.length = len;
+ rc = write_record(ctx, &rec);
+ if ( rc < 0 )
+ PERROR("failed to write DOMAIN_CONTEXT record");
+
+ out:
+ free(rec.data);
+
+ return rc;
+}
+
/*
* Writes an END record into the stream.
*/
@@ -905,6 +951,10 @@ static int save(struct xc_sr_context *ctx, uint16_t guest_type)
goto err;
}
+ rc = write_domain_context_record(ctx);
+ if ( rc )
+ goto err;
+
rc = ctx->save.ops.end_of_checkpoint(ctx);
if ( rc )
goto err;
@@ -193,11 +193,6 @@ static int x86_hvm_end_of_checkpoint(struct xc_sr_context *ctx)
{
int rc;
- /* Write the TSC record. */
- rc = write_x86_tsc_info(ctx);
- if ( rc )
- return rc;
-
/* Write the HVM_CONTEXT record. */
rc = write_hvm_context(ctx);
if ( rc )
@@ -849,20 +849,6 @@ static int write_x86_pv_p2m_frames(struct xc_sr_context *ctx)
return rc;
}
-/*
- * Writes an SHARED_INFO record into the stream.
- */
-static int write_shared_info(struct xc_sr_context *ctx)
-{
- struct xc_sr_record rec = {
- .type = REC_TYPE_SHARED_INFO,
- .length = PAGE_SIZE,
- .data = ctx->x86.pv.shinfo,
- };
-
- return write_record(ctx, &rec);
-}
-
/*
* Normalise a pagetable for the migration stream. Performs mfn->pfn
* conversions on the ptes.
@@ -1093,14 +1079,6 @@ static int x86_pv_end_of_checkpoint(struct xc_sr_context *ctx)
{
int rc;
- rc = write_x86_tsc_info(ctx);
- if ( rc )
- return rc;
-
- rc = write_shared_info(ctx);
- if ( rc )
- return rc;
-
rc = write_all_vcpu_information(ctx);
if ( rc )
return rc;