All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
To: svt-core@virtuozzo.com
Cc: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Subject: [PATCH QEMU HCI-8.1 v5 36/36] VZ: migration: don't wait for stop-copy-only device state #VSTOR-150595
Date: Fri, 23 Oct 2026 19:54:13 +0300	[thread overview]
Message-ID: <20261023-vfio_v1-v5-36-ba0bf3c6d122@virtuozzo.com> (raw)
In-Reply-To: <20261023-vfio_v1-v5-0-ba0bf3c6d122@virtuozzo.com>

A VFIO device reports its stop-copy state as pending data.  Once it
has nothing left to pre-copy, or doesn't pre-copy at all, nothing done
while the guest runs makes it smaller.  If it doesn't fit into
bandwidth x downtime-limit on its own, the migration iterates until
the limit is raised, which Nova does in steps of minutes.  An NVIDIA
vGPU reports ~2 GiB, so at the usual limits it never fits.

Have state_pending_exact handlers report such irreducible data and,
when it alone exceeds the threshold, switch over once the rest is
within the threshold plus as much again: waiting can't do better, and
squeezing the rest further only keeps the guest throttled.  Migrations
whose pending data fits the threshold are unaffected.

Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
---
 hw/vfio/migration.c   |  9 ++++++++-
 migration/migration.c | 17 +++++++++++++++--
 migration/migration.h |  2 ++
 migration/savevm.c    | 15 +++++++++++++--
 migration/savevm.h    |  5 +++--
 5 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 8f2722dc671..c7312d9cb58 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -569,18 +569,25 @@ static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy,
     VFIODevice *vbasedev = opaque;
     VFIOMigration *migration = vbasedev->migration;
     uint64_t stop_copy_size = VFIO_MIG_STOP_COPY_SIZE;
+    int ret;
 
     /*
      * If getting pending migration size fails, VFIO_MIG_STOP_COPY_SIZE is
      * reported so downtime limit won't be violated.
      */
-    vfio_query_stop_copy_size(vbasedev, &stop_copy_size);
+    ret = vfio_query_stop_copy_size(vbasedev, &stop_copy_size);
     *must_precopy += stop_copy_size;
 
     if (vfio_device_state_is_precopy(vbasedev)) {
         vfio_query_precopy_size(migration);
     }
 
+    /* Once there's nothing left to pre-copy, iterating can't shrink it */
+    if (!ret && !migration->precopy_init_size &&
+        !migration->precopy_dirty_size) {
+        qemu_savevm_state_pending_add_irreducible(stop_copy_size);
+    }
+
     trace_vfio_state_pending_exact(vbasedev->name, *must_precopy, *can_postcopy,
                                    stop_copy_size, migration->precopy_init_size,
                                    migration->precopy_dirty_size);
diff --git a/migration/migration.c b/migration/migration.c
index 5f488836ab1..4a7da07fa05 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1840,6 +1840,7 @@ int migrate_init(MigrationState *s, Error **errp)
     s->rp_state.from_dst_file = NULL;
     s->mbps = 0.0;
     s->switchover_bw_per_ms = 0.0;
+    s->irreducible_pending = 0;
     s->pages_per_second = 0.0;
     s->downtime = 0;
     s->expected_downtime = 0;
@@ -3576,8 +3577,10 @@ static MigIterateState migration_iteration_run(MigrationState *s)
          * postcopy started, so ESTIMATE should always match with EXACT
          * during postcopy phase.
          */
-        if (pending_size < s->threshold_size) {
-            qemu_savevm_state_pending_exact(&must_precopy, &can_postcopy);
+        /* Allow for what the estimate lacks, see the irreducible rule below */
+        if (pending_size < s->threshold_size + 2 * s->irreducible_pending) {
+            s->irreducible_pending =
+                qemu_savevm_state_pending_exact(&must_precopy, &can_postcopy);
             pending_size = must_precopy + can_postcopy;
             trace_migrate_pending_exact(pending_size, must_precopy,
                                         can_postcopy);
@@ -3601,6 +3604,16 @@ static MigIterateState migration_iteration_run(MigrationState *s)
          *     (which was calculated from expected downtime)
          */
         complete_ready = can_switchover && (pending_size <= s->threshold_size);
+
+        /*
+         * Data which only moves once the guest is stopped can't shrink by
+         * iterating: if it alone exceeds the threshold, switch over once
+         * the rest is within the threshold plus as much again.
+         */
+        if (s->irreducible_pending > s->threshold_size) {
+            complete_ready = can_switchover &&
+                pending_size <= s->threshold_size + 2 * s->irreducible_pending;
+        }
     }
 
     if (complete_ready) {
diff --git a/migration/migration.h b/migration/migration.h
index e2cdb087321..d5df6ce495f 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -316,6 +316,8 @@ struct MigrationState {
      * measured bandwidth, or avail-switchover-bandwidth if specified.
      */
     uint64_t threshold_size;
+    /* Pending data which only moves once stopped, from the last exact query */
+    uint64_t irreducible_pending;
 
     /* params from 'migrate-set-parameters' */
     MigrationParameters parameters;
diff --git a/migration/savevm.c b/migration/savevm.c
index 3b768f4f4e0..f4df8308c2d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1752,13 +1752,23 @@ void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,
     }
 }
 
-void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
-                                     uint64_t *can_postcopy)
+/* Exact pending data which only moves once the guest is stopped */
+static uint64_t savevm_pending_irreducible;
+
+void qemu_savevm_state_pending_add_irreducible(uint64_t size)
+{
+    savevm_pending_irreducible += size;
+}
+
+/* Returns the part of the pending data which only moves once stopped */
+uint64_t qemu_savevm_state_pending_exact(uint64_t *must_precopy,
+                                         uint64_t *can_postcopy)
 {
     SaveStateEntry *se;
 
     *must_precopy = 0;
     *can_postcopy = 0;
+    savevm_pending_irreducible = 0;
 
     QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
         if (!se->ops || !se->ops->state_pending_exact) {
@@ -1771,6 +1781,7 @@ void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
         }
         se->ops->state_pending_exact(se->opaque, must_precopy, can_postcopy);
     }
+    return savevm_pending_irreducible;
 }
 
 void qemu_savevm_state_cleanup(void)
diff --git a/migration/savevm.h b/migration/savevm.h
index 2d5e9c71668..dc37a4ba194 100644
--- a/migration/savevm.h
+++ b/migration/savevm.h
@@ -40,10 +40,11 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
 void qemu_savevm_state_cleanup(void);
 void qemu_savevm_state_complete_postcopy(QEMUFile *f);
 int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
-void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
-                                     uint64_t *can_postcopy);
+uint64_t qemu_savevm_state_pending_exact(uint64_t *must_precopy,
+                                         uint64_t *can_postcopy);
 void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,
                                         uint64_t *can_postcopy);
+void qemu_savevm_state_pending_add_irreducible(uint64_t size);
 int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
 bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);
 void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);

-- 
2.47.1


  parent reply	other threads:[~2026-10-23 16:55 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-23 16:53 [PATCH QEMU HCI-8.1 v5 00/36] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 01/36] VZ: migration/cpr-exec: fix Error leak in preserve_ram() Andrey Drobyshev
2026-10-23 16:58   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 02/36] migration/cpr-exec: restore RAM write access if exec fails Andrey Drobyshev
2026-10-23 16:58   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 03/36] vfio/region: create BAR dma-bufs with O_CLOEXEC Andrey Drobyshev
2026-10-23 17:00   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 04/36] migration/cpr-exec: require a file or exec migration URI Andrey Drobyshev
2026-10-23 17:00   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 05/36] migration: close the CPR state if the outgoing channel fails to open Andrey Drobyshev
2026-10-23 17:01   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 06/36] migration/cpr-exec: close the persisted state if the " Andrey Drobyshev
2026-10-23 17:01   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 07/36] migration: don't refuse a blocker over a migration of another mode Andrey Drobyshev
2026-10-23 17:03   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 08/36] migration: Plug memory leaks after migrate_set_error() Andrey Drobyshev
2026-10-23 17:02   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 09/36] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() Andrey Drobyshev
2026-10-23 17:04   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 10/36] vfio/pci: Reject invalid MSI-X Table and PBA BIR values Andrey Drobyshev
2026-10-23 17:03   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 11/36] vfio/pci: Fix information leak in vfio_rom_read() Andrey Drobyshev
2026-10-23 17:04   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 12/36] vfio/pci: Initialize rom_read_failed in vfio_pci_load_rom() Andrey Drobyshev
2026-10-23 17:05   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 13/36] vfio/pci: Grow buffer in vfio_pci_host_match() Andrey Drobyshev
2026-10-23 17:05   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 14/36] q35: Fix migration of SMRAM state Andrey Drobyshev
2026-10-23 17:07   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 15/36] migration: ensure APIC is loaded prior to VFIO PCI devices Andrey Drobyshev
2026-10-23 17:06   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 16/36] migration: Fix regression of passing error_fatal into vmstate_load_state() Andrey Drobyshev
2026-10-23 17:09   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 17/36] migration: vmstate_save_state_v: fix double error_setg Andrey Drobyshev
2026-10-23 17:11   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 18/36] migration: yank: Move register instance earlier Andrey Drobyshev
2026-10-23 17:13   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 19/36] migration: Free cpr-transfer MigrationAddress along with gsource Andrey Drobyshev
2026-10-23 17:12   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 20/36] migration: Move CPR HUP watch to cpr-transfer.c Andrey Drobyshev
2026-10-23 17:12   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 21/36] migration: Fix crash on second migration when cancel early Andrey Drobyshev
2026-10-23 17:17   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 22/36] kvm: tolerate ioctls after kvm_close() Andrey Drobyshev
2026-10-23 17:17   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 23/36] kvm: fix coalesced MMIO flush racing with kvm_close() Andrey Drobyshev
2026-10-23 17:19   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 24/36] migration/cpr: add cpr_is_in_progress() Andrey Drobyshev
2026-10-23 17:19   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 25/36] vfio/migration: don't migrate device state during CPR Andrey Drobyshev
2026-10-23 17:26   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 26/36] vfio/migration: don't assume the device is running on CPR incoming Andrey Drobyshev
2026-10-23 17:23   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 27/36] vfio/listener: skip dirty page tracking during CPR Andrey Drobyshev
2026-10-23 17:27   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 28/36] VZ: vfio/cpr: don't close KVM on cpr-exec Andrey Drobyshev
2026-10-23 17:29   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 29/36] VZ: migration/cpr-exec: abort cpr-exec if memory can't be preserved Andrey Drobyshev
2026-10-23 17:29   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 30/36] VZ: migration/cpr-exec: take the vhost-net devices back if exec fails Andrey Drobyshev
2026-10-23 17:31   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 31/36] VZ: migration/cpr-exec: don't exec if a vhost-net device can't be released Andrey Drobyshev
2026-10-23 17:30   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 32/36] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Andrey Drobyshev
2026-10-23 17:36   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 33/36] VZ: migration/cpr-exec: allow cpr-exec with VFIO devices #VSTOR-103860 Andrey Drobyshev
2026-10-23 17:32   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 34/36] VZ: vfio/container: lift the CPR blocker for mdev " Andrey Drobyshev
2026-10-23 17:34   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 35/36] VZ: migration: keep the estimate and wait over starved windows #VSTOR-150595 Andrey Drobyshev
2026-10-23 17:38   ` no-reply
2026-10-23 16:54 ` Andrey Drobyshev [this message]
2026-10-23 17:40   ` [PATCH QEMU HCI-8.1 v5 36/36] VZ: migration: don't wait for stop-copy-only device state #VSTOR-150595 no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261023-vfio_v1-v5-36-ba0bf3c6d122@virtuozzo.com \
    --to=andrey.drobyshev@virtuozzo.com \
    --cc=svt-core@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.