The method to postpone the intercepted command (pause/suspend/migrate)
until the introspection tool has the chance to remove its hooks
(e.g. breakpoints) from guest doesn't work on snapshot+memory (at
least as it is done by libvirt/virt-manager 1.3.1). The sequence
qmp_stop()+save_vm+qmp_cont() doesn't wait for the STOP event.  save_vm()
is called right after qmp_stop() returns OK. What we do is postpone
this OK response until the introspection tools finishes the unhook
process.

CC: Markus Armbruster <arm...@redhat.com>
Signed-off-by: Adalbert Lazăr <ala...@bitdefender.com>
---
 accel/kvm/vmi.c                | 29 +++++++++++++++++++++++++++++
 accel/stubs/vmi-stubs.c        |  7 +++++++
 include/monitor/monitor.h      |  1 +
 include/sysemu/vmi-intercept.h |  2 +-
 monitor/Makefile.objs          |  2 +-
 monitor/qmp.c                  | 11 +++++++++++
 monitor/stubs.c                |  9 +++++++++
 7 files changed, 59 insertions(+), 2 deletions(-)
 create mode 100644 monitor/stubs.c

diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c
index ea7191e48d..01034d460e 100644
--- a/accel/kvm/vmi.c
+++ b/accel/kvm/vmi.c
@@ -10,6 +10,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
 #include "qemu/error-report.h"
 #include "qom/object_interfaces.h"
 #include "sysemu/sysemu.h"
@@ -23,6 +24,8 @@
 #include "migration/vmstate.h"
 #include "migration/migration.h"
 #include "migration/misc.h"
+#include "qapi/qmp/qobject.h"
+#include "monitor/monitor.h"
 
 #include "sysemu/vmi-intercept.h"
 #include "sysemu/vmi-handshake.h"
@@ -63,6 +66,9 @@ typedef struct VMIntrospection {
     Notifier migration_state_change;
     bool created_from_command_line;
 
+    void *qmp_monitor;
+    QDict *qmp_rsp;
+
     bool kvmi_hooked;
 } VMIntrospection;
 
@@ -333,6 +339,8 @@ static void instance_finalize(Object *obj)
 
     error_free(i->init_error);
 
+    qobject_unref(i->qmp_rsp);
+
     ic->instance_counter--;
     if (!ic->instance_counter) {
         ic->uniq = NULL;
@@ -506,6 +514,12 @@ static void 
continue_with_the_intercepted_action(VMIntrospection *i)
 
     info_report("VMI: continue with '%s'",
                 action_string[i->intercepted_action]);
+
+    if (i->qmp_rsp) {
+        monitor_qmp_respond_later(i->qmp_monitor, i->qmp_rsp);
+        i->qmp_monitor = NULL;
+        i->qmp_rsp = NULL;
+    }
 }
 
 /*
@@ -676,6 +690,21 @@ static VMIntrospection *vm_introspection_object(void)
     return ic ? ic->uniq : NULL;
 }
 
+bool vm_introspection_qmp_delay(void *mon, QDict *rsp)
+{
+    VMIntrospection *i = vm_introspection_object();
+    bool intercepted;
+
+    intercepted = i && i->intercepted_action == VMI_INTERCEPT_SUSPEND;
+
+    if (intercepted) {
+        i->qmp_monitor = mon;
+        i->qmp_rsp = rsp;
+    }
+
+    return intercepted;
+}
+
 /*
  * This ioctl succeeds only when KVM signals the introspection tool.
  * (the socket is connected and the event was sent without error).
diff --git a/accel/stubs/vmi-stubs.c b/accel/stubs/vmi-stubs.c
index 1bd93b2ca5..0cb1d6572b 100644
--- a/accel/stubs/vmi-stubs.c
+++ b/accel/stubs/vmi-stubs.c
@@ -1,7 +1,14 @@
 #include "qemu/osdep.h"
+#include "qapi/qmp/qdict.h"
+
 #include "sysemu/vmi-intercept.h"
 
 bool vm_introspection_intercept(VMI_intercept_command ic, Error **errp)
 {
     return false;
 }
+
+bool vm_introspection_qmp_delay(void *mon, QDict *rsp)
+{
+    return false;
+}
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 1018d754a6..1b3debc635 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -47,5 +47,6 @@ int monitor_fdset_get_fd(int64_t fdset_id, int flags);
 int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
 void monitor_fdset_dup_fd_remove(int dup_fd);
 int64_t monitor_fdset_dup_fd_find(int dup_fd);
+void monitor_qmp_respond_later(void *_mon, QDict *rsp);
 
 #endif /* MONITOR_H */
diff --git a/include/sysemu/vmi-intercept.h b/include/sysemu/vmi-intercept.h
index b4a9a3faa7..4b93d17f2b 100644
--- a/include/sysemu/vmi-intercept.h
+++ b/include/sysemu/vmi-intercept.h
@@ -19,6 +19,6 @@ typedef enum {
 } VMI_intercept_command;
 
 bool vm_introspection_intercept(VMI_intercept_command ic, Error **errp);
-bool vm_introspection_qmp_delay(void *mon, QObject *id, bool resume);
+bool vm_introspection_qmp_delay(void *mon, QDict *rsp);
 
 #endif /* QEMU_VMI_INTERCEPT_H */
diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs
index a8533c9dd7..16652ed162 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -3,4 +3,4 @@ common-obj-y += monitor.o qmp.o hmp.o
 common-obj-y += qmp-cmds.o qmp-cmds-control.o
 common-obj-y += hmp-cmds.o
 
-storage-daemon-obj-y += monitor.o qmp.o qmp-cmds-control.o
+storage-daemon-obj-y += monitor.o qmp.o qmp-cmds-control.o stubs.o
diff --git a/monitor/qmp.c b/monitor/qmp.c
index f89e7daf27..fc9ea7eafa 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -32,6 +32,7 @@
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qlist.h"
 #include "qapi/qmp/qstring.h"
+#include "sysemu/vmi-intercept.h"
 #include "trace.h"
 
 struct QMPRequest {
@@ -158,6 +159,16 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject 
*req)
         }
     }
 
+    if (!vm_introspection_qmp_delay(mon, rsp)) {
+        monitor_qmp_respond(mon, rsp);
+        qobject_unref(rsp);
+    }
+}
+
+void monitor_qmp_respond_later(void *_mon, QDict *rsp)
+{
+    MonitorQMP *mon = _mon;
+
     monitor_qmp_respond(mon, rsp);
     qobject_unref(rsp);
 }
diff --git a/monitor/stubs.c b/monitor/stubs.c
new file mode 100644
index 0000000000..fc5707ae13
--- /dev/null
+++ b/monitor/stubs.c
@@ -0,0 +1,9 @@
+#include "qemu/osdep.h"
+#include "qapi/qmp/qdict.h"
+
+#include "sysemu/vmi-intercept.h"
+
+bool vm_introspection_qmp_delay(void *mon, QDict *rsp)
+{
+    return false;
+}

Reply via email to