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];
 
openSUSE Build Service is sponsored by