migration: Replace switchover_ack_needed SaveVMHandler
A new switchover-ack mechanism that will replace the existing one will be added in the following patches. The new mechanism will not use switchover_ack_needed SaveVMHandler, however, the old mechanism must still be kept for backward compatibility. To keep things clear and decrease API surface of old code, replace switchover_ack_needed SaveVMHandler with a regular function migration_request_switchover_ack(). No functional changes intended. Acked-by: Peter Xu <peterx@redhat.com> Signed-off-by: Avihai Horon <avihaih@nvidia.com> Link: https://lore.kernel.org/qemu-devel/20260706085211.13905-6-avihaih@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
Avihai Horon committed
Jul 6, 2026 at 11:52 UTC
f267196712d530c473f94f8ec83c07f4fe78aba4
7 files changed
+28
-46
docs/devel/migration/vfio.rst
-3
@@ -59,9 +59,6 @@ VFIO implements the device hooks for the iterative approach as follows:
59
* A ``save_live_iterate`` function that reads the VFIO device's data from the
60
vendor driver during iterative pre-copy phase.
61
62
-* A ``switchover_ack_needed`` function that checks if the VFIO device uses
63
- "switchover-ack" migration capability when this capability is enabled.
64
-
62
* A ``switchover_start`` function that in the multifd mode starts a thread that
63
reassembles the multifd received data and loads it in-order into the device.
64
In the non-multifd mode this function is a NOP.
hw/vfio/migration.c
+10
-8
@@ -487,6 +487,14 @@ static bool vfio_precopy_supported(VFIODevice *vbasedev)
487
return migration->mig_flags & VFIO_MIGRATION_PRE_COPY;
488
}
489
490
+static void vfio_request_switchover_ack(VFIODevice *vbasedev)
491
+{
492
+ if (vfio_precopy_supported(vbasedev)) {
493
+ /* Precopy support implies switchover-ack is needed */
494
+ migration_request_switchover_ack(vbasedev->name);
495
+ }
496
+}
497
+
498
/* ---------------------------------------------------------------------- */
499
500
static int vfio_save_prepare(void *opaque, Error **errp)
@@ -776,6 +784,8 @@ static int vfio_load_setup(QEMUFile *f, void *opaque, Error **errp)
784
return ret;
785
}
786
787
+ vfio_request_switchover_ack(vbasedev);
788
+
789
return 0;
790
}
791
@@ -874,13 +884,6 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id)
884
return ret;
885
}
886
877
-static bool vfio_switchover_ack_needed(void *opaque)
878
-{
879
- VFIODevice *vbasedev = opaque;
880
-
881
- return vfio_precopy_supported(vbasedev);
882
-}
883
-
887
static int vfio_switchover_start(void *opaque)
888
{
889
VFIODevice *vbasedev = opaque;
@@ -904,7 +907,6 @@ static const SaveVMHandlers savevm_vfio_handlers = {
907
.load_setup = vfio_load_setup,
908
.load_cleanup = vfio_load_cleanup,
909
.load_state = vfio_load_state,
907
- .switchover_ack_needed = vfio_switchover_ack_needed,
910
/*
911
* Multifd support
912
*/
include/migration/misc.h
+2
@@ -159,4 +159,6 @@ bool multifd_device_state_save_thread_should_exit(void);
159
void multifd_abort_device_state_save_threads(void);
160
bool multifd_join_device_state_save_threads(void);
161
162
+void migration_request_switchover_ack(const char *requester);
163
+
164
#endif
include/migration/register.h
-13
@@ -302,19 +302,6 @@ typedef struct SaveVMHandlers {
302
*/
303
int (*resume_prepare)(MigrationState *s, void *opaque);
304
305
- /**
306
- * @switchover_ack_needed
307
- *
308
- * Checks if switchover ack should be used. Called only on
309
- * destination.
310
- *
311
- * @opaque: data pointer passed to register_savevm_live()
312
- *
313
- * Returns true if switchover ack should be used and false
314
- * otherwise
315
- */
316
- bool (*switchover_ack_needed)(void *opaque);
317
-
305
/**
306
* @switchover_start
307
*
migration/migration.c
+15
@@ -2202,6 +2202,21 @@ void migration_rp_kick(MigrationState *s)
2202
qemu_sem_post(&s->rp_state.rp_sem);
2203
}
2204
2205
+/* This is called only on destination side */
2206
+void migration_request_switchover_ack(const char *requester)
2207
+{
2208
+ MigrationIncomingState *mis = migration_incoming_get_current();
2209
+
2210
+ if (!migrate_switchover_ack()) {
2211
+ return;
2212
+ }
2213
+
2214
+ mis->switchover_ack_pending_num++;
2215
+
2216
+ trace_migration_request_switchover_ack(requester,
2217
+ mis->switchover_ack_pending_num);
2218
+}
2219
+
2220
static struct rp_cmd_args {
2221
ssize_t len; /* -1 = variable */
2222
const char *name;
migration/savevm.c
-21
@@ -2800,23 +2800,6 @@ static int qemu_loadvm_state_header(QEMUFile *f, Error **errp)
2800
return 0;
2801
}
2802
2803
-static void qemu_loadvm_state_switchover_ack_needed(MigrationIncomingState *mis)
2804
-{
2805
- SaveStateEntry *se;
2806
-
2807
- QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
2808
- if (!se->ops || !se->ops->switchover_ack_needed) {
2809
- continue;
2810
- }
2811
-
2812
- if (se->ops->switchover_ack_needed(se->opaque)) {
2813
- mis->switchover_ack_pending_num++;
2814
- }
2815
- }
2816
-
2817
- trace_loadvm_state_switchover_ack_needed(mis->switchover_ack_pending_num);
2818
-}
2819
-
2803
static int qemu_loadvm_state_setup(QEMUFile *f, Error **errp)
2804
{
2805
ERRP_GUARD();
@@ -3078,10 +3061,6 @@ int qemu_loadvm_state(QEMUFile *f, Error **errp)
3061
return -EINVAL;
3062
}
3063
3081
- if (migrate_switchover_ack()) {
3082
- qemu_loadvm_state_switchover_ack_needed(mis);
3083
- }
3084
-
3064
cpu_synchronize_all_pre_loadvm();
3065
3066
ret = qemu_loadvm_state_main(f, mis, errp);
migration/trace-events
+1
-1
@@ -8,7 +8,6 @@ qemu_loadvm_state_post_main(int ret) "%d"
8
qemu_loadvm_state_section_startfull(uint32_t section_id, const char *idstr, uint32_t instance_id, uint32_t version_id) "%u(%s) %u %u"
9
qemu_savevm_send_packaged(void) ""
10
qemu_savevm_query_pending(bool exact, bool final, uint64_t precopy, uint64_t stopcopy, uint64_t postcopy, uint64_t total) "exact=%d, final=%d, precopy=%"PRIu64", stopcopy=%"PRIu64", postcopy=%"PRIu64", total=%"PRIu64
11
-loadvm_state_switchover_ack_needed(unsigned int switchover_ack_pending_num) "Switchover ack pending num=%u"
11
loadvm_state_setup(void) ""
12
loadvm_state_cleanup(void) ""
13
loadvm_handle_cmd_packaged(unsigned int length) "%u"
@@ -199,6 +198,7 @@ process_incoming_migration_co_postcopy_end_main(void) ""
198
postcopy_preempt_enabled(bool value) "%d"
199
migration_precopy_complete(void) ""
200
migration_call_notifiers(int type) "type=%d"
201
+migration_request_switchover_ack(const char *requester, unsigned int switchover_ack_pending_num) "Requester %s, switchover_ack_pending_num %u"
202
203
# migration-stats
204
migration_transferred_bytes(uint64_t qemu_file, uint64_t multifd, uint64_t rdma) "qemu_file %" PRIu64 " multifd %" PRIu64 " RDMA %" PRIu64