File xen.sr-precopy_policy.patch of Package xen

From: Olaf Hering <olaf@aepfle.de>
Date: Fri, 8 Jan 2021 18:19:49 +0100
Subject: sr precopy_policy

tools: add callback to libxl for precopy_policy and precopy_stats

This duplicates simple_precopy_policy. To recap its purpose:
- do up to 5 iterations of copying dirty domU memory to target,
  including the initial copying of all domU memory, excluding
  the final copying while the domU is suspended
- do fewer iterations in case the domU dirtied less than 50 pages

Take the opportunity to also move xen_pfn_t into qw().

Signed-off-by: Olaf Hering <olaf@aepfle.de>

v02:
- use plain struct precopy_stats instead of inventing
  a new precopy_stats_t (anthony)
---
 tools/libs/light/libxl_dom_save.c       | 19 +++++++++
 tools/libs/light/libxl_internal.h       |  2 +
 tools/libs/light/libxl_save_msgs_gen.pl |  3 +-
 3 files changed, 23 insertions(+), 1 deletion(-)

--- a/tools/libs/light/libxl_dom_save.c
+++ b/tools/libs/light/libxl_dom_save.c
@@ -364,24 +364,42 @@ int libxl__save_emulator_xenstore_data(libxl__domain_save_state *dss,
 
     rc = 0;
 
  out:
     if (!rc) {
         *callee_buf = buf;
         *callee_len = len;
     }
 
     return rc;
 }
 
+static int libxl__domain_save_precopy_policy(struct precopy_stats stats, void *user)
+{
+    libxl__save_helper_state *shs = user;
+    libxl__domain_save_state *dss = shs->caller_state;
+    STATE_AO_GC(dss->ao);
+
+    LOGD(DEBUG, shs->domid, "iteration %u dirty_count %ld total_written %lu",
+         stats.iteration, stats.dirty_count, stats.total_written);
+    if (stats.dirty_count >= 0 && stats.dirty_count < LIBXL_XGS_POLICY_TARGET_DIRTY_COUNT)
+        goto stop_copy;
+    if (stats.iteration >= LIBXL_XGS_POLICY_MAX_ITERATIONS)
+        goto stop_copy;
+    return XGS_POLICY_CONTINUE_PRECOPY;
+
+stop_copy:
+    return XGS_POLICY_STOP_AND_COPY;
+}
+
 /*----- main code for saving, in order of execution -----*/
 
 void libxl__domain_save(libxl__egc *egc, libxl__domain_save_state *dss)
 {
     STATE_AO_GC(dss->ao);
     int rc, ret;
 
     /* Convenience aliases */
     const uint32_t domid = dss->domid;
     const libxl_domain_type type = dss->type;
     const int live = dss->live;
     const int debug = dss->debug;
@@ -421,24 +439,25 @@ void libxl__domain_save(libxl__egc *egc, libxl__domain_save_state *dss)
     ret = xc_domain_getvnuma(CTX->xch, domid, &nr_vnodes, &nr_vmemranges,
                              &nr_vcpus, NULL, NULL, NULL);
     if (ret != -1 || errno != EOPNOTSUPP) {
         LOGD(ERROR, domid, "Cannot save a guest with vNUMA configured");
         rc = ERROR_FAIL;
         goto out;
     }
 
     if (dss->checkpointed_stream == LIBXL_CHECKPOINTED_STREAM_NONE)
         callbacks->suspend = libxl__domain_suspend_callback;
 
     callbacks->switch_qemu_logdirty = libxl__domain_suspend_common_switch_qemu_logdirty;
+    callbacks->precopy_policy = libxl__domain_save_precopy_policy;
 
     dss->sws.ao  = dss->ao;
     dss->sws.dss = dss;
     dss->sws.fd  = dss->fd;
     dss->sws.back_channel = false;
     dss->sws.completion_callback = stream_done;
 
     libxl__stream_write_start(egc, &dss->sws);
     return;
 
  out:
     domain_save_done(egc, dss, rc);
--- a/tools/libs/light/libxl_internal.h
+++ b/tools/libs/light/libxl_internal.h
@@ -116,24 +116,26 @@
 #define QEMU_SIGNATURE "DeviceModelRecord0002"
 #define STUBDOM_CONSOLE_LOGGING 0
 #define STUBDOM_CONSOLE_SAVE 1
 #define STUBDOM_CONSOLE_RESTORE 2
 #define STUBDOM_CONSOLE_SERIAL 3
 #define STUBDOM_SPECIAL_CONSOLES 3
 #define LIBXL_LINUX_STUBDOM_MEM 128
 #define LIBXL_STUBDOM_EMPTY_CDROM XEN_RUN_DIR "/empty-cdrom" /* .$domid */
 #define TAP_DEVICE_SUFFIX "-emu"
 #define DOMID_XS_PATH "domid"
 #define PVSHIM_BASENAME "xen-shim"
 #define PVSHIM_CMDLINE "pv-shim console=xen,pv"
+#define LIBXL_XGS_POLICY_MAX_ITERATIONS 5
+#define LIBXL_XGS_POLICY_TARGET_DIRTY_COUNT 50
 
 #define DIV_ROUNDUP(n, d) (((n) + (d) - 1) / (d))
 
 #define LIBXL__LOGGING_ENABLED
 
 #ifdef LIBXL__LOGGING_ENABLED
 #define LIBXL__LOG(ctx, loglevel, _f, _a...)   libxl__log(ctx, loglevel, -1, __FILE__, __LINE__, __func__, INVALID_DOMID, _f, ##_a)
 #define LIBXL__LOG_ERRNO(ctx, loglevel, _f, _a...)   libxl__log(ctx, loglevel, errno, __FILE__, __LINE__, __func__, INVALID_DOMID, _f, ##_a)
 #define LIBXL__LOG_ERRNOVAL(ctx, loglevel, errnoval, _f, _a...)   libxl__log(ctx, loglevel, errnoval, __FILE__, __LINE__, __func__, INVALID_DOMID, _f, ##_a)
 
 /* Same log functions as above, but with _d being a domain id. */
 #define LIBXL__LOGD(ctx, loglevel, _d, _f, _a...)   libxl__log(ctx, loglevel, -1, __FILE__, __LINE__, __func__, _d, _f, ##_a)
--- a/tools/libs/light/libxl_save_msgs_gen.pl
+++ b/tools/libs/light/libxl_save_msgs_gen.pl
@@ -14,24 +14,25 @@ our @msgs = (
     #   x  - function pointer is in struct {save,restore}_callbacks
     #         and its null-ness needs to be passed through to the helper's xc
     #   W  - needs a return value; callback is synchronous
     #   A  - needs a return value; callback is asynchronous
     [ 'sr',     "log",                   [qw(uint32_t level
                                              uint32_t errnoval
                                              STRING context
                                              STRING formatted)] ],
     [ 'sr',     "progress",              [qw(STRING context
                                              STRING doing_what),
                                             'unsigned long', 'done',
                                             'unsigned long', 'total'] ],
+    [ 'scxW',   "precopy_policy", ['struct precopy_stats', 'stats'] ],
     [ 'srcxA',  "suspend", [] ],
     [ 'srcxA',  "postcopy", [] ],
     [ 'srcxA',  "checkpoint", [] ],
     [ 'srcxA',  "wait_checkpoint", [] ],
     [ 'scxA',   "switch_qemu_logdirty",  [qw(uint32_t domid
                                           unsigned enable)] ],
     [ 'rcxW',   "static_data_done",      [qw(unsigned missing)] ],
     [ 'rcx',    "restore_results",       ['xen_pfn_t', 'store_gfn',
                                           'xen_pfn_t', 'console_gfn'] ],
     [ 'srW',    "complete",              [qw(int retval
                                              int errnoval)] ],
 );
@@ -133,25 +134,25 @@ END
 $out_body{'helper'} .= <<END;
 static void bytes_put(unsigned char *const buf, int *len,
                       const void *value, int vlen)
 {
     assert(vlen < INT_MAX/2 - *len);
     if (buf)
         memcpy(buf + *len, value, vlen);
     *len += vlen;
 }
 
 END
 
-foreach my $simpletype (qw(int uint16_t uint32_t unsigned), 'unsigned long', 'xen_pfn_t') {
+foreach my $simpletype (qw(int uint16_t uint32_t unsigned xen_pfn_t), 'struct precopy_stats', 'unsigned long') {
     my $typeid = typeid($simpletype);
     $out_body{'callout'} .= <<END;
 static int ${typeid}_get(const unsigned char **msg,
                         const unsigned char *const endmsg,
                         $simpletype *result)
 {
     return bytes_get(msg, endmsg, result, sizeof(*result));
 }
 
 END
     $out_body{'helper'} .= <<END;
 static void ${typeid}_put(unsigned char *const buf, int *len,
openSUSE Build Service is sponsored by