File xen.sr-xg_sr_bitmap-populated_pfns.patch of Package xen
From: Olaf Hering <olaf@aepfle.de>
Date: Fri, 5 Feb 2021 20:16:02 +0100
Subject: sr xg_sr_bitmap populated_pfns
tools: use xg_sr_bitmap for populated_pfns
Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
tools/libs/guest/xg_sr_common.h | 20 ++-
tools/libs/guest/xg_sr_restore.c | 69 ---------
tools/libs/guest/xg_sr_restore_x86_hvm.c | 9 ++
tools/libs/guest/xg_sr_restore_x86_pv.c | 7 +
4 files changed, 34 insertions(+), 71 deletions(-)
--- a/tools/libs/guest/xg_sr_common.h
+++ b/tools/libs/guest/xg_sr_common.h
@@ -366,26 +366,25 @@ struct xc_sr_context
unsigned int buffered_rec_num;
/*
* Xenstore and Console parameters.
* INPUT: evtchn & domid
* OUTPUT: gfn
*/
xen_pfn_t xenstore_gfn, console_gfn;
unsigned int xenstore_evtchn, console_evtchn;
uint32_t xenstore_domid, console_domid;
/* Bitmap of currently populated PFNs during restore. */
- unsigned long *populated_pfns;
- xen_pfn_t max_populated_pfn;
+ struct sr_bitmap populated_pfns;
/* Sender has invoked verify mode on the stream. */
bool verify;
void *verify_buf;
} restore;
};
union /* Guest-arch specific data. */
{
struct /* x86 */
{
/* Common save/restore data. */
@@ -623,22 +622,39 @@ static inline bool page_type_has_stream_data(uint32_t type)
case XEN_DOMCTL_PFINFO_L4TAB:
case XEN_DOMCTL_PFINFO_L4TAB | XEN_DOMCTL_PFINFO_LPINTAB:
return true;
case XEN_DOMCTL_PFINFO_XTAB:
case XEN_DOMCTL_PFINFO_BROKEN:
case XEN_DOMCTL_PFINFO_XALLOC:
default:
return false;
}
}
+static inline bool pfn_is_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
+{
+ return 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 ( sr_set_bit(pfn, &ctx->restore.populated_pfns) == false )
+ {
+ PERROR("Failed to realloc populated_pfns bitmap");
+ errno = ENOMEM;
+ return -1;
+ }
+ return 0;
+}
#endif
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
--- a/tools/libs/guest/xg_sr_restore.c
+++ b/tools/libs/guest/xg_sr_restore.c
@@ -62,82 +62,24 @@ static int read_headers(struct xc_sr_context *ctx)
if ( dhdr.xen_major == 0 )
{
IPRINTF("Found %s domain, converted from legacy stream format",
dhdr_type_to_str(dhdr.type));
DPRINTF(" Legacy conversion script version %u", dhdr.xen_minor);
}
else
IPRINTF("Found %s domain from Xen %u.%u",
dhdr_type_to_str(dhdr.type), dhdr.xen_major, dhdr.xen_minor);
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 int count,
const xen_pfn_t *original_pfns, const uint32_t *types)
{
xc_interface *xch = ctx->xch;
unsigned int i, nr_pfns = 0;
int rc = -1;
@@ -902,34 +844,24 @@ static int setup(struct xc_sr_context *ctx)
if ( !dirty_bitmap )
{
ERROR("Unable to allocate memory for dirty bitmap");
rc = -1;
goto err;
}
}
rc = ctx->restore.ops.setup(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 )
- {
- ERROR("Unable to allocate memory for populated_pfns bitmap");
- rc = -1;
- goto err;
- }
-
ctx->restore.pfns = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.pfns));
ctx->restore.types = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.types));
ctx->restore.mfns = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.mfns));
ctx->restore.map_errs = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.map_errs));
ctx->restore.pp_pfns = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.pp_pfns));
ctx->restore.pp_mfns = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.pp_mfns));
ctx->restore.guest_data = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.guest_data));
ctx->restore.iov = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.iov));
ctx->restore.pages = malloc(MAX_BATCH_SIZE * sizeof(*ctx->restore.pages->pfn) + sizeof(*ctx->restore.pages));
if ( !ctx->restore.pfns || !ctx->restore.types || !ctx->restore.mfns ||
!ctx->restore.map_errs || !ctx->restore.pp_pfns ||
!ctx->restore.pp_mfns || !ctx->restore.guest_data ||
@@ -960,25 +892,24 @@ static void cleanup(struct xc_sr_context *ctx)
unsigned int i;
DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap,
&ctx->restore.dirty_bitmap_hbuf);
for ( i = 0; i < ctx->restore.buffered_rec_num; i++ )
free(ctx->restore.buffered_records[i].data);
if ( ctx->stream_type == XC_STREAM_COLO )
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);
free(ctx->restore.pages);
free(ctx->restore.iov);
free(ctx->restore.guest_data);
free(ctx->restore.pp_mfns);
free(ctx->restore.pp_pfns);
free(ctx->restore.map_errs);
free(ctx->restore.mfns);
free(ctx->restore.types);
free(ctx->restore.pfns);
if ( ctx->restore.ops.cleanup(ctx) )
PERROR("Failed to clean up");
--- a/tools/libs/guest/xg_sr_restore_x86_hvm.c
+++ b/tools/libs/guest/xg_sr_restore_x86_hvm.c
@@ -127,24 +127,25 @@ static int x86_hvm_localise_page(struct xc_sr_context *ctx,
uint32_t type, void *page)
{
/* no-op */
return 0;
}
/*
* restore_ops function. Confirms the stream matches the domain.
*/
static int x86_hvm_setup(struct xc_sr_context *ctx)
{
xc_interface *xch = ctx->xch;
+ unsigned long max_pfn;
if ( ctx->restore.guest_type != DHDR_TYPE_X86_HVM )
{
ERROR("Unable to restore %s domain into an x86 HVM domain",
dhdr_type_to_str(ctx->restore.guest_type));
return -1;
}
if ( ctx->restore.guest_page_size != PAGE_SIZE )
{
ERROR("Invalid page size %u for x86 HVM domains",
ctx->restore.guest_page_size);
@@ -152,24 +153,31 @@ static int x86_hvm_setup(struct xc_sr_context *ctx)
}
#ifdef __i386__
/* Very large domains (> 1TB) will exhaust virtual address space. */
if ( ctx->restore.p2m_size > 0x0fffffff )
{
errno = E2BIG;
PERROR("Cannot restore this big a guest");
return -1;
}
#endif
+ max_pfn = max(ctx->restore.p2m_size, ctx->dominfo.max_pages);
+ if ( !sr_bitmap_expand(&ctx->restore.populated_pfns, max_pfn) )
+ {
+ PERROR("Unable to allocate memory for populated_pfns bitmap");
+ return -1;
+ }
+
return 0;
}
/*
* restore_ops function.
*/
static int x86_hvm_process_record(struct xc_sr_context *ctx,
struct xc_sr_record *rec)
{
switch ( rec->type )
{
case REC_TYPE_X86_TSC_INFO:
@@ -232,24 +240,25 @@ static int x86_hvm_stream_complete(struct xc_sr_context *ctx)
ctx->restore.xenstore_domid);
if ( rc )
{
PERROR("Failed to seed grant table");
return rc;
}
return rc;
}
static int x86_hvm_cleanup(struct xc_sr_context *ctx)
{
+ sr_bitmap_free(&ctx->restore.populated_pfns);
free(ctx->x86.hvm.restore.context.ptr);
free(ctx->x86.restore.cpuid.ptr);
free(ctx->x86.restore.msr.ptr);
return 0;
}
struct xc_sr_restore_ops restore_ops_x86_hvm =
{
.pfn_is_valid = x86_hvm_pfn_is_valid,
.pfn_to_gfn = x86_hvm_pfn_to_gfn,
--- a/tools/libs/guest/xg_sr_restore_x86_pv.c
+++ b/tools/libs/guest/xg_sr_restore_x86_pv.c
@@ -1051,24 +1051,30 @@ static int x86_pv_setup(struct xc_sr_context *ctx)
if ( ctx->restore.guest_page_size != PAGE_SIZE )
{
ERROR("Invalid page size %d for x86_pv domains",
ctx->restore.guest_page_size);
return -1;
}
rc = x86_pv_domain_info(ctx);
if ( rc )
return rc;
+ if ( !sr_bitmap_expand(&ctx->restore.populated_pfns, 32 * 1024 / 4) )
+ {
+ PERROR("Unable to allocate memory for populated_pfns bitmap");
+ return -1;
+ }
+
ctx->x86.pv.restore.nr_vcpus = ctx->dominfo.max_vcpu_id + 1;
ctx->x86.pv.restore.vcpus = calloc(sizeof(struct xc_sr_x86_pv_restore_vcpu),
ctx->x86.pv.restore.nr_vcpus);
if ( !ctx->x86.pv.restore.vcpus )
{
errno = ENOMEM;
return -1;
}
rc = x86_pv_map_m2p(ctx);
if ( rc )
return rc;
@@ -1144,24 +1150,25 @@ static int x86_pv_stream_complete(struct xc_sr_context *ctx)
PERROR("Failed to seed grant table");
return rc;
}
return rc;
}
/*
* restore_ops function.
*/
static int x86_pv_cleanup(struct xc_sr_context *ctx)
{
+ sr_bitmap_free(&ctx->restore.populated_pfns);
free(ctx->x86.pv.p2m);
free(ctx->x86.pv.p2m_pfns);
if ( ctx->x86.pv.restore.vcpus )
{
unsigned int i;
for ( i = 0; i < ctx->x86.pv.restore.nr_vcpus; ++i )
{
struct xc_sr_x86_pv_restore_vcpu *vcpu =
&ctx->x86.pv.restore.vcpus[i];