[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH] libxc: try to find last used pfn when migrating



On 27/11/15 14:50, Juergen Gross wrote:
> For migration the last used pfn of a guest is needed to size the
> logdirty bitmap and as an upper bound of the page loop. Unfortunately
> there are pv-kernels advertising a much higher maximum pfn as they
> are really using in order to support memory hotplug. This will lead
> to allocation of much more memory in Xen tools during migration as
> really needed.
>
> Try to find the last used guest pfn of a pv-domu by scanning the p2m
> tree from the last entry towards it's start and search for an entry
> not being invalid.
>
> Normally the mid pages of the p2m tree containing all invalid entries
> are being reused, so we can just scan the top page for identical
> entries and skip them but the first one.
>
> Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
> ---
>  tools/libxc/xc_sr_save.c        |  8 ++++----
>  tools/libxc/xc_sr_save_x86_pv.c | 34 +++++++++++++++++++++++++++++++---
>  2 files changed, 35 insertions(+), 7 deletions(-)
>
> diff --git a/tools/libxc/xc_sr_save.c b/tools/libxc/xc_sr_save.c
> index 0c12e56..22b3f18 100644
> --- a/tools/libxc/xc_sr_save.c
> +++ b/tools/libxc/xc_sr_save.c
> @@ -677,6 +677,10 @@ static int setup(struct xc_sr_context *ctx)
>      DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap,
>                                      &ctx->save.dirty_bitmap_hbuf);
>  
> +    rc = ctx->save.ops.setup(ctx);
> +    if ( rc )
> +        goto err;
> +
>      dirty_bitmap = xc_hypercall_buffer_alloc_pages(
>                     xch, dirty_bitmap, 
> NRPAGES(bitmap_size(ctx->save.p2m_size)));
>      ctx->save.batch_pfns = malloc(MAX_BATCH_SIZE *
> @@ -692,10 +696,6 @@ static int setup(struct xc_sr_context *ctx)
>          goto err;
>      }
>  
> -    rc = ctx->save.ops.setup(ctx);
> -    if ( rc )
> -        goto err;
> -
>      rc = 0;
>  
>   err:

While moving this, the restore side should be consistent (turns out it
already is), and the docs updated.  There was an inaccuracy, so I went
ahead and did it.

--8<--
diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
index 64f6082..ae77155 100644
--- a/tools/libxc/xc_sr_common.h
+++ b/tools/libxc/xc_sr_common.h
@@ -54,9 +54,11 @@ struct xc_sr_save_ops
                           void **page);
 
     /**
-     * Set up local environment to restore a domain.  This is called before
-     * any records are written to the stream.  (Typically querying running
-     * domain state, setting up mappings etc.)
+     * Set up local environment to save a domain. (Typically querying
+     * running domain state, setting up mappings etc.)
+     *
+     * This is called once before any common setup has occurred,
allowing for
+     * guest-specific adjustments to be made to common state.
      */
     int (*setup)(struct xc_sr_context *ctx);
 
@@ -121,8 +123,10 @@ struct xc_sr_restore_ops
     int (*localise_page)(struct xc_sr_context *ctx, uint32_t type, void
*page);
 
     /**
-     * Set up local environment to restore a domain.  This is called before
-     * any records are read from the stream.
+     * Set up local environment to restore a domain.
+     *
+     * This is called once before any common setup has occurred,
allowing for
+     * guest-specific adjustments to be made to common state.
      */
     int (*setup)(struct xc_sr_context *ctx);
 
--8<--

Feel free to fold this into your patch, or I can submit it alone as a
cleanup prerequisite for your functional change below.

> diff --git a/tools/libxc/xc_sr_save_x86_pv.c b/tools/libxc/xc_sr_save_x86_pv.c
> index f63f40b..6189fda 100644
> --- a/tools/libxc/xc_sr_save_x86_pv.c
> +++ b/tools/libxc/xc_sr_save_x86_pv.c
> @@ -83,8 +83,8 @@ static int map_p2m(struct xc_sr_context *ctx)
>       */
>      xc_interface *xch = ctx->xch;
>      int rc = -1;
> -    unsigned x, fpp, fll_entries, fl_entries;
> -    xen_pfn_t fll_mfn;
> +    unsigned x, saved_x, fpp, fll_entries, fl_entries;
> +    xen_pfn_t fll_mfn, saved_mfn, max_pfn;
>  
>      xen_pfn_t *local_fll = NULL;
>      void *guest_fll = NULL;
> @@ -96,7 +96,6 @@ static int map_p2m(struct xc_sr_context *ctx)
>  
>      fpp = PAGE_SIZE / ctx->x86_pv.width;
>      fll_entries = (ctx->x86_pv.max_pfn / (fpp * fpp)) + 1;
> -    fl_entries  = (ctx->x86_pv.max_pfn / fpp) + 1;
>  
>      fll_mfn = GET_FIELD(ctx->x86_pv.shinfo, arch.pfn_to_mfn_frame_list_list,
>                          ctx->x86_pv.width);
> @@ -131,6 +130,8 @@ static int map_p2m(struct xc_sr_context *ctx)
>      }
>  
>      /* Check for bad mfns in frame list list. */
> +    saved_mfn = 0;
> +    saved_x = 0;
>      for ( x = 0; x < fll_entries; ++x )
>      {
>          if ( local_fll[x] == 0 || local_fll[x] > ctx->x86_pv.max_mfn )
> @@ -139,8 +140,35 @@ static int map_p2m(struct xc_sr_context *ctx)
>                    local_fll[x], x, fll_entries);
>              goto err;
>          }
> +        if ( local_fll[x] != saved_mfn )
> +        {
> +            saved_mfn = local_fll[x];
> +            saved_x = x;
> +        }
>      }
>  
> +    /*
> +     * Check for actual lower max_pfn:
> +     * If the trailing entries of the frame list list were all the same we 
> can
> +     * assume they all reference mid pages all referencing p2m pages with all
> +     * invalid entries. Otherwise there would be multiple pfns referencing 
> all
> +     * the same mfn which can't work across migration, as this sharing would 
> be
> +     * broken by the migration process.
> +     * Adjust max_pfn if possible to avoid allocating much larger areas as
> +     * needed for p2m and logdirty map.
> +     */
> +    max_pfn = (saved_x + 1) * fpp * fpp - 1;
> +    if ( max_pfn < ctx->x86_pv.max_pfn )
> +    {
> +        ctx->x86_pv.max_pfn = max_pfn;
> +        ctx->x86_pv.p2m_frames = (ctx->x86_pv.max_pfn + fpp) / fpp;
> +        ctx->save.p2m_size = max_pfn + 1;
> +        fll_entries = (ctx->x86_pv.max_pfn / (fpp * fpp)) + 1;
> +        DPRINTF("lowering max_pfn to %#lx, p2m_frames %d", max_pfn,
> +                ctx->x86_pv.p2m_frames);
> +    }
> +    fl_entries  = (ctx->x86_pv.max_pfn / fpp) + 1;
> +
>      /* Map the guest mid p2m frames. */
>      guest_fl = xc_map_foreign_pages(xch, ctx->domid, PROT_READ,
>                                      local_fll, fll_entries);

For the actual change, Reviewed-by: Andrew Cooper
<andrew.cooper3@xxxxxxxxxx>

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.