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

[PATCH v2 1/2] live migration: do not use deffered bitmap when inappropriate



Use deffered bitmap only in PV guests context as it not used for HVM guests.
This allow to reduce memory pressure on domain0 while migrating very large
(memory wise) HVM guests.

Signed-off-by: Andrei Semenov <andrei.semenov@xxxxxxxx>
---
 tools/libs/guest/xg_sr_common.h       | 26 ++++++++++++++++--
 tools/libs/guest/xg_sr_save.c         | 23 +++++++---------
 tools/libs/guest/xg_sr_save_x86_hvm.c | 21 +++++++++++++++
 tools/libs/guest/xg_sr_save_x86_pv.c  | 39 +++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 16 deletions(-)

diff --git a/tools/libs/guest/xg_sr_common.h b/tools/libs/guest/xg_sr_common.h
index 36d45ef56f..941e24d7b7 100644
--- a/tools/libs/guest/xg_sr_common.h
+++ b/tools/libs/guest/xg_sr_common.h
@@ -96,6 +96,24 @@ struct xc_sr_save_ops
      */
     int (*check_vm_state)(struct xc_sr_context *ctx);
 
+    /**
+     * For some reasons the page can't be sent for the moment. Postpone this
+     * send to the later stage when domain is suspended.
+     */
+    int (*defer_page)(struct xc_sr_context *ctx, xen_pfn_t pfn);
+
+    /**
+     *  Merge all deferred pages with the dirty pages bitmap (in order to be
+     *  sent).
+     */
+    int (*merge_deferred)(const struct xc_sr_context *ctx,
+                          unsigned long *bitmap, unsigned long *count);
+
+    /**
+     *  Deferred pages was successfully sent. Reset all associated information.
+     */
+    int (*reset_deferred)(struct xc_sr_context *ctx);
+
     /**
      * Clean up the local environment.  Will be called exactly once, either
      * after a successful save, or upon encountering an error.
@@ -243,8 +261,6 @@ struct xc_sr_context
 
             xen_pfn_t *batch_pfns;
             unsigned int nr_batch_pfns;
-            unsigned long *deferred_pages;
-            unsigned long nr_deferred_pages;
             xc_hypercall_buffer_t dirty_bitmap_hbuf;
         } save;
 
@@ -349,6 +365,12 @@ struct xc_sr_context
 
                 union
                 {
+                    struct
+                    {
+                        unsigned long *deferred_pages;
+                        unsigned long nr_deferred_pages;
+                    } save;
+
                     struct
                     {
                         /* State machine for the order of received records. */
diff --git a/tools/libs/guest/xg_sr_save.c b/tools/libs/guest/xg_sr_save.c
index 9853d8d846..602b18488d 100644
--- a/tools/libs/guest/xg_sr_save.c
+++ b/tools/libs/guest/xg_sr_save.c
@@ -132,8 +132,7 @@ static int write_batch(struct xc_sr_context *ctx)
         /* Likely a ballooned page. */
         if ( mfns[i] == INVALID_MFN )
         {
-            set_bit(ctx->save.batch_pfns[i], ctx->save.deferred_pages);
-            ++ctx->save.nr_deferred_pages;
+            ctx->save.ops.defer_page(ctx, ctx->save.batch_pfns[i]);
         }
     }
 
@@ -192,8 +191,7 @@ static int write_batch(struct xc_sr_context *ctx)
             {
                 if ( rc == -1 && errno == EAGAIN )
                 {
-                    set_bit(ctx->save.batch_pfns[i], ctx->save.deferred_pages);
-                    ++ctx->save.nr_deferred_pages;
+                    ctx->save.ops.defer_page(ctx, ctx->save.batch_pfns[i]);
                     types[i] = XEN_DOMCTL_PFINFO_XTAB;
                     --nr_pages;
                 }
@@ -641,6 +639,7 @@ static int suspend_and_send_dirty(struct xc_sr_context *ctx)
     xc_interface *xch = ctx->xch;
     xc_shadow_op_stats_t stats = { 0, ctx->save.p2m_size };
     char *progress_str = NULL;
+    unsigned long merged;
     int rc;
     DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap,
                                     &ctx->save.dirty_bitmap_hbuf);
@@ -669,7 +668,7 @@ static int suspend_and_send_dirty(struct xc_sr_context *ctx)
     else
         xc_set_progress_prefix(xch, "Checkpointed save");
 
-    bitmap_or(dirty_bitmap, ctx->save.deferred_pages, ctx->save.p2m_size);
+    ctx->save.ops.merge_deferred(ctx, dirty_bitmap, &merged);
 
     if ( !ctx->save.live && ctx->stream_type == XC_STREAM_COLO )
     {
@@ -681,12 +680,11 @@ static int suspend_and_send_dirty(struct xc_sr_context 
*ctx)
         }
     }
 
-    rc = send_dirty_pages(ctx, stats.dirty_count + 
ctx->save.nr_deferred_pages);
+    rc = send_dirty_pages(ctx, stats.dirty_count + merged);
     if ( rc )
         goto out;
 
-    bitmap_clear(ctx->save.deferred_pages, ctx->save.p2m_size);
-    ctx->save.nr_deferred_pages = 0;
+    ctx->save.ops.reset_deferred(ctx);
 
  out:
     xc_set_progress_prefix(xch, NULL);
@@ -805,18 +803,16 @@ static int setup(struct xc_sr_context *ctx)
         xch, dirty_bitmap, NRPAGES(bitmap_size(ctx->save.p2m_size)));
     ctx->save.batch_pfns = malloc(MAX_BATCH_SIZE *
                                   sizeof(*ctx->save.batch_pfns));
-    ctx->save.deferred_pages = bitmap_alloc(ctx->save.p2m_size);
 
-    if ( !ctx->save.batch_pfns || !dirty_bitmap || !ctx->save.deferred_pages )
+    if ( !ctx->save.batch_pfns || !dirty_bitmap )
     {
-        ERROR("Unable to allocate memory for dirty bitmaps, batch pfns and"
-              " deferred pages");
+        ERROR("Unable to allocate memory for dirty bitmaps, batch pfns");
         rc = -1;
         errno = ENOMEM;
         goto err;
     }
 
-    rc = 0;
+    rc = ctx->save.ops.reset_deferred(ctx);
 
  err:
     return rc;
@@ -837,7 +833,6 @@ static void cleanup(struct xc_sr_context *ctx)
 
     xc_hypercall_buffer_free_pages(xch, dirty_bitmap,
                                    NRPAGES(bitmap_size(ctx->save.p2m_size)));
-    free(ctx->save.deferred_pages);
     free(ctx->save.batch_pfns);
 }
 
diff --git a/tools/libs/guest/xg_sr_save_x86_hvm.c 
b/tools/libs/guest/xg_sr_save_x86_hvm.c
index 1634a7bc43..3c762a0af0 100644
--- a/tools/libs/guest/xg_sr_save_x86_hvm.c
+++ b/tools/libs/guest/xg_sr_save_x86_hvm.c
@@ -211,6 +211,24 @@ static int x86_hvm_end_of_checkpoint(struct xc_sr_context 
*ctx)
     return 0;
 }
 
+static int x86_hvm_defer_page(struct xc_sr_context *ctx, xen_pfn_t pfn)
+{
+    return 0;
+}
+
+static int x86_hvm_merge_deferred(const struct xc_sr_context *ctx,
+                                 unsigned long *bitmap, unsigned long *count)
+{
+    *count = 0;
+
+    return 0;
+}
+
+static int x86_hvm_reset_deferred(struct xc_sr_context *ctx)
+{
+    return 0;
+}
+
 static int x86_hvm_cleanup(struct xc_sr_context *ctx)
 {
     xc_interface *xch = ctx->xch;
@@ -237,6 +255,9 @@ struct xc_sr_save_ops save_ops_x86_hvm =
     .start_of_checkpoint = x86_hvm_start_of_checkpoint,
     .end_of_checkpoint   = x86_hvm_end_of_checkpoint,
     .check_vm_state      = x86_hvm_check_vm_state,
+    .defer_page          = x86_hvm_defer_page,
+    .merge_deferred      = x86_hvm_merge_deferred,
+    .reset_deferred      = x86_hvm_reset_deferred,
     .cleanup             = x86_hvm_cleanup,
 };
 
diff --git a/tools/libs/guest/xg_sr_save_x86_pv.c 
b/tools/libs/guest/xg_sr_save_x86_pv.c
index 4964f1f7b8..5fdc7e9590 100644
--- a/tools/libs/guest/xg_sr_save_x86_pv.c
+++ b/tools/libs/guest/xg_sr_save_x86_pv.c
@@ -1031,6 +1031,7 @@ static int x86_pv_normalise_page(struct xc_sr_context 
*ctx, xen_pfn_t type,
  */
 static int x86_pv_setup(struct xc_sr_context *ctx)
 {
+    xc_interface *xch = ctx->xch;
     int rc;
 
     rc = x86_pv_domain_info(ctx);
@@ -1049,6 +1050,15 @@ static int x86_pv_setup(struct xc_sr_context *ctx)
     if ( rc )
         return rc;
 
+    ctx->x86.pv.save.deferred_pages = bitmap_alloc(ctx->save.p2m_size);
+
+    if (!ctx->x86.pv.save.deferred_pages)
+    {
+        ERROR("Unable to allocate memory for deferred pages");
+        errno = ENOMEM;
+        return -1;
+    }
+
     return 0;
 }
 
@@ -1116,9 +1126,35 @@ static int x86_pv_check_vm_state(struct xc_sr_context 
*ctx)
     return x86_pv_check_vm_state_p2m_list(ctx);
 }
 
+static int x86_pv_defer_page(struct xc_sr_context *ctx, xen_pfn_t pfn)
+{
+    set_bit(pfn, ctx->x86.pv.save.deferred_pages);
+    ++ctx->x86.pv.save.nr_deferred_pages;
+
+    return 0;
+}
+
+static int x86_pv_merge_deferred(const struct xc_sr_context *ctx,
+                                 unsigned long *bitmap, unsigned long *count)
+{
+    bitmap_or(bitmap, ctx->x86.pv.save.deferred_pages, ctx->save.p2m_size);
+    *count = ctx->x86.pv.save.nr_deferred_pages;
+
+    return 0;
+}
+
+static int x86_pv_reset_deferred(struct xc_sr_context *ctx)
+{
+    bitmap_clear(ctx->x86.pv.save.deferred_pages, ctx->save.p2m_size);
+    ctx->x86.pv.save.nr_deferred_pages = 0;
+
+    return 0;
+}
+
 static int x86_pv_cleanup(struct xc_sr_context *ctx)
 {
     free(ctx->x86.pv.p2m_pfns);
+    free(ctx->x86.pv.save.deferred_pages);
 
     if ( ctx->x86.pv.p2m )
         munmap(ctx->x86.pv.p2m, ctx->x86.pv.p2m_frames * PAGE_SIZE);
@@ -1142,6 +1178,9 @@ struct xc_sr_save_ops save_ops_x86_pv =
     .start_of_checkpoint = x86_pv_start_of_checkpoint,
     .end_of_checkpoint   = x86_pv_end_of_checkpoint,
     .check_vm_state      = x86_pv_check_vm_state,
+    .defer_page          = x86_pv_defer_page,
+    .merge_deferred      = x86_pv_merge_deferred,
+    .reset_deferred      = x86_pv_reset_deferred,
     .cleanup             = x86_pv_cleanup,
 };
 
-- 
2.34.1



Andrei Semenov | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions
w: vates.fr | xcp-ng.org | xen-orchestra.com



 


Rackspace

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