@samitouri / QOSamiQemu / commits / ef1f718450

migration: update capability conflict test for postcopy-ram+mapped-ram

Remove the test test_validate_caps_pair, which asserted postcopy-ram and mapped-ram capabilities cannot be active together. The new fast snapshot load feature is exactly this pair of capabilities active together, with the following patches in this series, this combination will now supported and be functional. Remove the capability check that rejected mapped-ram and postcopy-ram being set simultaneously, as this combination now corresponds to fast snapshot load. Add a capability check against setting multifd when configured for fast snapshot load as it is not supported yet. Also add capability check against setting postcopy-preempt as it is incompatible. Add infrastructure to check postcopy_notifier_list being empty in capaility checking to block vhost-user with fast snapshot load as it is not supported. Add a check to bail in migrate_prepare to prevent unexpected usage when fast snapshot load is enabled. A smoke test exercising this feature has been added further in this series. Signed-off-by: Aadeshveer Singh <aadeshveer07@gmail.com> Signed-off-by: Peter Xu <peterx@redhat.com> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Aadeshveer Singh committed Aug 16, 2026 at 23:16 UTC ef1f718450947e22e9efba6afbd6cf67e90f65b7
7 files changed +37 -54
include/qemu/notify.h
+2
@@ -75,4 +75,6 @@ void notifier_with_return_remove(NotifierWithReturn *notifier);
75 int notifier_with_return_list_notify(NotifierWithReturnList *list,
76 void *data, Error **errp);
77
78 +bool notifier_with_return_list_empty(NotifierWithReturnList *list);
79 +
80 #endif
migration/migration.c
+6
@@ -2048,6 +2048,12 @@ static bool migrate_prepare(MigrationState *s, bool resume, Error **errp)
2048 error_setg(errp, "Cannot use compression with mapped-ram");
2049 return false;
2050 }
2051 +
2052 + if (migrate_postcopy_ram()) {
2053 + error_setg(errp, "Cannot migrate with fast snapshot load "
2054 + "enabled(mapped-ram + postcopy-ram)");
2055 + return false;
2056 + }
2057 }
2058
2059 if (migrate_mode_is_cpr()) {
migration/options.c
+18 -2
@@ -736,10 +736,26 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
736 "Mapped-ram migration is incompatible with xbzrle");
737 return false;
738 }
739 + }
740 +
741 + if (new_caps[MIGRATION_CAPABILITY_MAPPED_RAM] &&
742 + new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
743 + if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
744 + error_setg(errp,
745 + "Multifd is not supported with fast snapshot load");
746 + return false;
747 + }
748 +
749 + if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
750 + error_setg(
751 + errp,
752 + "Postcopy Preempt is incompatible with fast snapshot load");
753 + return false;
754 + }
755
740 - if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
756 + if (!postcopy_notifier_list_empty()) {
757 error_setg(errp,
742 - "Mapped-ram migration is incompatible with postcopy");
758 + "vhost-user is not supported with fast snapshot load");
759 return false;
760 }
761 }
migration/postcopy-ram.c
+5
@@ -84,6 +84,11 @@ int postcopy_notify(enum PostcopyNotifyReason reason, Error **errp)
84 &pnd, errp);
85 }
86
87 +bool postcopy_notifier_list_empty(void)
88 +{
89 + return notifier_with_return_list_empty(&postcopy_notifier_list);
90 +}
91 +
92 /*
93 * NOTE: this routine is not thread safe, we can't call it concurrently. But it
94 * should be good enough for migration's purposes.
migration/postcopy-ram.h
+1
@@ -136,6 +136,7 @@ void postcopy_add_notifier(NotifierWithReturn *nn);
136 void postcopy_remove_notifier(NotifierWithReturn *n);
137 /* Call the notifier list set by postcopy_add_start_notifier */
138 int postcopy_notify(enum PostcopyNotifyReason reason, Error **errp);
139 +bool postcopy_notifier_list_empty(void);
140
141 void postcopy_thread_create(MigrationIncomingState *mis,
142 QemuThread *thread, const char *name,
tests/qtest/migration/misc-tests.c
-52
@@ -201,55 +201,6 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
201 migrate_end(from, to, false);
202 }
203
204 -static void validate_caps_pair(QTestState *from,
205 - const char *first_capability,
206 - const char *second_capability,
207 - const char *expected_error)
208 -{
209 - QDict *rsp;
210 - const char *error_desc;
211 -
212 - migrate_set_capability(from, first_capability, true);
213 -
214 - rsp = qtest_qmp_assert_failure_ref(
215 - from,
216 - "{ 'execute': 'migrate-set-capabilities',"
217 - " 'arguments': { 'capabilities': [ { "
218 - " 'capability': %s, 'state': true } ] } }",
219 - second_capability);
220 -
221 - error_desc = qdict_get_str(rsp, "desc");
222 - g_assert_cmpstr(error_desc, ==, expected_error);
223 - qobject_unref(rsp);
224 -
225 - migrate_set_capability(from, first_capability, false);
226 -}
227 -
228 -static void test_validate_caps_pair(char *test_path, MigrateCommon *args)
229 -{
230 - g_autofree char *serial_path = g_strconcat(tmpfs, "/src_serial", NULL);
231 - g_autofree char *cap_pair = g_path_get_basename(test_path);
232 - QTestState *from, *to;
233 -
234 - args->start.hide_stderr = true;
235 - args->start.only_source = true;
236 -
237 - if (migrate_start(&from, &to, &args->start)) {
238 - return;
239 - }
240 -
241 - if (g_str_equal(cap_pair, "mapped_ram_postcopy")) {
242 - const char *error =
243 - "Mapped-ram migration is incompatible with postcopy";
244 -
245 - validate_caps_pair(from, "mapped-ram", "postcopy-ram", error);
246 - validate_caps_pair(from, "postcopy-ram", "mapped-ram", error);
247 - }
248 -
249 - qtest_quit(from);
250 - unlink(serial_path);
251 -}
252 -
204 static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
205 {
206 args->uri = "tcp:127.0.0.1:0",
@@ -309,7 +260,4 @@ void migration_test_add_misc(MigrationTestEnv *env)
260 test_validate_uri_channels_both_set);
261 migration_test_add("/migration/validate_uri/channels/none_set",
262 test_validate_uri_channels_none_set);
312 - migration_test_add_suffix("/migration/validate_caps/",
313 - "mapped_ram_postcopy",
314 - test_validate_caps_pair);
263 }
util/notify.c
+5
@@ -75,3 +75,8 @@ int notifier_with_return_list_notify(NotifierWithReturnList *list, void *data,
75 }
76 return ret;
77 }
78 +
79 +bool notifier_with_return_list_empty(NotifierWithReturnList *list)
80 +{
81 + return QLIST_EMPTY(&list->notifiers);
82 +}