diff mbox

[v9,2/3] tools/libxc: add API for bitmap access for restore

Message ID 20170901160843.9057-3-olaf@aepfle.de (mailing list archive)
State New, archived
Headers show

Commit Message

Olaf Hering Sept. 1, 2017, 4:08 p.m. UTC
Extend API for managing bitmaps. Each bitmap is now represented by a
generic struct xc_sr_bitmap.
Switch the existing populated_pfns to this API.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Acked-by: Wei Liu <wei.liu2@citrix.com>
---
 tools/libxc/xc_sr_common.c  | 41 ++++++++++++++++++++++++++
 tools/libxc/xc_sr_common.h  | 72 +++++++++++++++++++++++++++++++++++++++++++--
 tools/libxc/xc_sr_restore.c | 66 ++---------------------------------------
 3 files changed, 114 insertions(+), 65 deletions(-)

Comments

Andrew Cooper Sept. 6, 2017, 11:57 a.m. UTC | #1
On 01/09/17 17:08, Olaf Hering wrote:
> Extend API for managing bitmaps. Each bitmap is now represented by a
> generic struct xc_sr_bitmap.
> Switch the existing populated_pfns to this API.
>
> Signed-off-by: Olaf Hering <olaf@aepfle.de>
> Acked-by: Wei Liu <wei.liu2@citrix.com>
> ---
>  tools/libxc/xc_sr_common.c  | 41 ++++++++++++++++++++++++++
>  tools/libxc/xc_sr_common.h  | 72 +++++++++++++++++++++++++++++++++++++++++++--
>  tools/libxc/xc_sr_restore.c | 66 ++---------------------------------------
>  3 files changed, 114 insertions(+), 65 deletions(-)
>
> diff --git a/tools/libxc/xc_sr_common.c b/tools/libxc/xc_sr_common.c
> index 79b9c3e940..4d221ca90c 100644
> --- a/tools/libxc/xc_sr_common.c
> +++ b/tools/libxc/xc_sr_common.c
> @@ -155,6 +155,47 @@ static void __attribute__((unused)) build_assertions(void)
>      BUILD_BUG_ON(sizeof(struct xc_sr_rec_hvm_params)        != 8);
>  }
>  
> +/*
> + * 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)

Libxc uses the hypervisor coding style, and xc_sr_* currently have a
consistent style.

> +    {
> +        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
> diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
> index a83f22af4e..734320947a 100644
> --- a/tools/libxc/xc_sr_common.h
> +++ b/tools/libxc/xc_sr_common.h
> @@ -172,6 +172,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 +261,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;
> @@ -343,6 +348,69 @@ 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);

No need for extern on function prototypes.

> +
> +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;

bm->bits = 0, or a subsequent test/set/clear will fall over a NULL pointer.

> +}
> +
> +static inline bool xc_sr_set_bit(unsigned long bit, struct xc_sr_bitmap *bm)
> +{
> +    if (!xc_sr_bitmap_resize(bm, bit))

There's a boundary condition here trying to test bit 0 of an empty bitmap.

> +        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;
> +}

Why are these moved?  They are still restore specific.

~Andrew

> +
>  struct xc_sr_record
>  {
>      uint32_t type;
> diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c
> index a016678332..d53948e1a6 100644
> --- a/tools/libxc/xc_sr_restore.c
> +++ b/tools/libxc/xc_sr_restore.c
> @@ -68,64 +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
> @@ -684,10 +626,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 +662,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");
>  }
Olaf Hering Sept. 6, 2017, 12:15 p.m. UTC | #2
On Wed, Sep 06, Andrew Cooper wrote:

> On 01/09/17 17:08, Olaf Hering wrote:
> > +static inline bool pfn_is_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
> > +static inline int pfn_set_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
> Why are these moved?  They are still restore specific.

There is no tools/libxc/xc_sr_restore.h, should I create one?

Olaf
diff mbox

Patch

diff --git a/tools/libxc/xc_sr_common.c b/tools/libxc/xc_sr_common.c
index 79b9c3e940..4d221ca90c 100644
--- a/tools/libxc/xc_sr_common.c
+++ b/tools/libxc/xc_sr_common.c
@@ -155,6 +155,47 @@  static void __attribute__((unused)) build_assertions(void)
     BUILD_BUG_ON(sizeof(struct xc_sr_rec_hvm_params)        != 8);
 }
 
+/*
+ * 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
diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
index a83f22af4e..734320947a 100644
--- a/tools/libxc/xc_sr_common.h
+++ b/tools/libxc/xc_sr_common.h
@@ -172,6 +172,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 +261,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;
@@ -343,6 +348,69 @@  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);
+    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;
diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c
index a016678332..d53948e1a6 100644
--- a/tools/libxc/xc_sr_restore.c
+++ b/tools/libxc/xc_sr_restore.c
@@ -68,64 +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
@@ -684,10 +626,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 +662,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");
 }