* [PATCH v1] tools/libxc: use superpages during restore of HVM guest
@ 2017-08-02 13:45 Olaf Hering
2017-08-04 5:43 ` Olaf Hering
2017-08-04 12:44 ` Wei Liu
0 siblings, 2 replies; 5+ messages in thread
From: Olaf Hering @ 2017-08-02 13:45 UTC (permalink / raw)
To: Ian Jackson, Wei Liu, xen-devel; +Cc: Olaf Hering
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.
Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
based on RELEASE-4.9.0
tools/libxc/xc_sr_common.c | 41 ++++++++
tools/libxc/xc_sr_common.h | 79 +++++++++++++++-
tools/libxc/xc_sr_restore.c | 135 +-------------------------
tools/libxc/xc_sr_restore_x86_hvm.c | 183 ++++++++++++++++++++++++++++++++++++
tools/libxc/xc_sr_restore_x86_pv.c | 72 +++++++++++++-
5 files changed, 376 insertions(+), 134 deletions(-)
diff --git a/tools/libxc/xc_sr_common.c b/tools/libxc/xc_sr_common.c
index 48fa676f4e..9b68a064eb 100644
--- a/tools/libxc/xc_sr_common.c
+++ b/tools/libxc/xc_sr_common.c
@@ -156,6 +156,47 @@ static void __attribute__((unused)) build_assertions(void)
}
/*
+ * 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"
diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
index a83f22af4e..ad1a2e6e02 100644
--- a/tools/libxc/xc_sr_common.h
+++ b/tools/libxc/xc_sr_common.h
@@ -140,6 +140,13 @@ struct xc_sr_restore_ops
int (*setup)(struct xc_sr_context *ctx);
/**
+ * Populate PFNs
+ *
+ */
+ 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 +179,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;
@@ -255,8 +268,7 @@ struct xc_sr_context
domid_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;
@@ -331,6 +343,11 @@ 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;
} restore;
};
} x86_hvm;
@@ -343,6 +360,64 @@ extern struct xc_sr_save_ops save_ops_x86_hvm;
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);
+}
+
+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 int xc_sr_test_and_clear_bit(unsigned long bit, struct xc_sr_bitmap *bm)
+{
+ return test_and_clear_bit(bit, bm->p);
+}
+
+static inline int xc_sr_test_and_set_bit(unsigned long bit, struct xc_sr_bitmap *bm)
+{
+ 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;
diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c
index 3549f0a1ae..9888acb05f 100644
--- a/tools/libxc/xc_sr_restore.c
+++ b/tools/libxc/xc_sr_restore.c
@@ -68,131 +68,6 @@ static int read_headers(struct xc_sr_context *ctx)
return 0;
}
-/*
- * 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
@@ -219,7 +94,7 @@ static int process_page_data(struct xc_sr_context *ctx, unsigned count,
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 +559,8 @@ static int setup(struct xc_sr_context *ctx)
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 +595,7 @@ static void cleanup(struct xc_sr_context *ctx)
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");
}
diff --git a/tools/libxc/xc_sr_restore_x86_hvm.c b/tools/libxc/xc_sr_restore_x86_hvm.c
index 1dca85354a..c32a318bc4 100644
--- a/tools/libxc/xc_sr_restore_x86_hvm.c
+++ b/tools/libxc/xc_sr_restore_x86_hvm.c
@@ -3,6 +3,10 @@
#include "xc_sr_common_x86.h"
+#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)
/*
* Process an HVM_CONTEXT record from the stream.
*/
@@ -135,6 +139,8 @@ static int x86_hvm_localise_page(struct xc_sr_context *ctx,
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 )
{
@@ -149,7 +155,30 @@ static int x86_hvm_setup(struct xc_sr_context *ctx)
return -1;
}
+ 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;
}
/*
@@ -224,10 +253,163 @@ static int x86_hvm_stream_complete(struct xc_sr_context *ctx)
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;
+}
+
+/*
+ * 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 = false;
+ int rc = -1, done;
+ unsigned int order;
+ unsigned long i;
+ unsigned long stat_1g = 0, stat_2m = 0, stat_4k = 0;
+ unsigned long idx_1g, idx_2m;
+ unsigned long count;
+ xen_pfn_t base_pfn = 0, extnt;
+
+ 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;
+ }
+ DPRINTF("idx_1g %lu idx_2m %lu\n", idx_1g, idx_2m);
+ if (!xc_sr_test_and_set_bit(idx_1g, &ctx->x86_hvm.restore.attempted_1g)) {
+ order = SUPERPAGE_1GB_SHIFT;
+ count = 1UL << order;
+ base_pfn = (pfn >> order) << order;
+ extnt = base_pfn;
+ done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extnt);
+ DPRINTF("1G base_pfn %" PRI_xen_pfn " done %d\n", base_pfn, done);
+ if (done > 0) {
+ struct xc_sr_bitmap *bm = &ctx->x86_hvm.restore.attempted_2m;
+ success = true;
+ stat_1g = done;
+ for (i = 0; i < (count >> SUPERPAGE_2MB_SHIFT); i++)
+ xc_sr_set_bit((base_pfn >> SUPERPAGE_2MB_SHIFT) + i, bm);
+ }
+ }
+
+ if (!xc_sr_test_and_set_bit(idx_2m, &ctx->x86_hvm.restore.attempted_2m)) {
+ order = SUPERPAGE_2MB_SHIFT;
+ count = 1UL << order;
+ base_pfn = (pfn >> order) << order;
+ extnt = base_pfn;
+ done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extnt);
+ DPRINTF("2M base_pfn %" PRI_xen_pfn " done %d\n", base_pfn, done);
+ if (done > 0) {
+ success = true;
+ stat_2m = done;
+ }
+ }
+ if (success == false) {
+ count = 1;
+ extnt = base_pfn = pfn;
+ done = xc_domain_populate_physmap(xch, ctx->domid, count, 0, 0, &extnt);
+ if (done > 0) {
+ success = true;
+ stat_4k = count;
+ }
+ }
+ DPRINTF("count %lu 1G %lu 2M %lu 4k %lu\n", count, stat_1g, stat_2m, stat_4k);
+ if (success == true) {
+ do {
+ count--;
+ rc = pfn_set_allocated(ctx, base_pfn + count);
+ if (rc)
+ break;
+ } while (count);
+ }
+ return rc;
+}
+
+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 min_pfn = original_pfns[0], max_pfn = original_pfns[0];
+ unsigned i;
+ int rc = -1;
+
+ 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];
+ if ( (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
+ types[i] != XEN_DOMCTL_PFINFO_BROKEN) &&
+ !pfn_is_populated(ctx, original_pfns[i]) )
+ {
+ rc = x86_hvm_allocate_pfn(ctx, original_pfns[i]);
+ if ( rc )
+ goto err;
+ rc = pfn_set_populated(ctx, original_pfns[i]);
+ if ( rc )
+ goto err;
+ }
+ }
+
+ while (min_pfn < max_pfn)
+ {
+ if (!xc_sr_bitmap_resize(&ctx->x86_hvm.restore.allocated_pfns, min_pfn))
+ {
+ PERROR("Failed to realloc allocated_pfns %" PRI_xen_pfn, min_pfn);
+ goto err;
+ }
+ if (!pfn_is_populated(ctx, min_pfn) && xc_sr_test_and_clear_bit(min_pfn, &ctx->x86_hvm.restore.allocated_pfns)) {
+ xen_pfn_t pfn = min_pfn;
+ rc = xc_domain_decrease_reservation_exact(xch, ctx->domid, 1, 0, &pfn);
+ if ( rc )
+ {
+ PERROR("Failed to release pfn %" PRI_xen_pfn, min_pfn);
+ goto err;
+ }
+ }
+ min_pfn++;
+ }
+
+ rc = 0;
+
+ err:
+ return rc;
+}
+
+
struct xc_sr_restore_ops restore_ops_x86_hvm =
{
.pfn_is_valid = x86_hvm_pfn_is_valid,
@@ -236,6 +418,7 @@ struct xc_sr_restore_ops restore_ops_x86_hvm =
.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,
diff --git a/tools/libxc/xc_sr_restore_x86_pv.c b/tools/libxc/xc_sr_restore_x86_pv.c
index 50e25c162c..87957559bc 100644
--- a/tools/libxc/xc_sr_restore_x86_pv.c
+++ b/tools/libxc/xc_sr_restore_x86_pv.c
@@ -937,6 +937,75 @@ static void x86_pv_set_gfn(struct xc_sr_context *ctx, xen_pfn_t pfn,
}
/*
+ * 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.
@@ -980,7 +1049,7 @@ static int x86_pv_localise_page(struct xc_sr_context *ctx,
}
}
- 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 )
@@ -1160,6 +1229,7 @@ struct xc_sr_restore_ops restore_ops_x86_pv =
.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,
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v1] tools/libxc: use superpages during restore of HVM guest
2017-08-02 13:45 [PATCH v1] tools/libxc: use superpages during restore of HVM guest Olaf Hering
@ 2017-08-04 5:43 ` Olaf Hering
2017-08-04 12:47 ` Wei Liu
2017-08-04 12:44 ` Wei Liu
1 sibling, 1 reply; 5+ messages in thread
From: Olaf Hering @ 2017-08-04 5:43 UTC (permalink / raw)
To: Ian Jackson, Wei Liu, xen-devel; +Cc: Andrew Cooper
[-- Attachment #1.1: Type: text/plain, Size: 1261 bytes --]
On Wed, Aug 02, Olaf Hering wrote:
> +++ b/tools/libxc/xc_sr_restore_x86_hvm.c
> +#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)
I think these can be moved to a header file. xc_dom_x86.c and
xc_sr_restore_x86_hvm.c use xc_dom.h.
> +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 min_pfn = original_pfns[0], max_pfn = original_pfns[0];
> + unsigned i;
> + int rc = -1;
> +
> + 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];
> + if ( (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
> + types[i] != XEN_DOMCTL_PFINFO_BROKEN) &&
> + !pfn_is_populated(ctx, original_pfns[i]) )
Are these types used at all for a HVM domU? Otherwise this condition can
be simplified to just check the populated state.
Olaf
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: Type: text/plain, Size: 127 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1] tools/libxc: use superpages during restore of HVM guest
2017-08-02 13:45 [PATCH v1] tools/libxc: use superpages during restore of HVM guest Olaf Hering
2017-08-04 5:43 ` Olaf Hering
@ 2017-08-04 12:44 ` Wei Liu
2017-08-04 12:49 ` Olaf Hering
1 sibling, 1 reply; 5+ messages in thread
From: Wei Liu @ 2017-08-04 12:44 UTC (permalink / raw)
To: Olaf Hering; +Cc: Wei Liu, Ian Jackson, xen-devel
On Wed, Aug 02, 2017 at 03:45:25PM +0200, Olaf Hering wrote:
> 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.
>
Can you split this patch into several:
1. code movement
2. refactoring / introduction of new hooks
3. implementing the new algorithm
Thanks
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1] tools/libxc: use superpages during restore of HVM guest
2017-08-04 5:43 ` Olaf Hering
@ 2017-08-04 12:47 ` Wei Liu
0 siblings, 0 replies; 5+ messages in thread
From: Wei Liu @ 2017-08-04 12:47 UTC (permalink / raw)
To: Olaf Hering; +Cc: Wei Liu, Andrew Cooper, Ian Jackson, xen-devel
On Fri, Aug 04, 2017 at 07:43:47AM +0200, Olaf Hering wrote:
> On Wed, Aug 02, Olaf Hering wrote:
>
> > +++ b/tools/libxc/xc_sr_restore_x86_hvm.c
>
> > +#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)
>
> I think these can be moved to a header file. xc_dom_x86.c and
> xc_sr_restore_x86_hvm.c use xc_dom.h.
>
> > +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 min_pfn = original_pfns[0], max_pfn = original_pfns[0];
> > + unsigned i;
> > + int rc = -1;
> > +
> > + 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];
> > + if ( (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
> > + types[i] != XEN_DOMCTL_PFINFO_BROKEN) &&
> > + !pfn_is_populated(ctx, original_pfns[i]) )
>
> Are these types used at all for a HVM domU? Otherwise this condition can
> be simplified to just check the populated state.
I *think* XTAB is PV only but BROKEN applies to both PV and HVM.
Maybe someone more familiar with the bit can chime in to provide more
information.
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1] tools/libxc: use superpages during restore of HVM guest
2017-08-04 12:44 ` Wei Liu
@ 2017-08-04 12:49 ` Olaf Hering
0 siblings, 0 replies; 5+ messages in thread
From: Olaf Hering @ 2017-08-04 12:49 UTC (permalink / raw)
To: Wei Liu; +Cc: Ian Jackson, xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 250 bytes --]
On Fri, Aug 04, Wei Liu wrote:
> Can you split this patch into several:
> 1. code movement
> 2. refactoring / introduction of new hooks
> 3. implementing the new algorithm
I tried that, it did not work well. But, I can try again if required.
Olaf
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: Type: text/plain, Size: 127 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-08-04 12:49 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-08-02 13:45 [PATCH v1] tools/libxc: use superpages during restore of HVM guest Olaf Hering
2017-08-04 5:43 ` Olaf Hering
2017-08-04 12:47 ` Wei Liu
2017-08-04 12:44 ` Wei Liu
2017-08-04 12:49 ` Olaf Hering
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.