]> xenbits.xensource.com Git - people/hx242/xen.git/commitdiff
libxc/restore: STATIC_DATA_END inference for v2 compatibility
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 16 Dec 2019 19:03:14 +0000 (19:03 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 29 May 2020 16:33:03 +0000 (17:33 +0100)
A v3 stream can compatibly read a v2 stream by inferring the position of the
STATIC_DATA_END record.

v2 compatibility is only needed for x86.  No other architectures exist yet,
but they will have a minimum of v3 when introduced.

The x86 HVM compatibility point being in handle_page_data() (which is common
code) is a bit awkward.  However, as the two compatibility points are subtly
different, and it is (intentionally) not possible to call into arch specific
code from common code (except via the ops hooks), use some #ifdef-ary and
opencode the check, rather than make handle_page_data() a per-arch helper.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
tools/libxc/include/xenguest.h
tools/libxc/xc_sr_common.h
tools/libxc/xc_sr_restore.c
tools/libxc/xc_sr_restore_x86_pv.c

index efd90b0d42442e75666f5178267753bea259dbd5..b4df8d0ffeff97a0c15f38f1a3feb23837a0eb85 100644 (file)
@@ -139,7 +139,7 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom,
 
 /* callbacks provided by xc_domain_restore */
 struct restore_callbacks {
-    /* Called once the STATIC_DATA_END record has been received. */
+    /* Called once the STATIC_DATA_END record has been received/inferred. */
     int (*static_data_done)(void *data);
 
     /* Called after a new checkpoint to suspend the guest. */
index ae0ab70f76d7a9e2fea4307cfc91fcb415195792..51e3d3ee3b69b4fd6d7c2338e6733a1b0281b59b 100644 (file)
@@ -253,7 +253,7 @@ struct xc_sr_context
             /* Currently buffering records between a checkpoint */
             bool buffer_all_records;
 
-            /* Whether a STATIC_DATA_END record has been seen. */
+            /* Whether a STATIC_DATA_END record has been seen/inferred. */
             bool seen_static_data_end;
 
 /*
@@ -428,6 +428,9 @@ int read_record(struct xc_sr_context *ctx, int fd, struct xc_sr_record *rec);
 int populate_pfns(struct xc_sr_context *ctx, unsigned int count,
                   const xen_pfn_t *original_pfns, const uint32_t *types);
 
+/* Handle a STATIC_DATA_END record. */
+int handle_static_data_end(struct xc_sr_context *ctx);
+
 #endif
 /*
  * Local variables:
index 9c924387aeb519c68c510014c1a42d6dc7a07da8..bb94cd879d9080b9ed5196e150c9f7b1d577cac2 100644 (file)
@@ -342,6 +342,31 @@ static int handle_page_data(struct xc_sr_context *ctx, struct xc_sr_record *rec)
     xen_pfn_t *pfns = NULL, pfn;
     uint32_t *types = NULL, type;
 
+    /*
+     * v2 compatibility only exists for x86 streams.  This is a bit of a
+     * bodge, but it is less bad than duplicating handle_page_data() between
+     * different architectures.
+     */
+#if defined(__i386__) || defined(__x86_64__)
+    /* v2 compat.  Infer the position of STATIC_DATA_END. */
+    if ( ctx->restore.format_version < 3 && !ctx->restore.seen_static_data_end )
+    {
+        rc = handle_static_data_end(ctx);
+        if ( rc )
+        {
+            ERROR("Inferred STATIC_DATA_END record failed");
+            goto err;
+        }
+        rc = -1;
+    }
+
+    if ( !ctx->restore.seen_static_data_end )
+    {
+        ERROR("No STATIC_DATA_END seen");
+        goto err;
+    }
+#endif
+
     if ( rec->length < sizeof(*pages) )
     {
         ERROR("PAGE_DATA record truncated: length %u, min %zu",
@@ -631,7 +656,7 @@ static int buffer_record(struct xc_sr_context *ctx, struct xc_sr_record *rec)
     return 0;
 }
 
-static int handle_static_data_end(struct xc_sr_context *ctx)
+int handle_static_data_end(struct xc_sr_context *ctx)
 {
     xc_interface *xch = ctx->xch;
     int rc = 0;
index 904ccc462a6f221c76926e2dcacbc0ed04aae70d..0adfcdcddae54c4d51d0befbe2b61f2bec107c3f 100644 (file)
@@ -679,6 +679,23 @@ static int handle_x86_pv_p2m_frames(struct xc_sr_context *ctx,
     unsigned int start, end, x, fpp = PAGE_SIZE / ctx->x86.pv.width;
     int rc;
 
+    /* v2 compat.  Infer the position of STATIC_DATA_END. */
+    if ( ctx->restore.format_version < 3 && !ctx->restore.seen_static_data_end )
+    {
+        rc = handle_static_data_end(ctx);
+        if ( rc )
+        {
+            ERROR("Inferred STATIC_DATA_END record failed");
+            return rc;
+        }
+    }
+
+    if ( !ctx->restore.seen_static_data_end )
+    {
+        ERROR("No STATIC_DATA_END seen");
+        return -1;
+    }
+
     if ( !ctx->x86.pv.restore.seen_pv_info )
     {
         ERROR("Not yet received X86_PV_INFO record");