@@ -175,6 +175,11 @@ static void monitor_fdset_free(MonFdset *mon_fdset)
static void monitor_fdset_free_if_empty(MonFdset *mon_fdset)
{
+ /*
+ * Only remove an empty fdset. The fds are owned by the user and
+ * should have been removed with qmp_remove_fd(). The dup_fds are
+ * owned by QEMU and should have been removed with qemu_close().
+ */
if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
monitor_fdset_free(mon_fdset);
}
@@ -194,9 +199,7 @@ static void monitor_fdset_cleanup(MonFdset *mon_fdset)
MonFdsetFd *mon_fdset_fd_next;
QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
- if ((mon_fdset_fd->removed ||
- (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) &&
- runstate_is_running()) {
+ if (mon_fdset_fd->removed) {
monitor_fdset_fd_free(mon_fdset_fd);
}
}
@@ -211,7 +214,7 @@ void monitor_fdsets_cleanup(void)
QEMU_LOCK_GUARD(&mon_fdsets_lock);
QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
- monitor_fdset_cleanup(mon_fdset);
+ monitor_fdset_free_if_empty(mon_fdset);
}
}
@@ -484,9 +487,7 @@ void monitor_fdset_dup_fd_remove(int dup_fd)
if (mon_fdset_fd_dup->fd == dup_fd) {
QLIST_REMOVE(mon_fdset_fd_dup, next);
g_free(mon_fdset_fd_dup);
- if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
- monitor_fdset_cleanup(mon_fdset);
- }
+ monitor_fdset_free_if_empty(mon_fdset);
return;
}
}
@@ -1437,11 +1437,9 @@ static void monitor_event(void *opaque, QEMUChrEvent event)
monitor_resume(mon);
}
qemu_mutex_unlock(&mon->mon_lock);
- mon_refcount++;
break;
case CHR_EVENT_CLOSED:
- mon_refcount--;
monitor_fdsets_cleanup();
break;
@@ -168,7 +168,6 @@ extern bool qmp_dispatcher_co_shutdown;
extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
extern QemuMutex monitor_lock;
extern MonitorList mon_list;
-extern int mon_refcount;
extern HMPCommand hmp_cmds[];
@@ -71,7 +71,6 @@ static GHashTable *monitor_qapi_event_state;
static GHashTable *coroutine_mon; /* Maps Coroutine* to Monitor* */
MonitorList mon_list;
-int mon_refcount;
static bool monitor_destroyed;
Monitor *monitor_cur(void)
@@ -466,7 +466,6 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
data = qmp_greeting(mon);
qmp_send_response(mon, data);
qobject_unref(data);
- mon_refcount++;
break;
case CHR_EVENT_CLOSED:
/*
@@ -479,7 +478,6 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
json_message_parser_destroy(&mon->parser);
json_message_parser_init(&mon->parser, handle_qmp_command,
mon, NULL);
- mon_refcount--;
monitor_fdsets_cleanup();
break;
case CHR_EVENT_BREAK:
@@ -514,11 +514,6 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
kill(s->qemu_pid, SIGSTOP);
}
#endif
-
- /* ask endianness of the target */
-
- s->big_endian = qtest_query_target_endianness(s);
-
return s;
}
@@ -527,11 +522,21 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
return qtest_init_internal(qtest_qemu_binary(NULL), extra_args);
}
+QTestState *qtest_init_with_env_no_handshake(const char *var,
+ const char *extra_args)
+{
+ return qtest_init_internal(qtest_qemu_binary(var), extra_args);
+}
+
QTestState *qtest_init_with_env(const char *var, const char *extra_args)
{
QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args);
QDict *greeting;
+ /* ask endianness of the target */
+
+ s->big_endian = qtest_query_target_endianness(s);
+
/* Read the QMP greeting and then do the handshake */
greeting = qtest_qmp_receive(s);
qobject_unref(greeting);
@@ -68,6 +68,8 @@ QTestState *qtest_init(const char *extra_args);
*/
QTestState *qtest_init_with_env(const char *var, const char *extra_args);
+QTestState *qtest_init_with_env_no_handshake(const char *var,
+ const char *extra_args);
/**
* qtest_init_without_qmp_handshake:
* @extra_args: other arguments to pass to QEMU. CAUTION: these
@@ -64,6 +64,7 @@ static QTestMigrationState dst_state;
#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */
#define ANALYZE_SCRIPT "scripts/analyze-migration.py"
+#define VMSTATE_CHECKER_SCRIPT "scripts/vmstate-static-checker.py"
#define QEMU_VM_FILE_MAGIC 0x5145564d
#define FILE_TEST_FILENAME "migfile"
@@ -1589,6 +1590,85 @@ static void test_analyze_script(void)
test_migrate_end(from, to, false);
cleanup("migfile");
}
+
+static void test_vmstate_checker_script(void)
+{
+ g_autofree gchar *cmd_src = NULL;
+ g_autofree gchar *cmd_dst = NULL;
+ g_autofree gchar *vmstate_src = NULL;
+ g_autofree gchar *vmstate_dst = NULL;
+ const char *machine_alias, *machine_opts = "";
+ g_autofree char *machine = NULL;
+ const char *arch = qtest_get_arch();
+ int pid, wstatus;
+ const char *python = g_getenv("PYTHON");
+
+ if (!getenv(QEMU_ENV_SRC) && !getenv(QEMU_ENV_DST)) {
+ g_test_skip("Test needs two different QEMU versions");
+ return;
+ }
+
+ if (!python) {
+ g_test_skip("PYTHON variable not set");
+ return;
+ }
+
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ if (g_str_equal(arch, "i386")) {
+ machine_alias = "pc";
+ } else {
+ machine_alias = "q35";
+ }
+ } else if (g_str_equal(arch, "s390x")) {
+ machine_alias = "s390-ccw-virtio";
+ } else if (strcmp(arch, "ppc64") == 0) {
+ machine_alias = "pseries";
+ } else if (strcmp(arch, "aarch64") == 0) {
+ machine_alias = "virt";
+ } else {
+ g_assert_not_reached();
+ }
+
+ if (!qtest_has_machine(machine_alias)) {
+ g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
+ g_test_skip(msg);
+ return;
+ }
+
+ machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
+ QEMU_ENV_DST);
+
+ vmstate_src = g_strdup_printf("%s/vmstate-src", tmpfs);
+ vmstate_dst = g_strdup_printf("%s/vmstate-dst", tmpfs);
+
+ cmd_dst = g_strdup_printf("-machine %s,%s -dump-vmstate %s",
+ machine, machine_opts, vmstate_dst);
+ cmd_src = g_strdup_printf("-machine %s,%s -dump-vmstate %s",
+ machine, machine_opts, vmstate_src);
+
+ qtest_init_with_env_no_handshake(QEMU_ENV_SRC, cmd_src);
+ qtest_init_with_env_no_handshake(QEMU_ENV_DST, cmd_dst);
+
+ pid = fork();
+ if (!pid) {
+ close(1);
+ open("/dev/null", O_WRONLY);
+ execl(python, python, VMSTATE_CHECKER_SCRIPT,
+ "-s", vmstate_src,
+ "-d", vmstate_dst,
+ NULL);
+ g_assert_not_reached();
+ }
+
+ g_assert(waitpid(pid, &wstatus, 0) == pid);
+ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
+ g_test_message("Failed to run vmstate-static-checker.py");
+ g_test_fail();
+ }
+
+ cleanup("vmstate-src");
+ cleanup("vmstate-dst");
+}
#endif
static void test_precopy_common(MigrateCommon *args)
@@ -3522,6 +3602,8 @@ int main(int argc, char **argv)
migration_test_add("/migration/bad_dest", test_baddest);
#ifndef _WIN32
migration_test_add("/migration/analyze-script", test_analyze_script);
+ migration_test_add("/migration/vmstate-checker-script",
+ test_vmstate_checker_script);
#endif
/*