Migration pull for rc2
- Zhijian's COLO regression fix (since 10.0) - Matthew's fix to avoid crash on wrong list manipulations - Markus's error report leak fix and cleanups - Peter's qtest changes to merge memory_backend and use_shmem -----BEGIN PGP SIGNATURE----- iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCaSEDHxIccGV0ZXJ4QHJl ZGhhdC5jb20ACgkQO1/MzfOr1wZSAAEAmixKaiIm+w0vp7YiNNTeq22+y6Eo7ran K7g5jCswEH8BAOTPeh7AHBN3L2Zi3tw58Rqyh08kiY/x0/s8DE7sL0wM =3a75 -----END PGP SIGNATURE----- Merge tag 'staging-pull-request' of https://gitlab.com/peterx/qemu into staging Migration pull for rc2 - Zhijian's COLO regression fix (since 10.0) - Matthew's fix to avoid crash on wrong list manipulations - Markus's error report leak fix and cleanups - Peter's qtest changes to merge memory_backend and use_shmem # -----BEGIN PGP SIGNATURE----- # # iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCaSEDHxIccGV0ZXJ4QHJl # ZGhhdC5jb20ACgkQO1/MzfOr1wZSAAEAmixKaiIm+w0vp7YiNNTeq22+y6Eo7ran # K7g5jCswEH8BAOTPeh7AHBN3L2Zi3tw58Rqyh08kiY/x0/s8DE7sL0wM # =3a75 # -----END PGP SIGNATURE----- # gpg: Signature made Fri 21 Nov 2025 04:26:07 PM PST # gpg: using EDDSA key B9184DC20CC457DACF7DD1A93B5FCCCDF3ABD706 # gpg: issuer "peterx@redhat.com" # gpg: Good signature from "Peter Xu <xzpeter@gmail.com>" [unknown] # gpg: aka "Peter Xu <peterx@redhat.com>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B918 4DC2 0CC4 57DA CF7D D1A9 3B5F CCCD F3AB D706 * tag 'staging-pull-request' of https://gitlab.com/peterx/qemu: tests/migration-test: Use MEM_TYPE_MEMFD for memory_backend tests/migration-test: Add MEM_TYPE_SHMEM tests/migration-test: Merge shmem_opts into memory_backend tests/migration-test: Introduce MemType migration/postcopy-ram: Improve error reporting after loadvm failure migration: Use warn_reportf_err() where appropriate migration: Plug memory leaks after migrate_set_error() migration: set correct list pointer when removing notifier migration: Fix transition to COLO state from precopy Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
fb241d0a1f
8 changed files with 121 additions and 60 deletions
|
|
@ -159,11 +159,12 @@ static void cpr_exec_cb(void *opaque)
|
|||
error_report_err(error_copy(err));
|
||||
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
|
||||
migrate_set_error(s, err);
|
||||
error_free(err);
|
||||
err = NULL;
|
||||
|
||||
/* Note, we can go from state COMPLETED to FAILED */
|
||||
migration_call_notifiers(s, MIG_EVENT_PRECOPY_FAILED, NULL);
|
||||
|
||||
err = NULL;
|
||||
if (!migration_block_activate(&err)) {
|
||||
/* error was already reported */
|
||||
error_free(err);
|
||||
|
|
|
|||
|
|
@ -1693,7 +1693,7 @@ void migration_remove_notifier(NotifierWithReturn *notify)
|
|||
{
|
||||
if (notify->notify) {
|
||||
for (MigMode mode = 0; mode < MIG_MODE__MAX; mode++) {
|
||||
migration_blockers[mode] =
|
||||
migration_state_notifiers[mode] =
|
||||
g_slist_remove(migration_state_notifiers[mode], notify);
|
||||
}
|
||||
notify->notify = NULL;
|
||||
|
|
@ -3081,9 +3081,9 @@ static void migration_completion(MigrationState *s)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (migrate_colo() && s->state == MIGRATION_STATUS_ACTIVE) {
|
||||
if (migrate_colo() && s->state == MIGRATION_STATUS_DEVICE) {
|
||||
/* COLO does not support postcopy */
|
||||
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
|
||||
migrate_set_state(&s->state, MIGRATION_STATUS_DEVICE,
|
||||
MIGRATION_STATUS_COLO);
|
||||
} else {
|
||||
migration_completion_end(s);
|
||||
|
|
|
|||
|
|
@ -464,8 +464,8 @@ static void migration_ioc_shutdown_gracefully(QIOChannel *ioc)
|
|||
*/
|
||||
migration_tls_channel_end(ioc, &local_err);
|
||||
if (local_err) {
|
||||
warn_report("Failed to gracefully terminate TLS connection: %s",
|
||||
error_get_pretty(local_err));
|
||||
warn_reportf_err(local_err,
|
||||
"Failed to gracefully terminate TLS connection: ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -964,6 +964,7 @@ bool multifd_send_setup(void)
|
|||
|
||||
if (!multifd_new_send_channel_create(p, &local_err)) {
|
||||
migrate_set_error(s, local_err);
|
||||
error_free(local_err);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -988,6 +989,7 @@ bool multifd_send_setup(void)
|
|||
ret = multifd_send_state->ops->send_setup(p, &local_err);
|
||||
if (ret) {
|
||||
migrate_set_error(s, local_err);
|
||||
error_free(local_err);
|
||||
goto err;
|
||||
}
|
||||
assert(p->iov);
|
||||
|
|
|
|||
|
|
@ -2146,25 +2146,24 @@ static void *postcopy_listen_thread(void *opaque)
|
|||
if (load_res < 0) {
|
||||
qemu_file_set_error(f, load_res);
|
||||
dirty_bitmap_mig_cancel_incoming();
|
||||
error_prepend(&local_err,
|
||||
"loadvm failed during postcopy: %d: ", load_res);
|
||||
if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
|
||||
!migrate_postcopy_ram() && migrate_dirty_bitmaps())
|
||||
{
|
||||
error_report("%s: loadvm failed during postcopy: %d: %s. All states "
|
||||
"are migrated except dirty bitmaps. Some dirty "
|
||||
"bitmaps may be lost, and present migrated dirty "
|
||||
"bitmaps are correctly migrated and valid.",
|
||||
__func__, load_res, error_get_pretty(local_err));
|
||||
g_clear_pointer(&local_err, error_free);
|
||||
error_append_hint(&local_err,
|
||||
"All state is migrated except dirty bitmaps."
|
||||
" Some dirty bitmaps may be lost, but any"
|
||||
" migrated dirty bitmaps are valid.");
|
||||
error_report_err(local_err);
|
||||
} else {
|
||||
/*
|
||||
* Something went fatally wrong and we have a bad state, QEMU will
|
||||
* exit depending on if postcopy-exit-on-error is true, but the
|
||||
* migration cannot be recovered.
|
||||
*/
|
||||
error_prepend(&local_err,
|
||||
"loadvm failed during postcopy: %d: ", load_res);
|
||||
migrate_set_error(migr, local_err);
|
||||
g_clear_pointer(&local_err, error_report_err);
|
||||
error_report_err(local_err);
|
||||
migrate_set_state(&mis->state, mis->state, MIGRATION_STATUS_FAILED);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ static void test_mode_reboot(void)
|
|||
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
|
||||
FILE_TEST_FILENAME);
|
||||
MigrateCommon args = {
|
||||
.start.use_shmem = true,
|
||||
.start.mem_type = MEM_TYPE_SHMEM,
|
||||
.connect_uri = uri,
|
||||
.listen_uri = "defer",
|
||||
.start_hook = migrate_hook_start_mode_reboot,
|
||||
|
|
@ -89,8 +89,7 @@ static void test_mode_transfer_common(bool incoming_defer)
|
|||
.start.opts_source = opts,
|
||||
.start.opts_target = opts_target,
|
||||
.start.defer_target_connect = true,
|
||||
.start.memory_backend = "-object memory-backend-memfd,id=pc.ram,size=%s"
|
||||
" -machine memory-backend=pc.ram",
|
||||
.start.mem_type = MEM_TYPE_MEMFD,
|
||||
.listen_uri = incoming_defer ? "defer" : uri,
|
||||
.connect_channels = connect_channels,
|
||||
.cpr_channel = cpr_channel,
|
||||
|
|
@ -235,8 +234,7 @@ static void test_mode_exec(void)
|
|||
MigrateCommon args = {
|
||||
.start.only_source = true,
|
||||
.start.opts_source = "-machine aux-ram-share=on -nodefaults",
|
||||
.start.memory_backend = "-object memory-backend-memfd,id=pc.ram,size=%s"
|
||||
" -machine memory-backend=pc.ram",
|
||||
.start.mem_type = MEM_TYPE_MEMFD,
|
||||
.connect_uri = uri,
|
||||
.listen_uri = listen_uri,
|
||||
.start_hook = test_mode_exec_start,
|
||||
|
|
|
|||
|
|
@ -260,6 +260,41 @@ static char *test_shmem_path(void)
|
|||
return g_strdup_printf("/dev/shm/qemu-%d", getpid());
|
||||
}
|
||||
|
||||
#define MIG_MEM_ID "mig.mem"
|
||||
|
||||
/* NOTE: caller is responsbile to free the string if returned */
|
||||
static char *migrate_mem_type_get_opts(MemType type, const char *memory_size)
|
||||
{
|
||||
g_autofree char *shmem_path = NULL;
|
||||
g_autofree char *backend = NULL;
|
||||
bool share = true;
|
||||
char *opts;
|
||||
|
||||
switch (type) {
|
||||
case MEM_TYPE_ANON:
|
||||
backend = g_strdup("-object memory-backend-ram");
|
||||
share = false;
|
||||
break;
|
||||
case MEM_TYPE_SHMEM:
|
||||
shmem_path = test_shmem_path();
|
||||
backend = g_strdup_printf("-object memory-backend-file,mem-path=%s",
|
||||
shmem_path);
|
||||
break;
|
||||
case MEM_TYPE_MEMFD:
|
||||
backend = g_strdup("-object memory-backend-memfd");
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
|
||||
opts = g_strdup_printf("%s,id=%s,size=%s,share=%s",
|
||||
backend, MIG_MEM_ID, memory_size,
|
||||
share ? "on" : "off");
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
|
||||
{
|
||||
/* options for source and target */
|
||||
|
|
@ -267,8 +302,7 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
|
|||
gchar *cmd_source = NULL;
|
||||
gchar *cmd_target = NULL;
|
||||
const gchar *ignore_stderr;
|
||||
g_autofree char *shmem_opts = NULL;
|
||||
g_autofree char *shmem_path = NULL;
|
||||
g_autofree char *mem_object = NULL;
|
||||
const char *kvm_opts = NULL;
|
||||
const char *arch = qtest_get_arch();
|
||||
const char *memory_size;
|
||||
|
|
@ -332,19 +366,9 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
|
|||
ignore_stderr = "";
|
||||
}
|
||||
|
||||
if (args->use_shmem) {
|
||||
shmem_path = test_shmem_path();
|
||||
shmem_opts = g_strdup_printf(
|
||||
"-object memory-backend-file,id=mem0,size=%s"
|
||||
",mem-path=%s,share=on -numa node,memdev=mem0",
|
||||
memory_size, shmem_path);
|
||||
}
|
||||
|
||||
if (args->memory_backend) {
|
||||
memory_backend = g_strdup_printf(args->memory_backend, memory_size);
|
||||
} else {
|
||||
memory_backend = g_strdup_printf("-m %s ", memory_size);
|
||||
}
|
||||
mem_object = migrate_mem_type_get_opts(args->mem_type, memory_size);
|
||||
memory_backend = g_strdup_printf("-machine memory-backend=%s %s",
|
||||
MIG_MEM_ID, mem_object);
|
||||
|
||||
if (args->use_dirty_ring) {
|
||||
kvm_opts = ",dirty-ring-size=4096";
|
||||
|
|
@ -366,12 +390,11 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
|
|||
"-name source,debug-threads=on "
|
||||
"%s "
|
||||
"-serial file:%s/src_serial "
|
||||
"%s %s %s %s",
|
||||
"%s %s %s",
|
||||
kvm_opts ? kvm_opts : "",
|
||||
machine, machine_opts,
|
||||
memory_backend, tmpfs,
|
||||
arch_opts ? arch_opts : "",
|
||||
shmem_opts ? shmem_opts : "",
|
||||
args->opts_source ? args->opts_source : "",
|
||||
ignore_stderr);
|
||||
|
||||
|
|
@ -388,13 +411,12 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
|
|||
"%s "
|
||||
"-serial file:%s/dest_serial "
|
||||
"-incoming %s "
|
||||
"%s %s %s %s %s",
|
||||
"%s %s %s %s",
|
||||
kvm_opts ? kvm_opts : "",
|
||||
machine, machine_opts,
|
||||
memory_backend, tmpfs, uri,
|
||||
events,
|
||||
arch_opts ? arch_opts : "",
|
||||
shmem_opts ? shmem_opts : "",
|
||||
args->opts_target ? args->opts_target : "",
|
||||
ignore_stderr);
|
||||
|
||||
|
|
@ -403,6 +425,42 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool migrate_mem_type_prepare(MemType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MEM_TYPE_SHMEM:
|
||||
if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
|
||||
g_test_skip("/dev/shm is not supported");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void migrate_mem_type_cleanup(MemType type)
|
||||
{
|
||||
g_autofree char *shmem_path = NULL;
|
||||
|
||||
switch (type) {
|
||||
case MEM_TYPE_SHMEM:
|
||||
|
||||
/*
|
||||
* Remove shmem file immediately to avoid memory leak in test
|
||||
* failed case. It's valid because QEMU has already opened this
|
||||
* file
|
||||
*/
|
||||
shmem_path = test_shmem_path();
|
||||
unlink(shmem_path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int migrate_start(QTestState **from, QTestState **to, const char *uri,
|
||||
MigrateStart *args)
|
||||
{
|
||||
|
|
@ -410,11 +468,8 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
|
|||
g_autofree gchar *cmd_target = NULL;
|
||||
g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
|
||||
|
||||
if (args->use_shmem) {
|
||||
if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
|
||||
g_test_skip("/dev/shm is not supported");
|
||||
return -1;
|
||||
}
|
||||
if (!migrate_mem_type_prepare(args->mem_type)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dst_state = (QTestMigrationState) { };
|
||||
|
|
@ -441,15 +496,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
|
|||
&dst_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove shmem file immediately to avoid memory leak in test failed case.
|
||||
* It's valid because QEMU has already opened this file
|
||||
*/
|
||||
if (args->use_shmem) {
|
||||
g_autofree char *shmem_path = test_shmem_path();
|
||||
unlink(shmem_path);
|
||||
}
|
||||
|
||||
migrate_mem_type_cleanup(args->mem_type);
|
||||
migrate_start_set_capabilities(*from,
|
||||
args->only_source ? NULL : *to,
|
||||
args);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,25 @@
|
|||
#define FILE_TEST_OFFSET 0x1000
|
||||
#define FILE_TEST_MARKER 'X'
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* Use memory-backend-ram, private mappings
|
||||
*/
|
||||
MEM_TYPE_ANON,
|
||||
/*
|
||||
* Use shmem file (under /dev/shm), shared mappings
|
||||
*/
|
||||
MEM_TYPE_SHMEM,
|
||||
/*
|
||||
* Use anonymous memfd, shared mappings.
|
||||
*
|
||||
* NOTE: this is internally almost the same as MEM_TYPE_SHMEM on Linux,
|
||||
* but only anonymously allocated.
|
||||
*/
|
||||
MEM_TYPE_MEMFD,
|
||||
MEM_TYPE_NUM,
|
||||
} MemType;
|
||||
|
||||
typedef struct MigrationTestEnv {
|
||||
bool has_kvm;
|
||||
bool has_tcg;
|
||||
|
|
@ -102,7 +121,7 @@ typedef struct {
|
|||
* unconditionally, because it means the user would like to be verbose.
|
||||
*/
|
||||
bool hide_stderr;
|
||||
bool use_shmem;
|
||||
MemType mem_type;
|
||||
/* only launch the source process */
|
||||
bool only_source;
|
||||
/* only launch the target process */
|
||||
|
|
@ -115,11 +134,6 @@ typedef struct {
|
|||
bool suspend_me;
|
||||
/* enable OOB QMP capability */
|
||||
bool oob;
|
||||
/*
|
||||
* Format string for the main memory backend, containing one %s where the
|
||||
* size is plugged in. If omitted, "-m %s" is used.
|
||||
*/
|
||||
const char *memory_backend;
|
||||
|
||||
/* Do not connect to target monitor and qtest sockets in qtest_init */
|
||||
bool defer_target_connect;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ static void test_ignore_shared(void)
|
|||
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||
QTestState *from, *to;
|
||||
MigrateStart args = {
|
||||
.use_shmem = true,
|
||||
.mem_type = MEM_TYPE_SHMEM,
|
||||
.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue