qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V1 00/11] cpr-exec test
@ 2025-09-19 14:12 Steve Sistare
  2025-09-19 14:12 ` [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary Steve Sistare
                   ` (11 more replies)
  0 siblings, 12 replies; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Add a migration test for cpr-exec mode.
Depends on the patch series "Live update: cpr-exec".

Steve Sistare (11):
  tests/qtest: export qtest_qemu_binary
  tests/qtest: qtest_qemu_args
  tests/qtest: qtest_create_test_state
  tests/qtest: qtest_qemu_spawn_func
  tests/qtest: qtest_init_after_exec
  migration-test: only_source option
  migration-test: shm path accessor
  migration-test: misc exports
  migration-test: migrate_args
  migration-test: strv parameter
  migration-test: test cpr-exec

 tests/qtest/libqtest.h                |  25 +++++++
 tests/qtest/migration/bootfile.h      |   1 +
 tests/qtest/migration/framework.h     |   8 +++
 tests/qtest/migration/migration-qmp.h |   2 +
 tests/qtest/libqtest.c                | 108 ++++++++++++++++++++----------
 tests/qtest/migration/bootfile.c      |   5 ++
 tests/qtest/migration/cpr-tests.c     | 120 ++++++++++++++++++++++++++++++++++
 tests/qtest/migration/framework.c     | 102 ++++++++++++++++++-----------
 tests/qtest/migration/migration-qmp.c |  16 +++++
 9 files changed, 317 insertions(+), 70 deletions(-)

-- 
1.8.3.1



^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 14:47   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 02/11] tests/qtest: qtest_qemu_args Steve Sistare
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/libqtest.h | 9 +++++++++
 tests/qtest/libqtest.c | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index b3f2e7f..6d3199f 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -48,6 +48,15 @@ QTestState *qtest_initf(const char *fmt, ...) G_GNUC_PRINTF(1, 2);
 QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
 
 /**
+ * qtest_qemu_binary:
+ * @var: environment variable name
+ *
+ * Look up @var and return its value as the qemu binary path.
+ * If @var is NULL, look up  the default var name.
+ */
+const char *qtest_qemu_binary(const char *var);
+
+/**
  * qtest_init:
  * @extra_args: other arguments to pass to QEMU.  CAUTION: these
  * arguments are subject to word splitting and shell evaluation.
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index f3d4e08..6f76be1 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -357,7 +357,7 @@ void qtest_remove_abrt_handler(void *data)
     }
 }
 
-static const char *qtest_qemu_binary(const char *var)
+const char *qtest_qemu_binary(const char *var)
 {
     const char *qemu_bin;
 
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 02/11] tests/qtest: qtest_qemu_args
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
  2025-09-19 14:12 ` [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 14:51   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 03/11] tests/qtest: qtest_create_test_state Steve Sistare
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Define an accessor that returns all the arguments used to exec QEMU.
Collect the arguments that were passed to qtest_spawn_qemu, plus the trace
arguments that were composed inside qtest_spawn_qemu, and move them to a
new function qtest_qemu_args.

This will be needed to test the cpr-exec migration mode.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/libqtest.h |  8 ++++++++
 tests/qtest/libqtest.c | 54 +++++++++++++++++++++++++++++---------------------
 2 files changed, 39 insertions(+), 23 deletions(-)

diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index 6d3199f..a164f58 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -57,6 +57,14 @@ QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
 const char *qtest_qemu_binary(const char *var);
 
 /**
+ * qtest_qemu_args:
+ * @extra_args: Other arguments to pass to QEMU.
+ *
+ * Return the command line used to start QEMU, sans binary.
+ */
+gchar *qtest_qemu_args(const char *extra_args);
+
+/**
  * qtest_init:
  * @extra_args: other arguments to pass to QEMU.  CAUTION: these
  * arguments are subject to word splitting and shell evaluation.
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 6f76be1..551bc8c 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -409,20 +409,12 @@ static pid_t qtest_create_process(char *cmd)
 }
 #endif /* _WIN32 */
 
-static QTestState *G_GNUC_PRINTF(2, 3) qtest_spawn_qemu(const char *qemu_bin,
-                                                        const char *fmt, ...)
+static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
 {
-    va_list ap;
     QTestState *s = g_new0(QTestState, 1);
-    const char *trace = g_getenv("QTEST_TRACE");
-    g_autofree char *tracearg = trace ?
-        g_strdup_printf("-trace %s ", trace) : g_strdup("");
     g_autoptr(GString) command = g_string_new("");
 
-    va_start(ap, fmt);
-    g_string_append_printf(command, CMD_EXEC "%s %s", qemu_bin, tracearg);
-    g_string_append_vprintf(command, fmt, ap);
-    va_end(ap);
+    g_string_printf(command, CMD_EXEC "%s %s", qemu_bin, args);
 
     qtest_add_abrt_handler(kill_qemu_hook_func, s);
 
@@ -466,6 +458,33 @@ static char *qtest_socket_path(const char *suffix)
     return g_strdup_printf("%s/qtest-%d.%s", g_get_tmp_dir(), getpid(), suffix);
 }
 
+gchar *qtest_qemu_args(const char *extra_args)
+{
+    g_autofree gchar *socket_path = qtest_socket_path("sock");
+    g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp");
+    const char *trace = g_getenv("QTEST_TRACE");
+    g_autofree char *tracearg = trace ? g_strdup_printf("-trace %s ", trace) :
+                                        g_strdup("");
+    gchar *args = g_strdup_printf(
+                      "%s"
+                      "-qtest unix:%s "
+                      "-qtest-log %s "
+                      "-chardev socket,path=%s,id=char0 "
+                      "-mon chardev=char0,mode=control "
+                      "-display none "
+                      "-audio none "
+                      "%s"
+                      " -accel qtest",
+
+                      tracearg,
+                      socket_path,
+                      getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL,
+                      qmp_socket_path,
+                      extra_args ?: "");
+
+    return args;
+}
+
 static QTestState *qtest_init_internal(const char *qemu_bin,
                                        const char *extra_args,
                                        bool do_connect)
@@ -474,6 +493,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
     int sock, qmpsock, i;
     g_autofree gchar *socket_path = qtest_socket_path("sock");
     g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp");
+    g_autofree gchar *args = qtest_qemu_args(extra_args);
 
     /*
      * It's possible that if an earlier test run crashed it might
@@ -488,19 +508,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
     sock = init_socket(socket_path);
     qmpsock = init_socket(qmp_socket_path);
 
-    s = qtest_spawn_qemu(qemu_bin,
-                         "-qtest unix:%s "
-                         "-qtest-log %s "
-                         "-chardev socket,path=%s,id=char0 "
-                         "-mon chardev=char0,mode=control "
-                         "-display none "
-                         "-audio none "
-                         "%s"
-                         " -accel qtest",
-                         socket_path,
-                         getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL,
-                         qmp_socket_path,
-                         extra_args ?: "");
+    s = qtest_spawn_qemu(qemu_bin, args);
 
     qtest_client_set_rx_handler(s, qtest_client_socket_recv_line);
     qtest_client_set_tx_handler(s, qtest_client_socket_send);
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 03/11] tests/qtest: qtest_create_test_state
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
  2025-09-19 14:12 ` [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary Steve Sistare
  2025-09-19 14:12 ` [PATCH V1 02/11] tests/qtest: qtest_qemu_args Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 14:52   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 04/11] tests/qtest: qtest_qemu_spawn_func Steve Sistare
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Refactor qtest_spawn_qemu and create a subroutine to create a QTestState
object, to be used in a subsequent patch.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/libqtest.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 551bc8c..3fa9317 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -409,22 +409,29 @@ static pid_t qtest_create_process(char *cmd)
 }
 #endif /* _WIN32 */
 
-static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
+static QTestState *qtest_create_test_state(int pid)
 {
     QTestState *s = g_new0(QTestState, 1);
+
+    s->qemu_pid = pid;
+    qtest_add_abrt_handler(kill_qemu_hook_func, s);
+    return s;
+}
+
+static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
+{
+    int pid;
     g_autoptr(GString) command = g_string_new("");
 
     g_string_printf(command, CMD_EXEC "%s %s", qemu_bin, args);
 
-    qtest_add_abrt_handler(kill_qemu_hook_func, s);
-
     if (!silence_spawn_log) {
         g_test_message("starting QEMU: %s", command->str);
     }
 
 #ifndef _WIN32
-    s->qemu_pid = fork();
-    if (s->qemu_pid == 0) {
+    pid = fork();
+    if (pid == 0) {
 #ifdef __linux__
         /*
          * Although we register a ABRT handler to kill off QEMU
@@ -447,10 +454,10 @@ static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
         exit(1);
     }
 #else
-    s->qemu_pid = qtest_create_process(command->str);
+    pid = qtest_create_process(command->str);
 #endif /* _WIN32 */
 
-    return s;
+    return qtest_create_test_state(pid);
 }
 
 static char *qtest_socket_path(const char *suffix)
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 04/11] tests/qtest: qtest_qemu_spawn_func
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (2 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 03/11] tests/qtest: qtest_create_test_state Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 14:57   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 05/11] tests/qtest: qtest_init_after_exec Steve Sistare
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Allow the qtest_qemu_spawn caller to pass the function to be called
to perform the spawn.  The opaque argument is needed by a new spawn
function in a subsequent patch.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/libqtest.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 3fa9317..d97144e 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -418,7 +418,8 @@ static QTestState *qtest_create_test_state(int pid)
     return s;
 }
 
-static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
+static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args,
+                                    void *opaque)
 {
     int pid;
     g_autoptr(GString) command = g_string_new("");
@@ -492,9 +493,15 @@ gchar *qtest_qemu_args(const char *extra_args)
     return args;
 }
 
+typedef QTestState *(*qtest_qemu_spawn_func)(const char *qemu_bin,
+                                             const char *extra_args,
+                                             void *opaque);
+
 static QTestState *qtest_init_internal(const char *qemu_bin,
                                        const char *extra_args,
-                                       bool do_connect)
+                                       bool do_connect,
+                                       qtest_qemu_spawn_func spawn,
+                                       void *opaque)
 {
     QTestState *s;
     int sock, qmpsock, i;
@@ -515,7 +522,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
     sock = init_socket(socket_path);
     qmpsock = init_socket(qmp_socket_path);
 
-    s = qtest_spawn_qemu(qemu_bin, args);
+    s = spawn(qemu_bin, args, opaque);
 
     qtest_client_set_rx_handler(s, qtest_client_socket_recv_line);
     qtest_client_set_tx_handler(s, qtest_client_socket_send);
@@ -570,7 +577,8 @@ void qtest_connect(QTestState *s)
 
 QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
 {
-    return qtest_init_internal(qtest_qemu_binary(NULL), extra_args, true);
+    return qtest_init_internal(qtest_qemu_binary(NULL), extra_args, true,
+                               qtest_spawn_qemu, NULL);
 }
 
 void qtest_qmp_handshake(QTestState *s, QList *capabilities)
@@ -593,7 +601,7 @@ QTestState *qtest_init_ext(const char *var, const char *extra_args,
                            QList *capabilities, bool do_connect)
 {
     QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args,
-                                        do_connect);
+                                        do_connect, qtest_spawn_qemu, NULL);
 
     if (do_connect) {
         qtest_qmp_handshake(s, capabilities);
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 05/11] tests/qtest: qtest_init_after_exec
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (3 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 04/11] tests/qtest: qtest_qemu_spawn_func Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 14:59   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 06/11] migration-test: only_source option Steve Sistare
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Define a function to create a QTestState object representing the state
of QEMU after old QEMU exec's new QEMU.  This is needed for testing
the cpr-exec migration mode.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/libqtest.h |  8 ++++++++
 tests/qtest/libqtest.c | 19 +++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index a164f58..ce6b9b0 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -57,6 +57,14 @@ QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
 const char *qtest_qemu_binary(const char *var);
 
 /**
+ * qtest_init_after_exec:
+ * @from: the previous QEMU state
+ *
+ * Return a test state representing new QEMU after @from exec's it.
+ */
+QTestState *qtest_init_after_exec(QTestState *from);
+
+/**
  * qtest_qemu_args:
  * @extra_args: Other arguments to pass to QEMU.
  *
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index d97144e..3522d75 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -615,6 +615,25 @@ QTestState *qtest_init_ext(const char *var, const char *extra_args,
     return s;
 }
 
+static QTestState *qtest_attach_qemu(const char *qemu_bin,
+                                     const char *extra_args,
+                                     void *opaque)
+{
+    int pid = *(int *)opaque;
+    return qtest_create_test_state(pid);
+}
+
+QTestState *qtest_init_after_exec(QTestState *from)
+{
+    void *opaque = (void *)&from->qemu_pid;
+    QTestState *s;
+
+    s = qtest_init_internal(NULL, NULL, true, qtest_attach_qemu, opaque);
+    from->qemu_pid = -1;
+    qtest_qmp_handshake(s, NULL);
+    return s;
+}
+
 QTestState *qtest_init(const char *extra_args)
 {
     return qtest_init_ext(NULL, extra_args, NULL, true);
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 06/11] migration-test: only_source option
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (4 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 05/11] tests/qtest: qtest_init_after_exec Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 20:27   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 07/11] migration-test: shm path accessor Steve Sistare
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Add the only_source option, analogous to only_target.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/migration/framework.h |  2 ++
 tests/qtest/migration/framework.c | 24 +++++++++++++++---------
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 01e425e..f1bb9d4 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -103,6 +103,8 @@ typedef struct {
      */
     bool hide_stderr;
     bool use_shmem;
+    /* only launch the source process */
+    bool only_source;
     /* only launch the target process */
     bool only_target;
     /* Use dirty ring if true; dirty logging otherwise */
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 407c902..9564293 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -234,7 +234,7 @@ static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
      * to mimic as closer as that.
      */
     migrate_set_capability(from, "events", true);
-    if (!args->defer_target_connect) {
+    if (!args->defer_target_connect && to) {
         migrate_set_capability(to, "events", true);
     }
 
@@ -246,8 +246,10 @@ static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
     if (args->caps[MIGRATION_CAPABILITY_MULTIFD]) {
         migrate_set_parameter_int(from, "multifd-channels",
                                   MULTIFD_TEST_CHANNELS);
-        migrate_set_parameter_int(to, "multifd-channels",
-                                  MULTIFD_TEST_CHANNELS);
+        if (to) {
+            migrate_set_parameter_int(to, "multifd-channels",
+                                      MULTIFD_TEST_CHANNELS);
+        }
     }
 
     return;
@@ -410,11 +412,13 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
                                  shmem_opts ? shmem_opts : "",
                                  args->opts_target ? args->opts_target : "",
                                  ignore_stderr);
-    *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
-                         !args->defer_target_connect);
-    qtest_qmp_set_event_callback(*to,
-                                 migrate_watch_for_events,
-                                 &dst_state);
+    if (!args->only_source) {
+        *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
+                             !args->defer_target_connect);
+        qtest_qmp_set_event_callback(*to,
+                                     migrate_watch_for_events,
+                                     &dst_state);
+    }
 
     /*
      * Remove shmem file immediately to avoid memory leak in test failed case.
@@ -424,7 +428,9 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
         unlink(shmem_path);
     }
 
-    migrate_start_set_capabilities(*from, *to, args);
+    migrate_start_set_capabilities(*from,
+                                   args->only_source ? NULL : *to,
+                                   args);
 
     return 0;
 }
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 07/11] migration-test: shm path accessor
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (5 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 06/11] migration-test: only_source option Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 20:28   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 08/11] migration-test: misc exports Steve Sistare
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Define an accessor for the shm path.  It will be referenced from
multiple sites in a subsequent patch.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/migration/framework.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 9564293..9d04f36 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -255,6 +255,11 @@ static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
     return;
 }
 
+static char *test_shmem_path(void)
+{
+    return g_strdup_printf("/dev/shm/qemu-%d", getpid());
+}
+
 int migrate_start(QTestState **from, QTestState **to, const char *uri,
                   MigrateStart *args)
 {
@@ -342,7 +347,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     }
 
     if (args->use_shmem) {
-        shmem_path = g_strdup_printf("/dev/shm/qemu-%d", getpid());
+        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",
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 08/11] migration-test: misc exports
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (6 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 07/11] migration-test: shm path accessor Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-19 14:12 ` [PATCH V1 09/11] migration-test: migrate_args Steve Sistare
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Export misc definitions needed by the cpr-exec test.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/migration/bootfile.h  | 1 +
 tests/qtest/migration/framework.h | 4 ++++
 tests/qtest/migration/bootfile.c  | 5 +++++
 tests/qtest/migration/framework.c | 7 +++++--
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/tests/qtest/migration/bootfile.h b/tests/qtest/migration/bootfile.h
index 6d6a673..96e784b 100644
--- a/tests/qtest/migration/bootfile.h
+++ b/tests/qtest/migration/bootfile.h
@@ -35,5 +35,6 @@
 
 void bootfile_delete(void);
 char *bootfile_create(const char *arch, const char *dir, bool suspend_me);
+char *bootfile_get(void);
 
 #endif /* BOOTFILE_H */
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index f1bb9d4..7ff3187 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -18,6 +18,9 @@
 #define FILE_TEST_OFFSET 0x1000
 #define FILE_TEST_MARKER 'X'
 
+#define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
+#define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST"
+
 typedef struct MigrationTestEnv {
     bool has_kvm;
     bool has_tcg;
@@ -237,6 +240,7 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
 
 typedef struct QTestMigrationState QTestMigrationState;
 QTestMigrationState *get_src(void);
+QTestMigrationState *get_dst(void);
 
 #ifdef CONFIG_GNUTLS
 void migration_test_add_tls(MigrationTestEnv *env);
diff --git a/tests/qtest/migration/bootfile.c b/tests/qtest/migration/bootfile.c
index fac059d..479c432 100644
--- a/tests/qtest/migration/bootfile.c
+++ b/tests/qtest/migration/bootfile.c
@@ -68,3 +68,8 @@ char *bootfile_create(const char *arch, const char *dir, bool suspend_me)
 
     return bootpath;
 }
+
+char *bootfile_get(void)
+{
+    return bootpath;
+}
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 9d04f36..8f9e359 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -28,8 +28,6 @@
 
 
 #define QEMU_VM_FILE_MAGIC 0x5145564d
-#define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
-#define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST"
 #define MULTIFD_TEST_CHANNELS 4
 
 unsigned start_address;
@@ -1005,6 +1003,11 @@ QTestMigrationState *get_src(void)
     return &src_state;
 }
 
+QTestMigrationState *get_dst(void)
+{
+    return &dst_state;
+}
+
 MigrationTestEnv *migration_get_env(void)
 {
     static MigrationTestEnv *env;
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 09/11] migration-test: migrate_args
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (7 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 08/11] migration-test: misc exports Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-29 20:32   ` Fabiano Rosas
  2025-09-30 19:51   ` Fabiano Rosas
  2025-09-19 14:12 ` [PATCH V1 10/11] migration-test: strv parameter Steve Sistare
                   ` (2 subsequent siblings)
  11 siblings, 2 replies; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Define the subroutine migrate_args to return the arguments that are
used to exec the source or target qemu process.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/migration/framework.h |  2 ++
 tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
 2 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 7ff3187..51a8a7e 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -226,6 +226,8 @@ typedef struct {
 void wait_for_serial(const char *side);
 void migrate_prepare_for_dirty_mem(QTestState *from);
 void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
+
+void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
 int migrate_start(QTestState **from, QTestState **to, const char *uri,
                   MigrateStart *args);
 void migrate_end(QTestState *from, QTestState *to, bool test_dest);
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 8f9e359..2dfb1ee 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -258,13 +258,12 @@ static char *test_shmem_path(void)
     return g_strdup_printf("/dev/shm/qemu-%d", getpid());
 }
 
-int migrate_start(QTestState **from, QTestState **to, const char *uri,
-                  MigrateStart *args)
+void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
 {
     /* options for source and target */
     g_autofree gchar *arch_opts = NULL;
-    g_autofree gchar *cmd_source = NULL;
-    g_autofree gchar *cmd_target = NULL;
+    gchar *cmd_source = NULL;
+    gchar *cmd_target = NULL;
     const gchar *ignore_stderr;
     g_autofree char *shmem_opts = NULL;
     g_autofree char *shmem_path = NULL;
@@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     const char *memory_size;
     const char *machine_alias, *machine_opts = "";
     g_autofree char *machine = NULL;
-    const char *bootpath;
-    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
+    const char *bootpath = bootfile_get();
     g_autofree char *memory_backend = NULL;
     const char *events;
 
-    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;
-        }
-    }
-
-    dst_state = (QTestMigrationState) { };
-    src_state = (QTestMigrationState) { };
-    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
-    src_state.suspend_me = args->suspend_me;
-
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
         memory_size = "150M";
 
@@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     if (!qtest_has_machine(machine_alias)) {
         g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
         g_test_skip(msg);
-        return -1;
+        return;
     }
 
     machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
@@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
                                  shmem_opts ? shmem_opts : "",
                                  args->opts_source ? args->opts_source : "",
                                  ignore_stderr);
-    if (!args->only_target) {
-        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
-        qtest_qmp_set_event_callback(*from,
-                                     migrate_watch_for_events,
-                                     &src_state);
-    }
 
     /*
      * If the monitor connection is deferred, enable events on the command line
@@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
                                  shmem_opts ? shmem_opts : "",
                                  args->opts_target ? args->opts_target : "",
                                  ignore_stderr);
+
+    *from = cmd_source;
+    *to = cmd_target;
+}
+
+int migrate_start(QTestState **from, QTestState **to, const char *uri,
+                  MigrateStart *args)
+{
+    g_autofree gchar *cmd_source = NULL;
+    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;
+        }
+    }
+
+    dst_state = (QTestMigrationState) { };
+    src_state = (QTestMigrationState) { };
+    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
+    src_state.suspend_me = args->suspend_me;
+
+    migrate_args(&cmd_source, &cmd_target, uri, args);
+
+    if (!args->only_target) {
+        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
+        qtest_qmp_set_event_callback(*from,
+                                     migrate_watch_for_events,
+                                     &src_state);
+    }
+
     if (!args->only_source) {
         *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
                              !args->defer_target_connect);
@@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
      * 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);
     }
 
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 10/11] migration-test: strv parameter
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (8 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 09/11] migration-test: migrate_args Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-19 14:12 ` [PATCH V1 11/11] migration-test: test cpr-exec Steve Sistare
  2025-09-30 14:35 ` [PATCH V1 00/11] cpr-exec test Fabiano Rosas
  11 siblings, 0 replies; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Define migrate_set_parameter_strv.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/migration/migration-qmp.h |  2 ++
 tests/qtest/migration/migration-qmp.c | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index faa8181..44482d2 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -34,6 +34,8 @@ void read_blocktime(QTestState *who);
 void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state);
 void migrate_set_parameter_str(QTestState *who, const char *parameter,
                                const char *value);
+void migrate_set_parameter_strv(QTestState *who, const char *parameter,
+                                char **strv);
 void migrate_set_parameter_bool(QTestState *who, const char *parameter,
                                 int value);
 void migrate_ensure_non_converge(QTestState *who);
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index 66dd369..c803fce 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -442,6 +442,22 @@ void migrate_set_parameter_str(QTestState *who, const char *parameter,
     migrate_check_parameter_str(who, parameter, value);
 }
 
+void migrate_set_parameter_strv(QTestState *who, const char *parameter,
+                                char **strv)
+{
+    g_autofree char *args = g_strjoinv("\",\"", strv);
+    g_autoptr(GString) value = g_string_new("");
+    g_autofree char *command = NULL;
+
+    g_string_printf(value, "\"%s\"", args);
+
+    command = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
+                              "'arguments': { %%s: [ %s ]}}",
+                              value->str);
+
+    qtest_qmp_assert_success(who, command, parameter);
+}
+
 static long long migrate_get_parameter_bool(QTestState *who,
                                             const char *parameter)
 {
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH V1 11/11] migration-test: test cpr-exec
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (9 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 10/11] migration-test: strv parameter Steve Sistare
@ 2025-09-19 14:12 ` Steve Sistare
  2025-09-30 17:08   ` Peter Xu
  2025-09-30 14:35 ` [PATCH V1 00/11] cpr-exec test Fabiano Rosas
  11 siblings, 1 reply; 30+ messages in thread
From: Steve Sistare @ 2025-09-19 14:12 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini, Peter Xu,
	Steve Sistare

Add a test for the cpr-exec migration mode.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 tests/qtest/migration/cpr-tests.c | 120 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 5e764a6..f33af76 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -110,6 +110,125 @@ static void test_mode_transfer_defer(void)
     test_mode_transfer_common(true);
 }
 
+static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
+{
+    g_autofree char *qtest_from_args = NULL;
+    g_autofree char *from_args = NULL;
+    g_autofree char *to_args = NULL;
+    g_autofree char *exec_args = NULL;
+    g_auto(GStrv) argv = NULL;
+    char *from_str, *src, *dst;
+
+    args->start.hide_stderr = false;    /* omit redirection word from args */
+    migrate_args(&from_args, &to_args, args->listen_uri, &args->start);
+    qtest_from_args = qtest_qemu_args(from_args);
+
+    /* De-dup spaces so argv does not contain empty strings */
+    from_str = src = dst = g_strstrip(qtest_from_args);
+    do {
+        if (*src != ' ' || src[-1] != ' ') {
+            *dst++ = *src;
+        }
+    } while (*src++);
+
+    exec_args = g_strconcat(qtest_qemu_binary(QEMU_ENV_SRC),
+                            " -incoming defer ", from_str, NULL);
+    argv = g_strsplit(exec_args, " ", -1);
+    migrate_set_parameter_strv(who, "cpr-exec-command", argv);
+}
+
+static void wait_for_migration_event(QTestState *who, const char *waitfor)
+{
+    QDict *rsp, *data;
+    char *status;
+    bool done = false;
+
+    while (!done) {
+        rsp = qtest_qmp_eventwait_ref(who, "MIGRATION");
+        g_assert(qdict_haskey(rsp, "data"));
+        data = qdict_get_qdict(rsp, "data");
+        g_assert(qdict_haskey(data, "status"));
+        status = g_strdup(qdict_get_str(data, "status"));
+        g_assert(strcmp(status, "failed"));
+        done = !strcmp(status, waitfor);
+        qobject_unref(rsp);
+    }
+}
+
+static void test_cpr_exec(MigrateCommon *args)
+{
+    QTestState *from, *to;
+    void *data_hook = NULL;
+    g_autofree char *connect_uri = g_strdup(args->connect_uri);
+    g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs,
+                                                FILE_TEST_FILENAME);
+
+
+    if (migrate_start(&from, NULL, args->listen_uri, &args->start)) {
+        return;
+    }
+
+    /* Source and dest never run concurrently */
+    g_assert_false(args->live);
+
+    if (args->start_hook) {
+        data_hook = args->start_hook(from, NULL);
+    }
+
+    wait_for_serial("src_serial");
+    set_cpr_exec_args(from, args);
+    migrate_set_capability(from, "events", true);
+    migrate_qmp(from, NULL, connect_uri, NULL, "{}");
+    wait_for_migration_event(from, "completed");
+
+    to = qtest_init_after_exec(from);
+
+    qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
+                             "  'arguments': { "
+                             "      'channels': [ { 'channel-type': 'main',"
+                             "      'addr': { 'transport': 'file',"
+                             "                'filename': %s,"
+                             "                'offset': 0  } } ] } }",
+                             filename);
+    wait_for_migration_complete(to);
+
+    wait_for_resume(to, get_dst());
+    /* Device on target is still named src_serial because args do not change */
+    wait_for_serial("src_serial");
+
+    if (args->end_hook) {
+        args->end_hook(from, to, data_hook);
+    }
+
+    migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
+}
+
+static void *test_mode_exec_start(QTestState *from, QTestState *to)
+{
+    assert(!to);
+    migrate_set_parameter_str(from, "mode", "cpr-exec");
+    return NULL;
+}
+
+static void test_mode_exec(void)
+{
+    g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+                                           FILE_TEST_FILENAME);
+    g_autofree char *listen_uri = g_strdup_printf("defer");
+
+    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",
+        .connect_uri = uri,
+        .listen_uri = listen_uri,
+        .start_hook = test_mode_exec_start,
+    };
+
+    test_cpr_exec(&args);
+}
+
 void migration_test_add_cpr(MigrationTestEnv *env)
 {
     tmpfs = env->tmpfs;
@@ -132,5 +251,6 @@ void migration_test_add_cpr(MigrationTestEnv *env)
         migration_test_add("/migration/mode/transfer", test_mode_transfer);
         migration_test_add("/migration/mode/transfer/defer",
                            test_mode_transfer_defer);
+        migration_test_add("/migration/mode/exec", test_mode_exec);
     }
 }
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary
  2025-09-19 14:12 ` [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary Steve Sistare
@ 2025-09-29 14:47   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 14:47 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> ---
>  tests/qtest/libqtest.h | 9 +++++++++
>  tests/qtest/libqtest.c | 2 +-
>  2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
> index b3f2e7f..6d3199f 100644
> --- a/tests/qtest/libqtest.h
> +++ b/tests/qtest/libqtest.h
> @@ -48,6 +48,15 @@ QTestState *qtest_initf(const char *fmt, ...) G_GNUC_PRINTF(1, 2);
>  QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
>  
>  /**
> + * qtest_qemu_binary:
> + * @var: environment variable name
> + *
> + * Look up @var and return its value as the qemu binary path.
> + * If @var is NULL, look up  the default var name.
> + */
> +const char *qtest_qemu_binary(const char *var);
> +
> +/**
>   * qtest_init:
>   * @extra_args: other arguments to pass to QEMU.  CAUTION: these
>   * arguments are subject to word splitting and shell evaluation.
> diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
> index f3d4e08..6f76be1 100644
> --- a/tests/qtest/libqtest.c
> +++ b/tests/qtest/libqtest.c
> @@ -357,7 +357,7 @@ void qtest_remove_abrt_handler(void *data)
>      }
>  }
>  
> -static const char *qtest_qemu_binary(const char *var)
> +const char *qtest_qemu_binary(const char *var)
>  {
>      const char *qemu_bin;

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 02/11] tests/qtest: qtest_qemu_args
  2025-09-19 14:12 ` [PATCH V1 02/11] tests/qtest: qtest_qemu_args Steve Sistare
@ 2025-09-29 14:51   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 14:51 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Define an accessor that returns all the arguments used to exec QEMU.
> Collect the arguments that were passed to qtest_spawn_qemu, plus the trace
> arguments that were composed inside qtest_spawn_qemu, and move them to a
> new function qtest_qemu_args.
>
> This will be needed to test the cpr-exec migration mode.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 03/11] tests/qtest: qtest_create_test_state
  2025-09-19 14:12 ` [PATCH V1 03/11] tests/qtest: qtest_create_test_state Steve Sistare
@ 2025-09-29 14:52   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 14:52 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Refactor qtest_spawn_qemu and create a subroutine to create a QTestState
> object, to be used in a subsequent patch.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> ---
>  tests/qtest/libqtest.c | 21 ++++++++++++++-------
>  1 file changed, 14 insertions(+), 7 deletions(-)
>
> diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
> index 551bc8c..3fa9317 100644
> --- a/tests/qtest/libqtest.c
> +++ b/tests/qtest/libqtest.c
> @@ -409,22 +409,29 @@ static pid_t qtest_create_process(char *cmd)
>  }
>  #endif /* _WIN32 */
>  
> -static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
> +static QTestState *qtest_create_test_state(int pid)
>  {
>      QTestState *s = g_new0(QTestState, 1);
> +
> +    s->qemu_pid = pid;
> +    qtest_add_abrt_handler(kill_qemu_hook_func, s);
> +    return s;
> +}
> +
> +static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
> +{
> +    int pid;
>      g_autoptr(GString) command = g_string_new("");
>  
>      g_string_printf(command, CMD_EXEC "%s %s", qemu_bin, args);
>  
> -    qtest_add_abrt_handler(kill_qemu_hook_func, s);
> -
>      if (!silence_spawn_log) {
>          g_test_message("starting QEMU: %s", command->str);
>      }
>  
>  #ifndef _WIN32
> -    s->qemu_pid = fork();
> -    if (s->qemu_pid == 0) {
> +    pid = fork();
> +    if (pid == 0) {
>  #ifdef __linux__
>          /*
>           * Although we register a ABRT handler to kill off QEMU
> @@ -447,10 +454,10 @@ static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args)
>          exit(1);
>      }
>  #else
> -    s->qemu_pid = qtest_create_process(command->str);
> +    pid = qtest_create_process(command->str);
>  #endif /* _WIN32 */
>  
> -    return s;
> +    return qtest_create_test_state(pid);
>  }
>  
>  static char *qtest_socket_path(const char *suffix)

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 04/11] tests/qtest: qtest_qemu_spawn_func
  2025-09-19 14:12 ` [PATCH V1 04/11] tests/qtest: qtest_qemu_spawn_func Steve Sistare
@ 2025-09-29 14:57   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 14:57 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Allow the qtest_qemu_spawn caller to pass the function to be called
> to perform the spawn.  The opaque argument is needed by a new spawn
> function in a subsequent patch.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 05/11] tests/qtest: qtest_init_after_exec
  2025-09-19 14:12 ` [PATCH V1 05/11] tests/qtest: qtest_init_after_exec Steve Sistare
@ 2025-09-29 14:59   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 14:59 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Define a function to create a QTestState object representing the state
> of QEMU after old QEMU exec's new QEMU.  This is needed for testing
> the cpr-exec migration mode.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>

Reviewed-by: Fabiano Rosas <farosas@suse.de>

> ---
>  tests/qtest/libqtest.h |  8 ++++++++
>  tests/qtest/libqtest.c | 19 +++++++++++++++++++
>  2 files changed, 27 insertions(+)
>
> diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
> index a164f58..ce6b9b0 100644
> --- a/tests/qtest/libqtest.h
> +++ b/tests/qtest/libqtest.h
> @@ -57,6 +57,14 @@ QTestState *qtest_vinitf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0);
>  const char *qtest_qemu_binary(const char *var);
>  
>  /**
> + * qtest_init_after_exec:
> + * @from: the previous QEMU state

qts is the term used in libqtest. I'll amend it myself.

> + *
> + * Return a test state representing new QEMU after @from exec's it.
> + */
> +QTestState *qtest_init_after_exec(QTestState *from);
> +
> +/**
>   * qtest_qemu_args:
>   * @extra_args: Other arguments to pass to QEMU.
>   *
> diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
> index d97144e..3522d75 100644
> --- a/tests/qtest/libqtest.c
> +++ b/tests/qtest/libqtest.c
> @@ -615,6 +615,25 @@ QTestState *qtest_init_ext(const char *var, const char *extra_args,
>      return s;
>  }
>  
> +static QTestState *qtest_attach_qemu(const char *qemu_bin,
> +                                     const char *extra_args,
> +                                     void *opaque)
> +{
> +    int pid = *(int *)opaque;
> +    return qtest_create_test_state(pid);
> +}
> +
> +QTestState *qtest_init_after_exec(QTestState *from)
> +{
> +    void *opaque = (void *)&from->qemu_pid;
> +    QTestState *s;
> +
> +    s = qtest_init_internal(NULL, NULL, true, qtest_attach_qemu, opaque);
> +    from->qemu_pid = -1;
> +    qtest_qmp_handshake(s, NULL);
> +    return s;
> +}
> +
>  QTestState *qtest_init(const char *extra_args)
>  {
>      return qtest_init_ext(NULL, extra_args, NULL, true);


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 06/11] migration-test: only_source option
  2025-09-19 14:12 ` [PATCH V1 06/11] migration-test: only_source option Steve Sistare
@ 2025-09-29 20:27   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 20:27 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Add the only_source option, analogous to only_target.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 07/11] migration-test: shm path accessor
  2025-09-19 14:12 ` [PATCH V1 07/11] migration-test: shm path accessor Steve Sistare
@ 2025-09-29 20:28   ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 20:28 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Define an accessor for the shm path.  It will be referenced from
> multiple sites in a subsequent patch.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 09/11] migration-test: migrate_args
  2025-09-19 14:12 ` [PATCH V1 09/11] migration-test: migrate_args Steve Sistare
@ 2025-09-29 20:32   ` Fabiano Rosas
  2025-09-30 14:35     ` Steven Sistare
  2025-09-30 19:51   ` Fabiano Rosas
  1 sibling, 1 reply; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-29 20:32 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Define the subroutine migrate_args to return the arguments that are
> used to exec the source or target qemu process.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> ---
>  tests/qtest/migration/framework.h |  2 ++
>  tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
>  2 files changed, 41 insertions(+), 25 deletions(-)
>
> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
> index 7ff3187..51a8a7e 100644
> --- a/tests/qtest/migration/framework.h
> +++ b/tests/qtest/migration/framework.h
> @@ -226,6 +226,8 @@ typedef struct {
>  void wait_for_serial(const char *side);
>  void migrate_prepare_for_dirty_mem(QTestState *from);
>  void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
> +
> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
>  int migrate_start(QTestState **from, QTestState **to, const char *uri,
>                    MigrateStart *args);
>  void migrate_end(QTestState *from, QTestState *to, bool test_dest);
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 8f9e359..2dfb1ee 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -258,13 +258,12 @@ static char *test_shmem_path(void)
>      return g_strdup_printf("/dev/shm/qemu-%d", getpid());
>  }
>  
> -int migrate_start(QTestState **from, QTestState **to, const char *uri,
> -                  MigrateStart *args)
> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
>  {
>      /* options for source and target */
>      g_autofree gchar *arch_opts = NULL;
> -    g_autofree gchar *cmd_source = NULL;
> -    g_autofree gchar *cmd_target = NULL;
> +    gchar *cmd_source = NULL;
> +    gchar *cmd_target = NULL;
>      const gchar *ignore_stderr;
>      g_autofree char *shmem_opts = NULL;
>      g_autofree char *shmem_path = NULL;
> @@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>      const char *memory_size;
>      const char *machine_alias, *machine_opts = "";
>      g_autofree char *machine = NULL;
> -    const char *bootpath;
> -    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
> +    const char *bootpath = bootfile_get();
>      g_autofree char *memory_backend = NULL;
>      const char *events;
>  
> -    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;
> -        }
> -    }
> -
> -    dst_state = (QTestMigrationState) { };
> -    src_state = (QTestMigrationState) { };
> -    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
> -    src_state.suspend_me = args->suspend_me;
> -
>      if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>          memory_size = "150M";
>  
> @@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>      if (!qtest_has_machine(machine_alias)) {
>          g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
>          g_test_skip(msg);
> -        return -1;
> +        return;
>      }
>  
>      machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
> @@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>                                   shmem_opts ? shmem_opts : "",
>                                   args->opts_source ? args->opts_source : "",
>                                   ignore_stderr);
> -    if (!args->only_target) {
> -        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
> -        qtest_qmp_set_event_callback(*from,
> -                                     migrate_watch_for_events,
> -                                     &src_state);
> -    }
>  
>      /*
>       * If the monitor connection is deferred, enable events on the command line
> @@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>                                   shmem_opts ? shmem_opts : "",
>                                   args->opts_target ? args->opts_target : "",
>                                   ignore_stderr);
> +
> +    *from = cmd_source;
> +    *to = cmd_target;
> +}
> +
> +int migrate_start(QTestState **from, QTestState **to, const char *uri,
> +                  MigrateStart *args)
> +{
> +    g_autofree gchar *cmd_source = NULL;
> +    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;
> +        }
> +    }
> +
> +    dst_state = (QTestMigrationState) { };
> +    src_state = (QTestMigrationState) { };
> +    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
> +    src_state.suspend_me = args->suspend_me;

I've been thinking of moving QTestState inside QTestMigrationState, so
these variables are not loosely kept without a accompanying
QTestState. When implementing ping-pong tests the current code got a bit
out of hand. Also the "src_serial" problem later on would be resolved by
a new qtms->serial.

What's stopping me at the moment is the amount of churn. If you spot a
better solution let be know.

> +
> +    migrate_args(&cmd_source, &cmd_target, uri, args);
> +
> +    if (!args->only_target) {
> +        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
> +        qtest_qmp_set_event_callback(*from,
> +                                     migrate_watch_for_events,
> +                                     &src_state);
> +    }
> +
>      if (!args->only_source) {
>          *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
>                               !args->defer_target_connect);
> @@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>       * 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);
>      }

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 09/11] migration-test: migrate_args
  2025-09-29 20:32   ` Fabiano Rosas
@ 2025-09-30 14:35     ` Steven Sistare
  0 siblings, 0 replies; 30+ messages in thread
From: Steven Sistare @ 2025-09-30 14:35 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini, Peter Xu

On 9/29/2025 4:32 PM, Fabiano Rosas wrote:
> Steve Sistare <steven.sistare@oracle.com> writes:
> 
>> Define the subroutine migrate_args to return the arguments that are
>> used to exec the source or target qemu process.
>>
>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>> ---
>>   tests/qtest/migration/framework.h |  2 ++
>>   tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
>>   2 files changed, 41 insertions(+), 25 deletions(-)
>>
>> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
>> index 7ff3187..51a8a7e 100644
>> --- a/tests/qtest/migration/framework.h
>> +++ b/tests/qtest/migration/framework.h
>> @@ -226,6 +226,8 @@ typedef struct {
>>   void wait_for_serial(const char *side);
>>   void migrate_prepare_for_dirty_mem(QTestState *from);
>>   void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
>> +
>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
>>   int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>                     MigrateStart *args);
>>   void migrate_end(QTestState *from, QTestState *to, bool test_dest);
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index 8f9e359..2dfb1ee 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -258,13 +258,12 @@ static char *test_shmem_path(void)
>>       return g_strdup_printf("/dev/shm/qemu-%d", getpid());
>>   }
>>   
>> -int migrate_start(QTestState **from, QTestState **to, const char *uri,
>> -                  MigrateStart *args)
>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
>>   {
>>       /* options for source and target */
>>       g_autofree gchar *arch_opts = NULL;
>> -    g_autofree gchar *cmd_source = NULL;
>> -    g_autofree gchar *cmd_target = NULL;
>> +    gchar *cmd_source = NULL;
>> +    gchar *cmd_target = NULL;
>>       const gchar *ignore_stderr;
>>       g_autofree char *shmem_opts = NULL;
>>       g_autofree char *shmem_path = NULL;
>> @@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>       const char *memory_size;
>>       const char *machine_alias, *machine_opts = "";
>>       g_autofree char *machine = NULL;
>> -    const char *bootpath;
>> -    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
>> +    const char *bootpath = bootfile_get();
>>       g_autofree char *memory_backend = NULL;
>>       const char *events;
>>   
>> -    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;
>> -        }
>> -    }
>> -
>> -    dst_state = (QTestMigrationState) { };
>> -    src_state = (QTestMigrationState) { };
>> -    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
>> -    src_state.suspend_me = args->suspend_me;
>> -
>>       if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>>           memory_size = "150M";
>>   
>> @@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>       if (!qtest_has_machine(machine_alias)) {
>>           g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
>>           g_test_skip(msg);
>> -        return -1;
>> +        return;
>>       }
>>   
>>       machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
>> @@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>                                    shmem_opts ? shmem_opts : "",
>>                                    args->opts_source ? args->opts_source : "",
>>                                    ignore_stderr);
>> -    if (!args->only_target) {
>> -        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>> -        qtest_qmp_set_event_callback(*from,
>> -                                     migrate_watch_for_events,
>> -                                     &src_state);
>> -    }
>>   
>>       /*
>>        * If the monitor connection is deferred, enable events on the command line
>> @@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>                                    shmem_opts ? shmem_opts : "",
>>                                    args->opts_target ? args->opts_target : "",
>>                                    ignore_stderr);
>> +
>> +    *from = cmd_source;
>> +    *to = cmd_target;
>> +}
>> +
>> +int migrate_start(QTestState **from, QTestState **to, const char *uri,
>> +                  MigrateStart *args)
>> +{
>> +    g_autofree gchar *cmd_source = NULL;
>> +    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;
>> +        }
>> +    }
>> +
>> +    dst_state = (QTestMigrationState) { };
>> +    src_state = (QTestMigrationState) { };
>> +    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
>> +    src_state.suspend_me = args->suspend_me;
> 
> I've been thinking of moving QTestState inside QTestMigrationState, so
> these variables are not loosely kept without a accompanying
> QTestState. When implementing ping-pong tests the current code got a bit
> out of hand. Also the "src_serial" problem later on would be resolved by
> a new qtms->serial.
> 
> What's stopping me at the moment is the amount of churn. If you spot a
> better solution let be know.

I had the same thought, or having QTestMigrationState and QTestState point to
each other.  Perhaps the latter would cause less churn.

Thanks very much for reviewing my patches!

- Steve

> 
>> +
>> +    migrate_args(&cmd_source, &cmd_target, uri, args);
>> +
>> +    if (!args->only_target) {
>> +        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>> +        qtest_qmp_set_event_callback(*from,
>> +                                     migrate_watch_for_events,
>> +                                     &src_state);
>> +    }
>> +
>>       if (!args->only_source) {
>>           *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
>>                                !args->defer_target_connect);
>> @@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>        * 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);
>>       }
> 
> Reviewed-by: Fabiano Rosas <farosas@suse.de>



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 00/11] cpr-exec test
  2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
                   ` (10 preceding siblings ...)
  2025-09-19 14:12 ` [PATCH V1 11/11] migration-test: test cpr-exec Steve Sistare
@ 2025-09-30 14:35 ` Fabiano Rosas
  11 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-30 14:35 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Add a migration test for cpr-exec mode.
> Depends on the patch series "Live update: cpr-exec".
>
> Steve Sistare (11):
>   tests/qtest: export qtest_qemu_binary
>   tests/qtest: qtest_qemu_args
>   tests/qtest: qtest_create_test_state
>   tests/qtest: qtest_qemu_spawn_func
>   tests/qtest: qtest_init_after_exec
>   migration-test: only_source option
>   migration-test: shm path accessor
>   migration-test: misc exports
>   migration-test: migrate_args
>   migration-test: strv parameter
>   migration-test: test cpr-exec
>
>  tests/qtest/libqtest.h                |  25 +++++++
>  tests/qtest/migration/bootfile.h      |   1 +
>  tests/qtest/migration/framework.h     |   8 +++
>  tests/qtest/migration/migration-qmp.h |   2 +
>  tests/qtest/libqtest.c                | 108 ++++++++++++++++++++----------
>  tests/qtest/migration/bootfile.c      |   5 ++
>  tests/qtest/migration/cpr-tests.c     | 120 ++++++++++++++++++++++++++++++++++
>  tests/qtest/migration/framework.c     | 102 ++++++++++++++++++-----------
>  tests/qtest/migration/migration-qmp.c |  16 +++++
>  9 files changed, 317 insertions(+), 70 deletions(-)

Queued up to patch 10 to qtest-next.


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 11/11] migration-test: test cpr-exec
  2025-09-19 14:12 ` [PATCH V1 11/11] migration-test: test cpr-exec Steve Sistare
@ 2025-09-30 17:08   ` Peter Xu
  2025-09-30 18:23     ` Steven Sistare
  0 siblings, 1 reply; 30+ messages in thread
From: Peter Xu @ 2025-09-30 17:08 UTC (permalink / raw)
  To: Steve Sistare; +Cc: qemu-devel, Fabiano Rosas, Laurent Vivier, Paolo Bonzini

On Fri, Sep 19, 2025 at 07:12:33AM -0700, Steve Sistare wrote:
> Add a test for the cpr-exec migration mode.
> 
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>

Looks good, only some nitpicks or pure questions below.

> ---
>  tests/qtest/migration/cpr-tests.c | 120 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 120 insertions(+)
> 
> diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
> index 5e764a6..f33af76 100644
> --- a/tests/qtest/migration/cpr-tests.c
> +++ b/tests/qtest/migration/cpr-tests.c
> @@ -110,6 +110,125 @@ static void test_mode_transfer_defer(void)
>      test_mode_transfer_common(true);
>  }
>  
> +static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
> +{
> +    g_autofree char *qtest_from_args = NULL;
> +    g_autofree char *from_args = NULL;
> +    g_autofree char *to_args = NULL;
> +    g_autofree char *exec_args = NULL;
> +    g_auto(GStrv) argv = NULL;
> +    char *from_str, *src, *dst;
> +
> +    args->start.hide_stderr = false;    /* omit redirection word from args */

It's default off, right?  Could I request for some more explanations?

Could we also set it in test_mode_exec() directly if needed?

> +    migrate_args(&from_args, &to_args, args->listen_uri, &args->start);
> +    qtest_from_args = qtest_qemu_args(from_args);
> +
> +    /* De-dup spaces so argv does not contain empty strings */
> +    from_str = src = dst = g_strstrip(qtest_from_args);
> +    do {
> +        if (*src != ' ' || src[-1] != ' ') {
> +            *dst++ = *src;
> +        }
> +    } while (*src++);

Pure ask.. when will empty string be present?

> +
> +    exec_args = g_strconcat(qtest_qemu_binary(QEMU_ENV_SRC),

Should this be QEMU_ENV_DST?

OTOH, we can use migration_get_env()->qemu_dst to reduce referencing global
vars.

> +                            " -incoming defer ", from_str, NULL);
> +    argv = g_strsplit(exec_args, " ", -1);
> +    migrate_set_parameter_strv(who, "cpr-exec-command", argv);
> +}
> +
> +static void wait_for_migration_event(QTestState *who, const char *waitfor)
> +{
> +    QDict *rsp, *data;
> +    char *status;
> +    bool done = false;
> +
> +    while (!done) {
> +        rsp = qtest_qmp_eventwait_ref(who, "MIGRATION");
> +        g_assert(qdict_haskey(rsp, "data"));
> +        data = qdict_get_qdict(rsp, "data");
> +        g_assert(qdict_haskey(data, "status"));
> +        status = g_strdup(qdict_get_str(data, "status"));
> +        g_assert(strcmp(status, "failed"));
> +        done = !strcmp(status, waitfor);
> +        qobject_unref(rsp);
> +    }
> +}
> +
> +static void test_cpr_exec(MigrateCommon *args)
> +{
> +    QTestState *from, *to;
> +    void *data_hook = NULL;
> +    g_autofree char *connect_uri = g_strdup(args->connect_uri);
> +    g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs,
> +                                                FILE_TEST_FILENAME);
> +
> +

Newline can be dropped.

> +    if (migrate_start(&from, NULL, args->listen_uri, &args->start)) {
> +        return;
> +    }
> +
> +    /* Source and dest never run concurrently */
> +    g_assert_false(args->live);
> +
> +    if (args->start_hook) {
> +        data_hook = args->start_hook(from, NULL);
> +    }
> +
> +    wait_for_serial("src_serial");
> +    set_cpr_exec_args(from, args);
> +    migrate_set_capability(from, "events", true);
> +    migrate_qmp(from, NULL, connect_uri, NULL, "{}");
> +    wait_for_migration_event(from, "completed");
> +
> +    to = qtest_init_after_exec(from);
> +
> +    qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
> +                             "  'arguments': { "
> +                             "      'channels': [ { 'channel-type': 'main',"
> +                             "      'addr': { 'transport': 'file',"
> +                             "                'filename': %s,"
> +                             "                'offset': 0  } } ] } }",
> +                             filename);
> +    wait_for_migration_complete(to);
> +
> +    wait_for_resume(to, get_dst());
> +    /* Device on target is still named src_serial because args do not change */
> +    wait_for_serial("src_serial");
> +
> +    if (args->end_hook) {
> +        args->end_hook(from, to, data_hook);
> +    }
> +
> +    migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
> +}
> +
> +static void *test_mode_exec_start(QTestState *from, QTestState *to)
> +{
> +    assert(!to);
> +    migrate_set_parameter_str(from, "mode", "cpr-exec");
> +    return NULL;
> +}
> +
> +static void test_mode_exec(void)
> +{
> +    g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> +                                           FILE_TEST_FILENAME);
> +    g_autofree char *listen_uri = g_strdup_printf("defer");
> +
> +    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",
> +        .connect_uri = uri,
> +        .listen_uri = listen_uri,
> +        .start_hook = test_mode_exec_start,
> +    };
> +
> +    test_cpr_exec(&args);
> +}
> +
>  void migration_test_add_cpr(MigrationTestEnv *env)
>  {
>      tmpfs = env->tmpfs;
> @@ -132,5 +251,6 @@ void migration_test_add_cpr(MigrationTestEnv *env)
>          migration_test_add("/migration/mode/transfer", test_mode_transfer);
>          migration_test_add("/migration/mode/transfer/defer",
>                             test_mode_transfer_defer);
> +        migration_test_add("/migration/mode/exec", test_mode_exec);
>      }
>  }
> -- 
> 1.8.3.1
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 11/11] migration-test: test cpr-exec
  2025-09-30 17:08   ` Peter Xu
@ 2025-09-30 18:23     ` Steven Sistare
  2025-09-30 19:02       ` Peter Xu
  0 siblings, 1 reply; 30+ messages in thread
From: Steven Sistare @ 2025-09-30 18:23 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, Fabiano Rosas, Laurent Vivier, Paolo Bonzini

On 9/30/2025 1:08 PM, Peter Xu wrote:
> On Fri, Sep 19, 2025 at 07:12:33AM -0700, Steve Sistare wrote:
>> Add a test for the cpr-exec migration mode.
>>
>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> 
> Looks good, only some nitpicks or pure questions below.
> 
>> ---
>>   tests/qtest/migration/cpr-tests.c | 120 ++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 120 insertions(+)
>>
>> diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
>> index 5e764a6..f33af76 100644
>> --- a/tests/qtest/migration/cpr-tests.c
>> +++ b/tests/qtest/migration/cpr-tests.c
>> @@ -110,6 +110,125 @@ static void test_mode_transfer_defer(void)
>>       test_mode_transfer_common(true);
>>   }
>>   
>> +static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
>> +{
>> +    g_autofree char *qtest_from_args = NULL;
>> +    g_autofree char *from_args = NULL;
>> +    g_autofree char *to_args = NULL;
>> +    g_autofree char *exec_args = NULL;
>> +    g_auto(GStrv) argv = NULL;
>> +    char *from_str, *src, *dst;
>> +
>> +    args->start.hide_stderr = false;    /* omit redirection word from args */
> 
> It's default off, right?  Could I request for some more explanations?

Yes, the default is false, so I will omit this line.  I will change it to
an assertion. (IIRC when I first wrote this code 1-2 years ago, the cpr-exec
test was a derivative of a precopy common test that set hide_stderr=true).

hide_stderr must be false when deriving cpr-exec arguments because of
this code in framework.c:

     if (!getenv("QTEST_LOG") && args->hide_stderr) {
         ignore_stderr = "2>/dev/null";

ignore_stderr is appended to the command line.  For cpr-exec the command line
may not include redirection, because we pass it to execv(), not to the shell.

> Could we also set it in test_mode_exec() directly if needed?

Yes, one can set hide_stderr when launching the source VM.

>> +    migrate_args(&from_args, &to_args, args->listen_uri, &args->start);
>> +    qtest_from_args = qtest_qemu_args(from_args);
>> +
>> +    /* De-dup spaces so argv does not contain empty strings */
>> +    from_str = src = dst = g_strstrip(qtest_from_args);
>> +    do {
>> +        if (*src != ' ' || src[-1] != ' ') {
>> +            *dst++ = *src;
>> +        }
>> +    } while (*src++);
> 
> Pure ask.. when will empty string be present?

migrate_args() format strings "%s %s %s" produce "   " when the arguments
are empty strings.  Then g_strsplit("   ") would produce an array of 3
empty strings.

>> +
>> +    exec_args = g_strconcat(qtest_qemu_binary(QEMU_ENV_SRC),
> 
> Should this be QEMU_ENV_DST?

Good catch, thanks, will fix.

> OTOH, we can use migration_get_env()->qemu_dst to reduce referencing global
> vars.

OK, that works.

>> +                            " -incoming defer ", from_str, NULL);
>> +    argv = g_strsplit(exec_args, " ", -1);
>> +    migrate_set_parameter_strv(who, "cpr-exec-command", argv);
>> +}
>> +
>> +static void wait_for_migration_event(QTestState *who, const char *waitfor)
>> +{
>> +    QDict *rsp, *data;
>> +    char *status;
>> +    bool done = false;
>> +
>> +    while (!done) {
>> +        rsp = qtest_qmp_eventwait_ref(who, "MIGRATION");
>> +        g_assert(qdict_haskey(rsp, "data"));
>> +        data = qdict_get_qdict(rsp, "data");
>> +        g_assert(qdict_haskey(data, "status"));
>> +        status = g_strdup(qdict_get_str(data, "status"));
>> +        g_assert(strcmp(status, "failed"));
>> +        done = !strcmp(status, waitfor);
>> +        qobject_unref(rsp);
>> +    }
>> +}
>> +
>> +static void test_cpr_exec(MigrateCommon *args)
>> +{
>> +    QTestState *from, *to;
>> +    void *data_hook = NULL;
>> +    g_autofree char *connect_uri = g_strdup(args->connect_uri);
>> +    g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs,
>> +                                                FILE_TEST_FILENAME);
>> +
>> +
> 
> Newline can be dropped.

OK.

- Steve

>> +    if (migrate_start(&from, NULL, args->listen_uri, &args->start)) {
>> +        return;
>> +    }
>> +
>> +    /* Source and dest never run concurrently */
>> +    g_assert_false(args->live);
>> +
>> +    if (args->start_hook) {
>> +        data_hook = args->start_hook(from, NULL);
>> +    }
>> +
>> +    wait_for_serial("src_serial");
>> +    set_cpr_exec_args(from, args);
>> +    migrate_set_capability(from, "events", true);
>> +    migrate_qmp(from, NULL, connect_uri, NULL, "{}");
>> +    wait_for_migration_event(from, "completed");
>> +
>> +    to = qtest_init_after_exec(from);
>> +
>> +    qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
>> +                             "  'arguments': { "
>> +                             "      'channels': [ { 'channel-type': 'main',"
>> +                             "      'addr': { 'transport': 'file',"
>> +                             "                'filename': %s,"
>> +                             "                'offset': 0  } } ] } }",
>> +                             filename);
>> +    wait_for_migration_complete(to);
>> +
>> +    wait_for_resume(to, get_dst());
>> +    /* Device on target is still named src_serial because args do not change */
>> +    wait_for_serial("src_serial");
>> +
>> +    if (args->end_hook) {
>> +        args->end_hook(from, to, data_hook);
>> +    }
>> +
>> +    migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
>> +}
>> +
>> +static void *test_mode_exec_start(QTestState *from, QTestState *to)
>> +{
>> +    assert(!to);
>> +    migrate_set_parameter_str(from, "mode", "cpr-exec");
>> +    return NULL;
>> +}
>> +
>> +static void test_mode_exec(void)
>> +{
>> +    g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
>> +                                           FILE_TEST_FILENAME);
>> +    g_autofree char *listen_uri = g_strdup_printf("defer");
>> +
>> +    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",
>> +        .connect_uri = uri,
>> +        .listen_uri = listen_uri,
>> +        .start_hook = test_mode_exec_start,
>> +    };
>> +
>> +    test_cpr_exec(&args);
>> +}
>> +
>>   void migration_test_add_cpr(MigrationTestEnv *env)
>>   {
>>       tmpfs = env->tmpfs;
>> @@ -132,5 +251,6 @@ void migration_test_add_cpr(MigrationTestEnv *env)
>>           migration_test_add("/migration/mode/transfer", test_mode_transfer);
>>           migration_test_add("/migration/mode/transfer/defer",
>>                              test_mode_transfer_defer);
>> +        migration_test_add("/migration/mode/exec", test_mode_exec);
>>       }
>>   }
>> -- 
>> 1.8.3.1
>>
> 




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 11/11] migration-test: test cpr-exec
  2025-09-30 18:23     ` Steven Sistare
@ 2025-09-30 19:02       ` Peter Xu
  2025-09-30 19:07         ` Steven Sistare
  0 siblings, 1 reply; 30+ messages in thread
From: Peter Xu @ 2025-09-30 19:02 UTC (permalink / raw)
  To: Steven Sistare; +Cc: qemu-devel, Fabiano Rosas, Laurent Vivier, Paolo Bonzini

On Tue, Sep 30, 2025 at 02:23:49PM -0400, Steven Sistare wrote:
> On 9/30/2025 1:08 PM, Peter Xu wrote:
> > On Fri, Sep 19, 2025 at 07:12:33AM -0700, Steve Sistare wrote:
> > > Add a test for the cpr-exec migration mode.
> > > 
> > > Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> > 
> > Looks good, only some nitpicks or pure questions below.
> > 
> > > ---
> > >   tests/qtest/migration/cpr-tests.c | 120 ++++++++++++++++++++++++++++++++++++++
> > >   1 file changed, 120 insertions(+)
> > > 
> > > diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
> > > index 5e764a6..f33af76 100644
> > > --- a/tests/qtest/migration/cpr-tests.c
> > > +++ b/tests/qtest/migration/cpr-tests.c
> > > @@ -110,6 +110,125 @@ static void test_mode_transfer_defer(void)
> > >       test_mode_transfer_common(true);
> > >   }
> > > +static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
> > > +{
> > > +    g_autofree char *qtest_from_args = NULL;
> > > +    g_autofree char *from_args = NULL;
> > > +    g_autofree char *to_args = NULL;
> > > +    g_autofree char *exec_args = NULL;
> > > +    g_auto(GStrv) argv = NULL;
> > > +    char *from_str, *src, *dst;
> > > +
> > > +    args->start.hide_stderr = false;    /* omit redirection word from args */
> > 
> > It's default off, right?  Could I request for some more explanations?
> 
> Yes, the default is false, so I will omit this line.  I will change it to
> an assertion. (IIRC when I first wrote this code 1-2 years ago, the cpr-exec
> test was a derivative of a precopy common test that set hide_stderr=true).
> 
> hide_stderr must be false when deriving cpr-exec arguments because of
> this code in framework.c:
> 
>     if (!getenv("QTEST_LOG") && args->hide_stderr) {
>         ignore_stderr = "2>/dev/null";
> 
> ignore_stderr is appended to the command line.  For cpr-exec the command line
> may not include redirection, because we pass it to execv(), not to the shell.

Please kindly add this rich comment above the assertion..

> 
> > Could we also set it in test_mode_exec() directly if needed?
> 
> Yes, one can set hide_stderr when launching the source VM.
> 
> > > +    migrate_args(&from_args, &to_args, args->listen_uri, &args->start);
> > > +    qtest_from_args = qtest_qemu_args(from_args);
> > > +
> > > +    /* De-dup spaces so argv does not contain empty strings */
> > > +    from_str = src = dst = g_strstrip(qtest_from_args);
> > > +    do {
> > > +        if (*src != ' ' || src[-1] != ' ') {
> > > +            *dst++ = *src;
> > > +        }
> > > +    } while (*src++);
> > 
> > Pure ask.. when will empty string be present?
> 
> migrate_args() format strings "%s %s %s" produce "   " when the arguments
> are empty strings.  Then g_strsplit("   ") would produce an array of 3
> empty strings.

... and here too.

Thanks,

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 11/11] migration-test: test cpr-exec
  2025-09-30 19:02       ` Peter Xu
@ 2025-09-30 19:07         ` Steven Sistare
  0 siblings, 0 replies; 30+ messages in thread
From: Steven Sistare @ 2025-09-30 19:07 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, Fabiano Rosas, Laurent Vivier, Paolo Bonzini

On 9/30/2025 3:02 PM, Peter Xu wrote:
> On Tue, Sep 30, 2025 at 02:23:49PM -0400, Steven Sistare wrote:
>> On 9/30/2025 1:08 PM, Peter Xu wrote:
>>> On Fri, Sep 19, 2025 at 07:12:33AM -0700, Steve Sistare wrote:
>>>> Add a test for the cpr-exec migration mode.
>>>>
>>>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>>>
>>> Looks good, only some nitpicks or pure questions below.
>>>
>>>> ---
>>>>    tests/qtest/migration/cpr-tests.c | 120 ++++++++++++++++++++++++++++++++++++++
>>>>    1 file changed, 120 insertions(+)
>>>>
>>>> diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
>>>> index 5e764a6..f33af76 100644
>>>> --- a/tests/qtest/migration/cpr-tests.c
>>>> +++ b/tests/qtest/migration/cpr-tests.c
>>>> @@ -110,6 +110,125 @@ static void test_mode_transfer_defer(void)
>>>>        test_mode_transfer_common(true);
>>>>    }
>>>> +static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
>>>> +{
>>>> +    g_autofree char *qtest_from_args = NULL;
>>>> +    g_autofree char *from_args = NULL;
>>>> +    g_autofree char *to_args = NULL;
>>>> +    g_autofree char *exec_args = NULL;
>>>> +    g_auto(GStrv) argv = NULL;
>>>> +    char *from_str, *src, *dst;
>>>> +
>>>> +    args->start.hide_stderr = false;    /* omit redirection word from args */
>>>
>>> It's default off, right?  Could I request for some more explanations?
>>
>> Yes, the default is false, so I will omit this line.  I will change it to
>> an assertion. (IIRC when I first wrote this code 1-2 years ago, the cpr-exec
>> test was a derivative of a precopy common test that set hide_stderr=true).
>>
>> hide_stderr must be false when deriving cpr-exec arguments because of
>> this code in framework.c:
>>
>>      if (!getenv("QTEST_LOG") && args->hide_stderr) {
>>          ignore_stderr = "2>/dev/null";
>>
>> ignore_stderr is appended to the command line.  For cpr-exec the command line
>> may not include redirection, because we pass it to execv(), not to the shell.
> 
> Please kindly add this rich comment above the assertion..

will do.

> 
>>
>>> Could we also set it in test_mode_exec() directly if needed?
>>
>> Yes, one can set hide_stderr when launching the source VM.
>>
>>>> +    migrate_args(&from_args, &to_args, args->listen_uri, &args->start);
>>>> +    qtest_from_args = qtest_qemu_args(from_args);
>>>> +
>>>> +    /* De-dup spaces so argv does not contain empty strings */
>>>> +    from_str = src = dst = g_strstrip(qtest_from_args);
>>>> +    do {
>>>> +        if (*src != ' ' || src[-1] != ' ') {
>>>> +            *dst++ = *src;
>>>> +        }
>>>> +    } while (*src++);
>>>
>>> Pure ask.. when will empty string be present?
>>
>> migrate_args() format strings "%s %s %s" produce "   " when the arguments
>> are empty strings.  Then g_strsplit("   ") would produce an array of 3
>> empty strings.
> 
> ... and here too.

will do.

- Steve



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 09/11] migration-test: migrate_args
  2025-09-19 14:12 ` [PATCH V1 09/11] migration-test: migrate_args Steve Sistare
  2025-09-29 20:32   ` Fabiano Rosas
@ 2025-09-30 19:51   ` Fabiano Rosas
  2025-09-30 19:59     ` Steven Sistare
  1 sibling, 1 reply; 30+ messages in thread
From: Fabiano Rosas @ 2025-09-30 19:51 UTC (permalink / raw)
  To: Steve Sistare, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Peter Xu, Steve Sistare

Steve Sistare <steven.sistare@oracle.com> writes:

> Define the subroutine migrate_args to return the arguments that are
> used to exec the source or target qemu process.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> ---
>  tests/qtest/migration/framework.h |  2 ++
>  tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
>  2 files changed, 41 insertions(+), 25 deletions(-)
>
> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
> index 7ff3187..51a8a7e 100644
> --- a/tests/qtest/migration/framework.h
> +++ b/tests/qtest/migration/framework.h
> @@ -226,6 +226,8 @@ typedef struct {
>  void wait_for_serial(const char *side);
>  void migrate_prepare_for_dirty_mem(QTestState *from);
>  void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
> +
> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
>  int migrate_start(QTestState **from, QTestState **to, const char *uri,
>                    MigrateStart *args);
>  void migrate_end(QTestState *from, QTestState *to, bool test_dest);
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 8f9e359..2dfb1ee 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -258,13 +258,12 @@ static char *test_shmem_path(void)
>      return g_strdup_printf("/dev/shm/qemu-%d", getpid());
>  }
>  
> -int migrate_start(QTestState **from, QTestState **to, const char *uri,
> -                  MigrateStart *args)
> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
>  {
>      /* options for source and target */
>      g_autofree gchar *arch_opts = NULL;
> -    g_autofree gchar *cmd_source = NULL;
> -    g_autofree gchar *cmd_target = NULL;
> +    gchar *cmd_source = NULL;
> +    gchar *cmd_target = NULL;
>      const gchar *ignore_stderr;
>      g_autofree char *shmem_opts = NULL;
>      g_autofree char *shmem_path = NULL;
> @@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>      const char *memory_size;
>      const char *machine_alias, *machine_opts = "";
>      g_autofree char *machine = NULL;
> -    const char *bootpath;
> -    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
> +    const char *bootpath = bootfile_get();
>      g_autofree char *memory_backend = NULL;
>      const char *events;
>  
> -    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;
> -        }
> -    }
> -
> -    dst_state = (QTestMigrationState) { };
> -    src_state = (QTestMigrationState) { };
> -    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
> -    src_state.suspend_me = args->suspend_me;
> -
>      if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>          memory_size = "150M";
>  
> @@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>      if (!qtest_has_machine(machine_alias)) {
>          g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
>          g_test_skip(msg);
> -        return -1;
> +        return;

A common pitfall is that g_test_skip() doesn't actually ends the
test. The -1 needs to be propagated up, otherwise the test will proceed
with the unsupported machine.

>      }
>  
>      machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
> @@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>                                   shmem_opts ? shmem_opts : "",
>                                   args->opts_source ? args->opts_source : "",
>                                   ignore_stderr);
> -    if (!args->only_target) {
> -        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
> -        qtest_qmp_set_event_callback(*from,
> -                                     migrate_watch_for_events,
> -                                     &src_state);
> -    }
>  
>      /*
>       * If the monitor connection is deferred, enable events on the command line
> @@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>                                   shmem_opts ? shmem_opts : "",
>                                   args->opts_target ? args->opts_target : "",
>                                   ignore_stderr);
> +
> +    *from = cmd_source;
> +    *to = cmd_target;
> +}
> +
> +int migrate_start(QTestState **from, QTestState **to, const char *uri,
> +                  MigrateStart *args)
> +{
> +    g_autofree gchar *cmd_source = NULL;
> +    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;
> +        }
> +    }
> +
> +    dst_state = (QTestMigrationState) { };
> +    src_state = (QTestMigrationState) { };
> +    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
> +    src_state.suspend_me = args->suspend_me;
> +
> +    migrate_args(&cmd_source, &cmd_target, uri, args);
> +
> +    if (!args->only_target) {
> +        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
> +        qtest_qmp_set_event_callback(*from,
> +                                     migrate_watch_for_events,
> +                                     &src_state);
> +    }
> +
>      if (!args->only_source) {
>          *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
>                               !args->defer_target_connect);
> @@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>       * 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);
>      }


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 09/11] migration-test: migrate_args
  2025-09-30 19:51   ` Fabiano Rosas
@ 2025-09-30 19:59     ` Steven Sistare
  2025-09-30 21:14       ` Steven Sistare
  0 siblings, 1 reply; 30+ messages in thread
From: Steven Sistare @ 2025-09-30 19:59 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini, Peter Xu

On 9/30/2025 3:51 PM, Fabiano Rosas wrote:
> Steve Sistare <steven.sistare@oracle.com> writes:
> 
>> Define the subroutine migrate_args to return the arguments that are
>> used to exec the source or target qemu process.
>>
>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>> ---
>>   tests/qtest/migration/framework.h |  2 ++
>>   tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
>>   2 files changed, 41 insertions(+), 25 deletions(-)
>>
>> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
>> index 7ff3187..51a8a7e 100644
>> --- a/tests/qtest/migration/framework.h
>> +++ b/tests/qtest/migration/framework.h
>> @@ -226,6 +226,8 @@ typedef struct {
>>   void wait_for_serial(const char *side);
>>   void migrate_prepare_for_dirty_mem(QTestState *from);
>>   void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
>> +
>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
>>   int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>                     MigrateStart *args);
>>   void migrate_end(QTestState *from, QTestState *to, bool test_dest);
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index 8f9e359..2dfb1ee 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -258,13 +258,12 @@ static char *test_shmem_path(void)
>>       return g_strdup_printf("/dev/shm/qemu-%d", getpid());
>>   }
>>   
>> -int migrate_start(QTestState **from, QTestState **to, const char *uri,
>> -                  MigrateStart *args)
>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
>>   {
>>       /* options for source and target */
>>       g_autofree gchar *arch_opts = NULL;
>> -    g_autofree gchar *cmd_source = NULL;
>> -    g_autofree gchar *cmd_target = NULL;
>> +    gchar *cmd_source = NULL;
>> +    gchar *cmd_target = NULL;
>>       const gchar *ignore_stderr;
>>       g_autofree char *shmem_opts = NULL;
>>       g_autofree char *shmem_path = NULL;
>> @@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>       const char *memory_size;
>>       const char *machine_alias, *machine_opts = "";
>>       g_autofree char *machine = NULL;
>> -    const char *bootpath;
>> -    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
>> +    const char *bootpath = bootfile_get();
>>       g_autofree char *memory_backend = NULL;
>>       const char *events;
>>   
>> -    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;
>> -        }
>> -    }
>> -
>> -    dst_state = (QTestMigrationState) { };
>> -    src_state = (QTestMigrationState) { };
>> -    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
>> -    src_state.suspend_me = args->suspend_me;
>> -
>>       if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>>           memory_size = "150M";
>>   
>> @@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>       if (!qtest_has_machine(machine_alias)) {
>>           g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
>>           g_test_skip(msg);
>> -        return -1;
>> +        return;
> 
> A common pitfall is that g_test_skip() doesn't actually ends the
> test. The -1 needs to be propagated up, otherwise the test will proceed
> with the unsupported machine.

Thanks.
migrate_args() will return an error code.
I'll send a V2 of this patch, and fix the call to migrate_args in patch
"cpr-exec test".

- Steve

> 
>>       }
>>   
>>       machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
>> @@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>                                    shmem_opts ? shmem_opts : "",
>>                                    args->opts_source ? args->opts_source : "",
>>                                    ignore_stderr);
>> -    if (!args->only_target) {
>> -        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>> -        qtest_qmp_set_event_callback(*from,
>> -                                     migrate_watch_for_events,
>> -                                     &src_state);
>> -    }
>>   
>>       /*
>>        * If the monitor connection is deferred, enable events on the command line
>> @@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>                                    shmem_opts ? shmem_opts : "",
>>                                    args->opts_target ? args->opts_target : "",
>>                                    ignore_stderr);
>> +
>> +    *from = cmd_source;
>> +    *to = cmd_target;
>> +}
>> +
>> +int migrate_start(QTestState **from, QTestState **to, const char *uri,
>> +                  MigrateStart *args)
>> +{
>> +    g_autofree gchar *cmd_source = NULL;
>> +    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;
>> +        }
>> +    }
>> +
>> +    dst_state = (QTestMigrationState) { };
>> +    src_state = (QTestMigrationState) { };
>> +    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
>> +    src_state.suspend_me = args->suspend_me;
>> +
>> +    migrate_args(&cmd_source, &cmd_target, uri, args);
>> +
>> +    if (!args->only_target) {
>> +        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>> +        qtest_qmp_set_event_callback(*from,
>> +                                     migrate_watch_for_events,
>> +                                     &src_state);
>> +    }
>> +
>>       if (!args->only_source) {
>>           *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
>>                                !args->defer_target_connect);
>> @@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>        * 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);
>>       }



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 09/11] migration-test: migrate_args
  2025-09-30 19:59     ` Steven Sistare
@ 2025-09-30 21:14       ` Steven Sistare
  2025-10-01 12:16         ` Fabiano Rosas
  0 siblings, 1 reply; 30+ messages in thread
From: Steven Sistare @ 2025-09-30 21:14 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini, Peter Xu

On 9/30/2025 3:59 PM, Steven Sistare wrote:
> On 9/30/2025 3:51 PM, Fabiano Rosas wrote:
>> Steve Sistare <steven.sistare@oracle.com> writes:
>>
>>> Define the subroutine migrate_args to return the arguments that are
>>> used to exec the source or target qemu process.
>>>
>>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>>> ---
>>>   tests/qtest/migration/framework.h |  2 ++
>>>   tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
>>>   2 files changed, 41 insertions(+), 25 deletions(-)
>>>
>>> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
>>> index 7ff3187..51a8a7e 100644
>>> --- a/tests/qtest/migration/framework.h
>>> +++ b/tests/qtest/migration/framework.h
>>> @@ -226,6 +226,8 @@ typedef struct {
>>>   void wait_for_serial(const char *side);
>>>   void migrate_prepare_for_dirty_mem(QTestState *from);
>>>   void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
>>> +
>>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
>>>   int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>                     MigrateStart *args);
>>>   void migrate_end(QTestState *from, QTestState *to, bool test_dest);
>>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>>> index 8f9e359..2dfb1ee 100644
>>> --- a/tests/qtest/migration/framework.c
>>> +++ b/tests/qtest/migration/framework.c
>>> @@ -258,13 +258,12 @@ static char *test_shmem_path(void)
>>>       return g_strdup_printf("/dev/shm/qemu-%d", getpid());
>>>   }
>>> -int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>> -                  MigrateStart *args)
>>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
>>>   {
>>>       /* options for source and target */
>>>       g_autofree gchar *arch_opts = NULL;
>>> -    g_autofree gchar *cmd_source = NULL;
>>> -    g_autofree gchar *cmd_target = NULL;
>>> +    gchar *cmd_source = NULL;
>>> +    gchar *cmd_target = NULL;
>>>       const gchar *ignore_stderr;
>>>       g_autofree char *shmem_opts = NULL;
>>>       g_autofree char *shmem_path = NULL;
>>> @@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>       const char *memory_size;
>>>       const char *machine_alias, *machine_opts = "";
>>>       g_autofree char *machine = NULL;
>>> -    const char *bootpath;
>>> -    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
>>> +    const char *bootpath = bootfile_get();
>>>       g_autofree char *memory_backend = NULL;
>>>       const char *events;
>>> -    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;
>>> -        }
>>> -    }
>>> -
>>> -    dst_state = (QTestMigrationState) { };
>>> -    src_state = (QTestMigrationState) { };
>>> -    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
>>> -    src_state.suspend_me = args->suspend_me;
>>> -
>>>       if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>>>           memory_size = "150M";
>>> @@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>       if (!qtest_has_machine(machine_alias)) {
>>>           g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
>>>           g_test_skip(msg);
>>> -        return -1;
>>> +        return;
>>
>> A common pitfall is that g_test_skip() doesn't actually ends the
>> test. The -1 needs to be propagated up, otherwise the test will proceed
>> with the unsupported machine.
> 
> Thanks.
> migrate_args() will return an error code.
> I'll send a V2 of this patch, 

Do you prefer I send a patch with just the fix, if you have already
pulled the patches into your tree?

- Steve

> and fix the call to migrate_args in patch
> "cpr-exec test".
> 
> - Steve
> 
>>
>>>       }
>>>       machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
>>> @@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>                                    shmem_opts ? shmem_opts : "",
>>>                                    args->opts_source ? args->opts_source : "",
>>>                                    ignore_stderr);
>>> -    if (!args->only_target) {
>>> -        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>>> -        qtest_qmp_set_event_callback(*from,
>>> -                                     migrate_watch_for_events,
>>> -                                     &src_state);
>>> -    }
>>>       /*
>>>        * If the monitor connection is deferred, enable events on the command line
>>> @@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>                                    shmem_opts ? shmem_opts : "",
>>>                                    args->opts_target ? args->opts_target : "",
>>>                                    ignore_stderr);
>>> +
>>> +    *from = cmd_source;
>>> +    *to = cmd_target;
>>> +}
>>> +
>>> +int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>> +                  MigrateStart *args)
>>> +{
>>> +    g_autofree gchar *cmd_source = NULL;
>>> +    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;
>>> +        }
>>> +    }
>>> +
>>> +    dst_state = (QTestMigrationState) { };
>>> +    src_state = (QTestMigrationState) { };
>>> +    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
>>> +    src_state.suspend_me = args->suspend_me;
>>> +
>>> +    migrate_args(&cmd_source, &cmd_target, uri, args);
>>> +
>>> +    if (!args->only_target) {
>>> +        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>>> +        qtest_qmp_set_event_callback(*from,
>>> +                                     migrate_watch_for_events,
>>> +                                     &src_state);
>>> +    }
>>> +
>>>       if (!args->only_source) {
>>>           *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
>>>                                !args->defer_target_connect);
>>> @@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>        * 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);
>>>       }
> 



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH V1 09/11] migration-test: migrate_args
  2025-09-30 21:14       ` Steven Sistare
@ 2025-10-01 12:16         ` Fabiano Rosas
  0 siblings, 0 replies; 30+ messages in thread
From: Fabiano Rosas @ 2025-10-01 12:16 UTC (permalink / raw)
  To: Steven Sistare, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini, Peter Xu

Steven Sistare <steven.sistare@oracle.com> writes:

> On 9/30/2025 3:59 PM, Steven Sistare wrote:
>> On 9/30/2025 3:51 PM, Fabiano Rosas wrote:
>>> Steve Sistare <steven.sistare@oracle.com> writes:
>>>
>>>> Define the subroutine migrate_args to return the arguments that are
>>>> used to exec the source or target qemu process.
>>>>
>>>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>>>> ---
>>>>   tests/qtest/migration/framework.h |  2 ++
>>>>   tests/qtest/migration/framework.c | 64 ++++++++++++++++++++++++---------------
>>>>   2 files changed, 41 insertions(+), 25 deletions(-)
>>>>
>>>> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
>>>> index 7ff3187..51a8a7e 100644
>>>> --- a/tests/qtest/migration/framework.h
>>>> +++ b/tests/qtest/migration/framework.h
>>>> @@ -226,6 +226,8 @@ typedef struct {
>>>>   void wait_for_serial(const char *side);
>>>>   void migrate_prepare_for_dirty_mem(QTestState *from);
>>>>   void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to);
>>>> +
>>>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args);
>>>>   int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>>                     MigrateStart *args);
>>>>   void migrate_end(QTestState *from, QTestState *to, bool test_dest);
>>>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>>>> index 8f9e359..2dfb1ee 100644
>>>> --- a/tests/qtest/migration/framework.c
>>>> +++ b/tests/qtest/migration/framework.c
>>>> @@ -258,13 +258,12 @@ static char *test_shmem_path(void)
>>>>       return g_strdup_printf("/dev/shm/qemu-%d", getpid());
>>>>   }
>>>> -int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>> -                  MigrateStart *args)
>>>> +void migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
>>>>   {
>>>>       /* options for source and target */
>>>>       g_autofree gchar *arch_opts = NULL;
>>>> -    g_autofree gchar *cmd_source = NULL;
>>>> -    g_autofree gchar *cmd_target = NULL;
>>>> +    gchar *cmd_source = NULL;
>>>> +    gchar *cmd_target = NULL;
>>>>       const gchar *ignore_stderr;
>>>>       g_autofree char *shmem_opts = NULL;
>>>>       g_autofree char *shmem_path = NULL;
>>>> @@ -273,23 +272,10 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>>       const char *memory_size;
>>>>       const char *machine_alias, *machine_opts = "";
>>>>       g_autofree char *machine = NULL;
>>>> -    const char *bootpath;
>>>> -    g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
>>>> +    const char *bootpath = bootfile_get();
>>>>       g_autofree char *memory_backend = NULL;
>>>>       const char *events;
>>>> -    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;
>>>> -        }
>>>> -    }
>>>> -
>>>> -    dst_state = (QTestMigrationState) { };
>>>> -    src_state = (QTestMigrationState) { };
>>>> -    bootpath = bootfile_create(arch, tmpfs, args->suspend_me);
>>>> -    src_state.suspend_me = args->suspend_me;
>>>> -
>>>>       if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>>>>           memory_size = "150M";
>>>> @@ -365,7 +351,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>>       if (!qtest_has_machine(machine_alias)) {
>>>>           g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
>>>>           g_test_skip(msg);
>>>> -        return -1;
>>>> +        return;
>>>
>>> A common pitfall is that g_test_skip() doesn't actually ends the
>>> test. The -1 needs to be propagated up, otherwise the test will proceed
>>> with the unsupported machine.
>> 
>> Thanks.
>> migrate_args() will return an error code.
>> I'll send a V2 of this patch, 
>
> Do you prefer I send a patch with just the fix, if you have already
> pulled the patches into your tree?
>

Yeah, could be.

> - Steve
>
>> and fix the call to migrate_args in patch
>> "cpr-exec test".
>> 
>> - Steve
>> 
>>>
>>>>       }
>>>>       machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
>>>> @@ -386,12 +372,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>>                                    shmem_opts ? shmem_opts : "",
>>>>                                    args->opts_source ? args->opts_source : "",
>>>>                                    ignore_stderr);
>>>> -    if (!args->only_target) {
>>>> -        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>>>> -        qtest_qmp_set_event_callback(*from,
>>>> -                                     migrate_watch_for_events,
>>>> -                                     &src_state);
>>>> -    }
>>>>       /*
>>>>        * If the monitor connection is deferred, enable events on the command line
>>>> @@ -415,6 +395,39 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>>                                    shmem_opts ? shmem_opts : "",
>>>>                                    args->opts_target ? args->opts_target : "",
>>>>                                    ignore_stderr);
>>>> +
>>>> +    *from = cmd_source;
>>>> +    *to = cmd_target;
>>>> +}
>>>> +
>>>> +int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>> +                  MigrateStart *args)
>>>> +{
>>>> +    g_autofree gchar *cmd_source = NULL;
>>>> +    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;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    dst_state = (QTestMigrationState) { };
>>>> +    src_state = (QTestMigrationState) { };
>>>> +    bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
>>>> +    src_state.suspend_me = args->suspend_me;
>>>> +
>>>> +    migrate_args(&cmd_source, &cmd_target, uri, args);
>>>> +
>>>> +    if (!args->only_target) {
>>>> +        *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
>>>> +        qtest_qmp_set_event_callback(*from,
>>>> +                                     migrate_watch_for_events,
>>>> +                                     &src_state);
>>>> +    }
>>>> +
>>>>       if (!args->only_source) {
>>>>           *to = qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities,
>>>>                                !args->defer_target_connect);
>>>> @@ -428,6 +441,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
>>>>        * 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);
>>>>       }
>> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2025-10-01 12:18 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-19 14:12 [PATCH V1 00/11] cpr-exec test Steve Sistare
2025-09-19 14:12 ` [PATCH V1 01/11] tests/qtest: export qtest_qemu_binary Steve Sistare
2025-09-29 14:47   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 02/11] tests/qtest: qtest_qemu_args Steve Sistare
2025-09-29 14:51   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 03/11] tests/qtest: qtest_create_test_state Steve Sistare
2025-09-29 14:52   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 04/11] tests/qtest: qtest_qemu_spawn_func Steve Sistare
2025-09-29 14:57   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 05/11] tests/qtest: qtest_init_after_exec Steve Sistare
2025-09-29 14:59   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 06/11] migration-test: only_source option Steve Sistare
2025-09-29 20:27   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 07/11] migration-test: shm path accessor Steve Sistare
2025-09-29 20:28   ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 08/11] migration-test: misc exports Steve Sistare
2025-09-19 14:12 ` [PATCH V1 09/11] migration-test: migrate_args Steve Sistare
2025-09-29 20:32   ` Fabiano Rosas
2025-09-30 14:35     ` Steven Sistare
2025-09-30 19:51   ` Fabiano Rosas
2025-09-30 19:59     ` Steven Sistare
2025-09-30 21:14       ` Steven Sistare
2025-10-01 12:16         ` Fabiano Rosas
2025-09-19 14:12 ` [PATCH V1 10/11] migration-test: strv parameter Steve Sistare
2025-09-19 14:12 ` [PATCH V1 11/11] migration-test: test cpr-exec Steve Sistare
2025-09-30 17:08   ` Peter Xu
2025-09-30 18:23     ` Steven Sistare
2025-09-30 19:02       ` Peter Xu
2025-09-30 19:07         ` Steven Sistare
2025-09-30 14:35 ` [PATCH V1 00/11] cpr-exec test Fabiano Rosas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).