summaryrefslogtreecommitdiff
path: root/libxc.sr.superpage.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-10-12 04:00:49 +0000
committerCoprDistGit <infra@openeuler.org>2023-10-12 04:00:49 +0000
commitc22f60e6e55f1bf300dd76d2222a93911f3b2bb2 (patch)
treeef665e7018377f53612ac2751dcaea35a1c587b6 /libxc.sr.superpage.patch
parent39a4763249cd6289e5019acfe0c98dbb169f5f2e (diff)
automatic import of xenopeneuler22.03_LTS
Diffstat (limited to 'libxc.sr.superpage.patch')
-rw-r--r--libxc.sr.superpage.patch905
1 files changed, 905 insertions, 0 deletions
diff --git a/libxc.sr.superpage.patch b/libxc.sr.superpage.patch
new file mode 100644
index 0000000..ccb66bc
--- /dev/null
+++ b/libxc.sr.superpage.patch
@@ -0,0 +1,905 @@
+tools/libxc: use superpages during restore of HVM guest
+bsc#1035231 - migration of HVM domU does not use superpages on destination dom0
+bsc#1055695 - XEN: 11SP4 and 12SP3 HVM guests can not be restored
+
+During creating of a HVM domU meminit_hvm() tries to map superpages.
+After save/restore or migration this mapping is lost, everything is
+allocated in single pages. This causes a performance degradition after
+migration.
+
+Add neccessary code to preallocate a superpage for the chunk of pfns
+that is received. In case a pfn was not populated on the sending side it
+must be freed on the receiving side to avoid over-allocation.
+
+The existing code for x86_pv is moved unmodified into its own file.
+Index: xen-4.13.1-testing/tools/libxc/xc_dom_x86.c
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_dom_x86.c
++++ xen-4.13.1-testing/tools/libxc/xc_dom_x86.c
+@@ -45,11 +45,6 @@
+
+ #define SUPERPAGE_BATCH_SIZE 512
+
+-#define SUPERPAGE_2MB_SHIFT 9
+-#define SUPERPAGE_2MB_NR_PFNS (1UL << SUPERPAGE_2MB_SHIFT)
+-#define SUPERPAGE_1GB_SHIFT 18
+-#define SUPERPAGE_1GB_NR_PFNS (1UL << SUPERPAGE_1GB_SHIFT)
+-
+ #define X86_CR0_PE 0x01
+ #define X86_CR0_ET 0x10
+
+Index: xen-4.13.1-testing/tools/libxc/xc_private.h
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_private.h
++++ xen-4.13.1-testing/tools/libxc/xc_private.h
+@@ -71,6 +71,11 @@ struct iovec {
+ #define DECLARE_FLASK_OP struct xen_flask_op op
+ #define DECLARE_PLATFORM_OP struct xen_platform_op platform_op
+
++#define SUPERPAGE_2MB_SHIFT 9
++#define SUPERPAGE_2MB_NR_PFNS (1UL << SUPERPAGE_2MB_SHIFT)
++#define SUPERPAGE_1GB_SHIFT 18
++#define SUPERPAGE_1GB_NR_PFNS (1UL << SUPERPAGE_1GB_SHIFT)
++
+ #undef PAGE_SHIFT
+ #undef PAGE_SIZE
+ #undef PAGE_MASK
+Index: xen-4.13.1-testing/tools/libxc/xc_sr_common.c
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_sr_common.c
++++ xen-4.13.1-testing/tools/libxc/xc_sr_common.c
+@@ -156,6 +156,47 @@ static void __attribute__((unused)) buil
+ }
+
+ /*
++ * Expand the tracking structures as needed.
++ * To avoid realloc()ing too excessively, the size increased to the nearest power
++ * of two large enough to contain the required number of bits.
++ */
++bool _xc_sr_bitmap_resize(struct xc_sr_bitmap *bm, unsigned long bits)
++{
++ if (bits > bm->bits)
++ {
++ size_t new_max;
++ size_t old_sz, new_sz;
++ void *p;
++
++ /* Round up to the nearest power of two larger than bit, less 1. */
++ new_max = bits;
++ new_max |= new_max >> 1;
++ new_max |= new_max >> 2;
++ new_max |= new_max >> 4;
++ new_max |= new_max >> 8;
++ new_max |= new_max >> 16;
++#ifdef __x86_64__
++ new_max |= new_max >> 32;
++#endif
++
++ old_sz = bitmap_size(bm->bits + 1);
++ new_sz = bitmap_size(new_max + 1);
++ p = realloc(bm->p, new_sz);
++ if (!p)
++ return false;
++
++ if (bm->p)
++ memset(p + old_sz, 0, new_sz - old_sz);
++ else
++ memset(p, 0, new_sz);
++
++ bm->p = p;
++ bm->bits = new_max;
++ }
++ return true;
++}
++
++/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+Index: xen-4.13.1-testing/tools/libxc/xc_sr_common.h
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_sr_common.h
++++ xen-4.13.1-testing/tools/libxc/xc_sr_common.h
+@@ -140,6 +140,16 @@ struct xc_sr_restore_ops
+ int (*setup)(struct xc_sr_context *ctx);
+
+ /**
++ * Populate PFNs
++ *
++ * Given a set of pfns, obtain memory from Xen to fill the physmap for the
++ * unpopulated subset.
++ */
++ int (*populate_pfns)(struct xc_sr_context *ctx, unsigned count,
++ const xen_pfn_t *original_pfns, const uint32_t *types);
++
++
++ /**
+ * Process an individual record from the stream. The caller shall take
+ * care of processing common records (e.g. END, PAGE_DATA).
+ *
+@@ -172,6 +182,12 @@ struct xc_sr_x86_pv_restore_vcpu
+ size_t basicsz, extdsz, xsavesz, msrsz;
+ };
+
++struct xc_sr_bitmap
++{
++ void *p;
++ unsigned long bits;
++};
++
+ struct xc_sr_context
+ {
+ xc_interface *xch;
+@@ -216,6 +232,8 @@ struct xc_sr_context
+
+ int send_back_fd;
+ unsigned long p2m_size;
++ unsigned long max_pages;
++ unsigned long tot_pages;
+ xc_hypercall_buffer_t dirty_bitmap_hbuf;
+
+ /* From Image Header. */
+@@ -253,8 +271,7 @@ struct xc_sr_context
+ uint32_t xenstore_domid, console_domid;
+
+ /* Bitmap of currently populated PFNs during restore. */
+- unsigned long *populated_pfns;
+- xen_pfn_t max_populated_pfn;
++ struct xc_sr_bitmap populated_pfns;
+
+ /* Sender has invoked verify mode on the stream. */
+ bool verify;
+@@ -329,6 +346,12 @@ struct xc_sr_context
+ /* HVM context blob. */
+ void *context;
+ size_t contextsz;
++
++ /* Bitmap of currently allocated PFNs during restore. */
++ struct xc_sr_bitmap attempted_1g;
++ struct xc_sr_bitmap attempted_2m;
++ struct xc_sr_bitmap allocated_pfns;
++ xen_pfn_t idx1G_prev, idx2M_prev;
+ } restore;
+ };
+ } x86_hvm;
+@@ -341,6 +364,69 @@ extern struct xc_sr_save_ops save_ops_x8
+ extern struct xc_sr_restore_ops restore_ops_x86_pv;
+ extern struct xc_sr_restore_ops restore_ops_x86_hvm;
+
++extern bool _xc_sr_bitmap_resize(struct xc_sr_bitmap *bm, unsigned long bits);
++
++static inline bool xc_sr_bitmap_resize(struct xc_sr_bitmap *bm, unsigned long bits)
++{
++ if (bits > bm->bits)
++ return _xc_sr_bitmap_resize(bm, bits);
++ return true;
++}
++
++static inline void xc_sr_bitmap_free(struct xc_sr_bitmap *bm)
++{
++ free(bm->p);
++ bm->p = NULL;
++}
++
++static inline bool xc_sr_set_bit(unsigned long bit, struct xc_sr_bitmap *bm)
++{
++ if (!xc_sr_bitmap_resize(bm, bit))
++ return false;
++
++ set_bit(bit, bm->p);
++ return true;
++}
++
++static inline bool xc_sr_test_bit(unsigned long bit, struct xc_sr_bitmap *bm)
++{
++ if (bit > bm->bits)
++ return false;
++ return !!test_bit(bit, bm->p);
++}
++
++static inline bool xc_sr_test_and_clear_bit(unsigned long bit, struct xc_sr_bitmap *bm)
++{
++ if (bit > bm->bits)
++ return false;
++ return !!test_and_clear_bit(bit, bm->p);
++}
++
++static inline bool xc_sr_test_and_set_bit(unsigned long bit, struct xc_sr_bitmap *bm)
++{
++ if (bit > bm->bits)
++ return false;
++ return !!test_and_set_bit(bit, bm->p);
++}
++
++static inline bool pfn_is_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
++{
++ return xc_sr_test_bit(pfn, &ctx->restore.populated_pfns);
++}
++
++static inline int pfn_set_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
++{
++ xc_interface *xch = ctx->xch;
++
++ if ( !xc_sr_set_bit(pfn, &ctx->restore.populated_pfns) )
++ {
++ ERROR("Failed to realloc populated_pfns bitmap");
++ errno = ENOMEM;
++ return -1;
++ }
++ return 0;
++}
++
+ struct xc_sr_record
+ {
+ uint32_t type;
+@@ -389,14 +475,6 @@ static inline int write_record(struct xc
+ */
+ int read_record(struct xc_sr_context *ctx, int fd, struct xc_sr_record *rec);
+
+-/*
+- * This would ideally be private in restore.c, but is needed by
+- * x86_pv_localise_page() if we receive pagetables frames ahead of the
+- * contents of the frames they point at.
+- */
+-int populate_pfns(struct xc_sr_context *ctx, unsigned count,
+- const xen_pfn_t *original_pfns, const uint32_t *types);
+-
+ #endif
+ /*
+ * Local variables:
+Index: xen-4.13.1-testing/tools/libxc/xc_sr_restore.c
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_sr_restore.c
++++ xen-4.13.1-testing/tools/libxc/xc_sr_restore.c
+@@ -69,132 +69,6 @@ static int read_headers(struct xc_sr_con
+ }
+
+ /*
+- * Is a pfn populated?
+- */
+-static bool pfn_is_populated(const struct xc_sr_context *ctx, xen_pfn_t pfn)
+-{
+- if ( pfn > ctx->restore.max_populated_pfn )
+- return false;
+- return test_bit(pfn, ctx->restore.populated_pfns);
+-}
+-
+-/*
+- * Set a pfn as populated, expanding the tracking structures if needed. To
+- * avoid realloc()ing too excessively, the size increased to the nearest power
+- * of two large enough to contain the required pfn.
+- */
+-static int pfn_set_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
+-{
+- xc_interface *xch = ctx->xch;
+-
+- if ( pfn > ctx->restore.max_populated_pfn )
+- {
+- xen_pfn_t new_max;
+- size_t old_sz, new_sz;
+- unsigned long *p;
+-
+- /* Round up to the nearest power of two larger than pfn, less 1. */
+- new_max = pfn;
+- new_max |= new_max >> 1;
+- new_max |= new_max >> 2;
+- new_max |= new_max >> 4;
+- new_max |= new_max >> 8;
+- new_max |= new_max >> 16;
+-#ifdef __x86_64__
+- new_max |= new_max >> 32;
+-#endif
+-
+- old_sz = bitmap_size(ctx->restore.max_populated_pfn + 1);
+- new_sz = bitmap_size(new_max + 1);
+- p = realloc(ctx->restore.populated_pfns, new_sz);
+- if ( !p )
+- {
+- ERROR("Failed to realloc populated bitmap");
+- errno = ENOMEM;
+- return -1;
+- }
+-
+- memset((uint8_t *)p + old_sz, 0x00, new_sz - old_sz);
+-
+- ctx->restore.populated_pfns = p;
+- ctx->restore.max_populated_pfn = new_max;
+- }
+-
+- assert(!test_bit(pfn, ctx->restore.populated_pfns));
+- set_bit(pfn, ctx->restore.populated_pfns);
+-
+- return 0;
+-}
+-
+-/*
+- * Given a set of pfns, obtain memory from Xen to fill the physmap for the
+- * unpopulated subset. If types is NULL, no page type checking is performed
+- * and all unpopulated pfns are populated.
+- */
+-int populate_pfns(struct xc_sr_context *ctx, unsigned count,
+- const xen_pfn_t *original_pfns, const uint32_t *types)
+-{
+- xc_interface *xch = ctx->xch;
+- xen_pfn_t *mfns = malloc(count * sizeof(*mfns)),
+- *pfns = malloc(count * sizeof(*pfns));
+- unsigned i, nr_pfns = 0;
+- int rc = -1;
+-
+- if ( !mfns || !pfns )
+- {
+- ERROR("Failed to allocate %zu bytes for populating the physmap",
+- 2 * count * sizeof(*mfns));
+- goto err;
+- }
+-
+- for ( i = 0; i < count; ++i )
+- {
+- if ( (!types || (types &&
+- (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
+- types[i] != XEN_DOMCTL_PFINFO_BROKEN))) &&
+- !pfn_is_populated(ctx, original_pfns[i]) )
+- {
+- rc = pfn_set_populated(ctx, original_pfns[i]);
+- if ( rc )
+- goto err;
+- pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i];
+- ++nr_pfns;
+- }
+- }
+-
+- if ( nr_pfns )
+- {
+- rc = xc_domain_populate_physmap_exact(
+- xch, ctx->domid, nr_pfns, 0, 0, mfns);
+- if ( rc )
+- {
+- PERROR("Failed to populate physmap");
+- goto err;
+- }
+-
+- for ( i = 0; i < nr_pfns; ++i )
+- {
+- if ( mfns[i] == INVALID_MFN )
+- {
+- ERROR("Populate physmap failed for pfn %u", i);
+- rc = -1;
+- goto err;
+- }
+-
+- ctx->restore.ops.set_gfn(ctx, pfns[i], mfns[i]);
+- }
+- }
+-
+- rc = 0;
+-
+- err:
+- free(pfns);
+- free(mfns);
+-
+- return rc;
+-}
+-
+-/*
+ * Given a list of pfns, their types, and a block of page data from the
+ * stream, populate and record their types, map the relevant subset and copy
+ * the data into the guest.
+@@ -219,7 +93,7 @@ static int process_page_data(struct xc_s
+ goto err;
+ }
+
+- rc = populate_pfns(ctx, count, pfns, types);
++ rc = ctx->restore.ops.populate_pfns(ctx, count, pfns, types);
+ if ( rc )
+ {
+ ERROR("Failed to populate pfns for batch of %u pages", count);
+@@ -684,10 +558,8 @@ static int setup(struct xc_sr_context *c
+ if ( rc )
+ goto err;
+
+- ctx->restore.max_populated_pfn = (32 * 1024 / 4) - 1;
+- ctx->restore.populated_pfns = bitmap_alloc(
+- ctx->restore.max_populated_pfn + 1);
+- if ( !ctx->restore.populated_pfns )
++ rc = !xc_sr_bitmap_resize(&ctx->restore.populated_pfns, 32 * 1024 / 4);
++ if ( rc )
+ {
+ ERROR("Unable to allocate memory for populated_pfns bitmap");
+ rc = -1;
+@@ -722,7 +594,7 @@ static void cleanup(struct xc_sr_context
+ xc_hypercall_buffer_free_pages(xch, dirty_bitmap,
+ NRPAGES(bitmap_size(ctx->restore.p2m_size)));
+ free(ctx->restore.buffered_records);
+- free(ctx->restore.populated_pfns);
++ xc_sr_bitmap_free(&ctx->restore.populated_pfns);
+ if ( ctx->restore.ops.cleanup(ctx) )
+ PERROR("Failed to clean up");
+ }
+@@ -886,7 +758,12 @@ int xc_domain_restore(xc_interface *xch,
+ return -1;
+ }
+
++ /* See xc_domain_getinfo */
++ ctx.restore.max_pages = ctx.dominfo.max_memkb >> (PAGE_SHIFT-10);
++ ctx.restore.tot_pages = ctx.dominfo.nr_pages;
+ ctx.restore.p2m_size = nr_pfns;
++ DPRINTF("dom %u p2m_size %lx max_pages %lx",
++ ctx.domid, ctx.restore.p2m_size, ctx.restore.max_pages);
+
+ if ( ctx.dominfo.hvm )
+ {
+Index: xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_hvm.c
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_sr_restore_x86_hvm.c
++++ xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_hvm.c
+@@ -135,6 +135,8 @@ static int x86_hvm_localise_page(struct
+ static int x86_hvm_setup(struct xc_sr_context *ctx)
+ {
+ xc_interface *xch = ctx->xch;
++ struct xc_sr_bitmap *bm;
++ unsigned long bits;
+
+ if ( ctx->restore.guest_type != DHDR_TYPE_X86_HVM )
+ {
+@@ -158,7 +160,30 @@ static int x86_hvm_setup(struct xc_sr_co
+ }
+ #endif
+
++ bm = &ctx->x86_hvm.restore.attempted_1g;
++ bits = (ctx->restore.p2m_size >> SUPERPAGE_1GB_SHIFT) + 1;
++ if ( xc_sr_bitmap_resize(bm, bits) == false )
++ goto out;
++
++ bm = &ctx->x86_hvm.restore.attempted_2m;
++ bits = (ctx->restore.p2m_size >> SUPERPAGE_2MB_SHIFT) + 1;
++ if ( xc_sr_bitmap_resize(bm, bits) == false )
++ goto out;
++
++ bm = &ctx->x86_hvm.restore.allocated_pfns;
++ bits = ctx->restore.p2m_size + 1;
++ if ( xc_sr_bitmap_resize(bm, bits) == false )
++ goto out;
++
++ /* No superpage in 1st 2MB due to VGA hole */
++ xc_sr_set_bit(0, &ctx->x86_hvm.restore.attempted_1g);
++ xc_sr_set_bit(0, &ctx->x86_hvm.restore.attempted_2m);
++
+ return 0;
++
++out:
++ ERROR("Unable to allocate memory for pfn bitmaps");
++ return -1;
+ }
+
+ /*
+@@ -233,10 +258,325 @@ static int x86_hvm_stream_complete(struc
+ static int x86_hvm_cleanup(struct xc_sr_context *ctx)
+ {
+ free(ctx->x86_hvm.restore.context);
++ xc_sr_bitmap_free(&ctx->x86_hvm.restore.attempted_1g);
++ xc_sr_bitmap_free(&ctx->x86_hvm.restore.attempted_2m);
++ xc_sr_bitmap_free(&ctx->x86_hvm.restore.allocated_pfns);
++
++ return 0;
++}
++
++/*
++ * Set a pfn as allocated, expanding the tracking structures if needed.
++ */
++static int pfn_set_allocated(struct xc_sr_context *ctx, xen_pfn_t pfn)
++{
++ xc_interface *xch = ctx->xch;
+
++ if ( !xc_sr_set_bit(pfn, &ctx->x86_hvm.restore.allocated_pfns) )
++ {
++ ERROR("Failed to realloc allocated_pfns bitmap");
++ errno = ENOMEM;
++ return -1;
++ }
+ return 0;
+ }
+
++struct x86_hvm_sp {
++ xen_pfn_t pfn;
++ xen_pfn_t base_pfn;
++ unsigned long index;
++ unsigned long count;
++};
++
++/*
++ * Try to allocate a 1GB page for this pfn, but avoid Over-allocation.
++ * If this succeeds, mark the range of 2MB pages as busy.
++ */
++static bool x86_hvm_alloc_1g(struct xc_sr_context *ctx, struct x86_hvm_sp *sp)
++{
++ xc_interface *xch = ctx->xch;
++ struct xc_sr_bitmap *bm;
++ unsigned int order, shift;
++ int i, done;
++ xen_pfn_t extent;
++
++ bm = &ctx->x86_hvm.restore.attempted_1g;
++
++ /* Only one attempt to avoid overlapping allocation */
++ if ( xc_sr_test_and_set_bit(sp->index, bm) )
++ return false;
++
++ order = SUPERPAGE_1GB_SHIFT;
++ sp->count = 1ULL << order;
++
++ /* Allocate only if there is room for another superpage */
++ if ( ctx->restore.tot_pages + sp->count > ctx->restore.max_pages )
++ return false;
++
++ extent = sp->base_pfn = (sp->pfn >> order) << order;
++ done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extent);
++ if ( done < 0 ) {
++ PERROR("populate_physmap failed.");
++ return false;
++ }
++ if ( done == 0 )
++ return false;
++
++ DPRINTF("1G base_pfn %" PRI_xen_pfn "\n", sp->base_pfn);
++
++ /* Mark all 2MB pages as done to avoid overlapping allocation */
++ bm = &ctx->x86_hvm.restore.attempted_2m;
++ shift = SUPERPAGE_1GB_SHIFT - SUPERPAGE_2MB_SHIFT;
++ for ( i = 0; i < (sp->count >> shift); i++ )
++ xc_sr_set_bit((sp->base_pfn >> SUPERPAGE_2MB_SHIFT) + i, bm);
++
++ return true;
++}
++
++/* Allocate a 2MB page if x86_hvm_alloc_1g failed, avoid Over-allocation. */
++static bool x86_hvm_alloc_2m(struct xc_sr_context *ctx, struct x86_hvm_sp *sp)
++{
++ xc_interface *xch = ctx->xch;
++ struct xc_sr_bitmap *bm;
++ unsigned int order;
++ int done;
++ xen_pfn_t extent;
++
++ bm = &ctx->x86_hvm.restore.attempted_2m;
++
++ /* Only one attempt to avoid overlapping allocation */
++ if ( xc_sr_test_and_set_bit(sp->index, bm) )
++ return false;
++
++ order = SUPERPAGE_2MB_SHIFT;
++ sp->count = 1ULL << order;
++
++ /* Allocate only if there is room for another superpage */
++ if ( ctx->restore.tot_pages + sp->count > ctx->restore.max_pages )
++ return false;
++
++ extent = sp->base_pfn = (sp->pfn >> order) << order;
++ done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extent);
++ if ( done < 0 ) {
++ PERROR("populate_physmap failed.");
++ return false;
++ }
++ if ( done == 0 )
++ return false;
++
++ DPRINTF("2M base_pfn %" PRI_xen_pfn "\n", sp->base_pfn);
++ return true;
++}
++
++/* Allocate a single page if x86_hvm_alloc_2m failed. */
++static bool x86_hvm_alloc_4k(struct xc_sr_context *ctx, struct x86_hvm_sp *sp)
++{
++ xc_interface *xch = ctx->xch;
++ unsigned int order;
++ int done;
++ xen_pfn_t extent;
++
++ order = 0;
++ sp->count = 1ULL << order;
++
++ /* Allocate only if there is room for another page */
++ if ( ctx->restore.tot_pages + sp->count > ctx->restore.max_pages )
++ return false;
++
++ extent = sp->base_pfn = (sp->pfn >> order) << order;
++ done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extent);
++ if ( done < 0 ) {
++ PERROR("populate_physmap failed.");
++ return false;
++ }
++ if ( done == 0 )
++ return false;
++
++ DPRINTF("4K base_pfn %" PRI_xen_pfn "\n", sp->base_pfn);
++ return true;
++}
++/*
++ * Attempt to allocate a superpage where the pfn resides.
++ */
++static int x86_hvm_allocate_pfn(struct xc_sr_context *ctx, xen_pfn_t pfn)
++{
++ xc_interface *xch = ctx->xch;
++ bool success;
++ int rc = -1;
++ unsigned long idx_1g, idx_2m;
++ struct x86_hvm_sp sp = {
++ .pfn = pfn
++ };
++
++ if ( xc_sr_test_bit(pfn, &ctx->x86_hvm.restore.allocated_pfns) )
++ return 0;
++
++ idx_1g = pfn >> SUPERPAGE_1GB_SHIFT;
++ idx_2m = pfn >> SUPERPAGE_2MB_SHIFT;
++ if ( !xc_sr_bitmap_resize(&ctx->x86_hvm.restore.attempted_1g, idx_1g) )
++ {
++ PERROR("Failed to realloc attempted_1g");
++ return -1;
++ }
++ if ( !xc_sr_bitmap_resize(&ctx->x86_hvm.restore.attempted_2m, idx_2m) )
++ {
++ PERROR("Failed to realloc attempted_2m");
++ return -1;
++ }
++
++ sp.index = idx_1g;
++ success = x86_hvm_alloc_1g(ctx, &sp);
++
++ if ( success == false ) {
++ sp.index = idx_2m;
++ success = x86_hvm_alloc_2m(ctx, &sp);
++ }
++
++ if ( success == false ) {
++ sp.index = 0;
++ success = x86_hvm_alloc_4k(ctx, &sp);
++ }
++
++ if ( success == true ) {
++ do {
++ sp.count--;
++ ctx->restore.tot_pages++;
++ rc = pfn_set_allocated(ctx, sp.base_pfn + sp.count);
++ if ( rc )
++ break;
++ } while ( sp.count );
++ }
++ return rc;
++}
++
++static bool x86_hvm_punch_hole(struct xc_sr_context *ctx, xen_pfn_t max_pfn)
++{
++ xc_interface *xch = ctx->xch;
++ struct xc_sr_bitmap *bm;
++ xen_pfn_t _pfn, pfn, min_pfn;
++ uint32_t domid, freed = 0, order;
++ int rc = -1;
++
++ /*
++ * Scan the entire superpage because several batches will fit into
++ * a superpage, and it is unknown which pfn triggered the allocation.
++ */
++ order = SUPERPAGE_1GB_SHIFT;
++ pfn = min_pfn = (max_pfn >> order) << order;
++
++ while ( pfn <= max_pfn )
++ {
++ bm = &ctx->x86_hvm.restore.allocated_pfns;
++ if ( !xc_sr_bitmap_resize(bm, pfn) )
++ {
++ PERROR("Failed to realloc allocated_pfns %" PRI_xen_pfn, pfn);
++ return false;
++ }
++ if ( !pfn_is_populated(ctx, pfn) &&
++ xc_sr_test_and_clear_bit(pfn, bm) ) {
++ domid = ctx->domid;
++ _pfn = pfn;
++ rc = xc_domain_decrease_reservation_exact(xch, domid, 1, 0, &_pfn);
++ if ( rc )
++ {
++ PERROR("Failed to release pfn %" PRI_xen_pfn, pfn);
++ return false;
++ }
++ ctx->restore.tot_pages--;
++ freed++;
++ }
++ pfn++;
++ }
++ if ( freed )
++ DPRINTF("freed %u between %" PRI_xen_pfn " %" PRI_xen_pfn "\n",
++ freed, min_pfn, max_pfn);
++ return true;
++}
++
++/*
++ * Try to allocate superpages.
++ * This works without memory map only if the pfns arrive in incremental order.
++ */
++static int x86_hvm_populate_pfns(struct xc_sr_context *ctx, unsigned count,
++ const xen_pfn_t *original_pfns,
++ const uint32_t *types)
++{
++ xc_interface *xch = ctx->xch;
++ xen_pfn_t pfn, min_pfn = original_pfns[0], max_pfn = original_pfns[0];
++ xen_pfn_t idx1G, idx2M;
++ unsigned i, order;
++ int rc = -1;
++
++ /* Loop once over the array to show statistics */
++ for ( i = 0; i < count; ++i )
++ {
++ if ( original_pfns[i] < min_pfn )
++ min_pfn = original_pfns[i];
++ if ( original_pfns[i] > max_pfn )
++ max_pfn = original_pfns[i];
++ }
++ DPRINTF("batch of %u pfns between %" PRI_xen_pfn " %" PRI_xen_pfn "\n",
++ count, min_pfn, max_pfn);
++
++ for ( i = 0; i < count; ++i )
++ {
++ pfn = original_pfns[i];
++ idx1G = pfn >> SUPERPAGE_1GB_SHIFT;
++ idx2M = pfn >> SUPERPAGE_2MB_SHIFT;
++
++ /*
++ * If this pfn is in another 2MB superpage it is required to punch holes
++ * to release memory, starting from the 1GB boundary up to the highest
++ * pfn within the previous 2MB superpage.
++ */
++ if ( ctx->x86_hvm.restore.idx1G_prev == idx1G &&
++ ctx->x86_hvm.restore.idx2M_prev == idx2M )
++ {
++ /* Same 2MB superpage, nothing to do */
++ ;
++ } else {
++ /*
++ * If this next pfn is within another 1GB or 2MB superpage it is
++ * required to scan the entire previous superpage because there
++ * might be holes between the last pfn and the end of the superpage.
++ */
++ if ( ctx->x86_hvm.restore.idx1G_prev != idx1G )
++ {
++ order = SUPERPAGE_1GB_SHIFT;
++ max_pfn = ((ctx->x86_hvm.restore.idx1G_prev + 1) << order) - 1;
++ }
++ else
++ {
++ order = SUPERPAGE_2MB_SHIFT;
++ max_pfn = ((ctx->x86_hvm.restore.idx2M_prev + 1) << order) - 1;
++ }
++
++ if ( x86_hvm_punch_hole(ctx, max_pfn) == false )
++ goto err;
++ }
++
++ if ( (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
++ types[i] != XEN_DOMCTL_PFINFO_BROKEN) &&
++ !pfn_is_populated(ctx, pfn) )
++ {
++ rc = x86_hvm_allocate_pfn(ctx, pfn);
++ if ( rc )
++ goto err;
++ rc = pfn_set_populated(ctx, pfn);
++ if ( rc )
++ goto err;
++ }
++ ctx->x86_hvm.restore.idx1G_prev = idx1G;
++ ctx->x86_hvm.restore.idx2M_prev = idx2M;
++ }
++
++ rc = 0;
++
++ err:
++ return rc;
++}
++
++
+ struct xc_sr_restore_ops restore_ops_x86_hvm =
+ {
+ .pfn_is_valid = x86_hvm_pfn_is_valid,
+@@ -245,6 +585,7 @@ struct xc_sr_restore_ops restore_ops_x86
+ .set_page_type = x86_hvm_set_page_type,
+ .localise_page = x86_hvm_localise_page,
+ .setup = x86_hvm_setup,
++ .populate_pfns = x86_hvm_populate_pfns,
+ .process_record = x86_hvm_process_record,
+ .stream_complete = x86_hvm_stream_complete,
+ .cleanup = x86_hvm_cleanup,
+Index: xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_pv.c
+===================================================================
+--- xen-4.13.1-testing.orig/tools/libxc/xc_sr_restore_x86_pv.c
++++ xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_pv.c
+@@ -960,6 +960,75 @@ static void x86_pv_set_gfn(struct xc_sr_
+ }
+
+ /*
++ * Given a set of pfns, obtain memory from Xen to fill the physmap for the
++ * unpopulated subset. If types is NULL, no page type checking is performed
++ * and all unpopulated pfns are populated.
++ */
++static int x86_pv_populate_pfns(struct xc_sr_context *ctx, unsigned count,
++ const xen_pfn_t *original_pfns,
++ const uint32_t *types)
++{
++ xc_interface *xch = ctx->xch;
++ xen_pfn_t *mfns = malloc(count * sizeof(*mfns)),
++ *pfns = malloc(count * sizeof(*pfns));
++ unsigned i, nr_pfns = 0;
++ int rc = -1;
++
++ if ( !mfns || !pfns )
++ {
++ ERROR("Failed to allocate %zu bytes for populating the physmap",
++ 2 * count * sizeof(*mfns));
++ goto err;
++ }
++
++ for ( i = 0; i < count; ++i )
++ {
++ if ( (!types || (types &&
++ (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
++ types[i] != XEN_DOMCTL_PFINFO_BROKEN))) &&
++ !pfn_is_populated(ctx, original_pfns[i]) )
++ {
++ rc = pfn_set_populated(ctx, original_pfns[i]);
++ if ( rc )
++ goto err;
++ pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i];
++ ++nr_pfns;
++ }
++ }
++
++ if ( nr_pfns )
++ {
++ rc = xc_domain_populate_physmap_exact(
++ xch, ctx->domid, nr_pfns, 0, 0, mfns);
++ if ( rc )
++ {
++ PERROR("Failed to populate physmap");
++ goto err;
++ }
++
++ for ( i = 0; i < nr_pfns; ++i )
++ {
++ if ( mfns[i] == INVALID_MFN )
++ {
++ ERROR("Populate physmap failed for pfn %u", i);
++ rc = -1;
++ goto err;
++ }
++
++ ctx->restore.ops.set_gfn(ctx, pfns[i], mfns[i]);
++ }
++ }
++
++ rc = 0;
++
++ err:
++ free(pfns);
++ free(mfns);
++
++ return rc;
++}
++
++/*
+ * restore_ops function. Convert pfns back to mfns in pagetables. Possibly
+ * needs to populate new frames if a PTE is found referring to a frame which
+ * hasn't yet been seen from PAGE_DATA records.
+@@ -1003,7 +1072,7 @@ static int x86_pv_localise_page(struct x
+ }
+ }
+
+- if ( to_populate && populate_pfns(ctx, to_populate, pfns, NULL) )
++ if ( to_populate && x86_pv_populate_pfns(ctx, to_populate, pfns, NULL) )
+ return -1;
+
+ for ( i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); ++i )
+@@ -1183,6 +1252,7 @@ struct xc_sr_restore_ops restore_ops_x86
+ .set_gfn = x86_pv_set_gfn,
+ .localise_page = x86_pv_localise_page,
+ .setup = x86_pv_setup,
++ .populate_pfns = x86_pv_populate_pfns,
+ .process_record = x86_pv_process_record,
+ .stream_complete = x86_pv_stream_complete,
+ .cleanup = x86_pv_cleanup,