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; +}