76daa3
From 769222403cfbd340ea3358eb1322907c550e5911 Mon Sep 17 00:00:00 2001
76daa3
From: Eric Blake <eblake@redhat.com>
76daa3
Date: Thu, 1 Jun 2017 16:58:21 +0200
76daa3
Subject: [PATCH 05/17] shutdown: Expose bool cause in SHUTDOWN and RESET
76daa3
 events
76daa3
76daa3
RH-Author: Eric Blake <eblake@redhat.com>
76daa3
Message-id: <20170601165821.26810-6-eblake@redhat.com>
76daa3
Patchwork-id: 75466
76daa3
O-Subject: [RHEL-7.4 qemu-kvm-rhev PATCH v2 5/5] shutdown: Expose bool cause in SHUTDOWN and RESET events
76daa3
Bugzilla: 1418927
76daa3
RH-Acked-by: John Snow <jsnow@redhat.com>
76daa3
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
76daa3
RH-Acked-by: Thomas Huth <thuth@redhat.com>
76daa3
76daa3
Libvirt would like to be able to distinguish between a SHUTDOWN
76daa3
event triggered solely by guest request and one triggered by a
76daa3
SIGTERM or other action on the host.  While qemu_kill_report() was
76daa3
already able to give different output to stderr based on whether a
76daa3
shutdown was triggered by a host signal (but NOT by a host UI event,
76daa3
such as clicking the X on the window), that information was then
76daa3
lost to management.  The previous patches improved things to use an
76daa3
enum throughout all callsites, so now we have something ready to
76daa3
expose through QMP.
76daa3
76daa3
Note that for now, the decision was to expose ONLY a boolean,
76daa3
rather than promoting ShutdownCause to a QAPI enum; this is because
76daa3
libvirt has not expressed an interest in anything finer-grained.
76daa3
We can still add additional details, in a backwards-compatible
76daa3
manner, if a need later arises (if the addition happens before 2.10,
76daa3
we can replace the bool with an enum; otherwise, the enum will have
76daa3
to be in addition to the bool); this patch merely adds a helper
76daa3
shutdown_caused_by_guest() to map the internal enum into the
76daa3
external boolean.
76daa3
76daa3
Update expected iotest outputs to match the new data (complete
76daa3
coverage of the affected tests is obtained by -raw, -qcow2, and -nbd).
76daa3
76daa3
Here is output from 'virsh qemu-monitor-event --loop' with the
76daa3
patch installed:
76daa3
76daa3
event SHUTDOWN at 1492639680.731251 for domain fedora_13: {"guest":true}
76daa3
event STOP at 1492639680.732116 for domain fedora_13: <null>
76daa3
event SHUTDOWN at 1492639680.732830 for domain fedora_13: {"guest":false}
76daa3
76daa3
Note that libvirt runs qemu with -no-shutdown: the first SHUTDOWN event
76daa3
was triggered by an action I took directly in the guest (shutdown -h),
76daa3
at which point qemu stops the vcpus and waits for libvirt to do any
76daa3
final cleanups; the second SHUTDOWN event is the result of libvirt
76daa3
sending SIGTERM now that it has completed cleanup.  Libvirt is already
76daa3
smart enough to only feed the first qemu SHUTDOWN event to the end user
76daa3
(remember, virsh qemu-monitor-event is a low-level debugging interface
76daa3
that is explicitly unsupported by libvirt, so it sees things that normal
76daa3
end users do not); changing qemu to emit SHUTDOWN only once is outside
76daa3
the scope of this series.
76daa3
76daa3
See also https://bugzilla.redhat.com/1384007
76daa3
76daa3
Signed-off-by: Eric Blake <eblake@redhat.com>
76daa3
Message-Id: <20170515214114.15442-6-eblake@redhat.com>
76daa3
Reviewed-by: Markus Armbruster <armbru@redhat.com>
76daa3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
76daa3
(cherry picked from commit 08fba7ac9b618516a5f1d096f78a7e2837fe0594)
76daa3
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
---
76daa3
 include/sysemu/sysemu.h    |  5 +++++
76daa3
 qapi/event.json            | 17 +++++++++++++----
76daa3
 tests/qemu-iotests/071.out |  4 ++--
76daa3
 tests/qemu-iotests/081.out |  2 +-
76daa3
 tests/qemu-iotests/087.out | 12 ++++++------
76daa3
 tests/qemu-iotests/094.out |  2 +-
76daa3
 tests/qemu-iotests/117.out |  2 +-
76daa3
 tests/qemu-iotests/119.out |  2 +-
76daa3
 tests/qemu-iotests/120.out |  2 +-
76daa3
 tests/qemu-iotests/140.out |  2 +-
76daa3
 tests/qemu-iotests/143.out |  2 +-
76daa3
 tests/qemu-iotests/156.out |  2 +-
76daa3
 vl.c                       |  8 ++++----
76daa3
 13 files changed, 38 insertions(+), 24 deletions(-)
76daa3
76daa3
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
76daa3
index 01a2c67..9e6f174 100644
76daa3
--- a/include/sysemu/sysemu.h
76daa3
+++ b/include/sysemu/sysemu.h
76daa3
@@ -49,6 +49,11 @@ typedef enum ShutdownCause {
76daa3
     SHUTDOWN_CAUSE__MAX,
76daa3
 } ShutdownCause;
76daa3
 
76daa3
+static inline bool shutdown_caused_by_guest(ShutdownCause cause)
76daa3
+{
76daa3
+    return cause >= SHUTDOWN_CAUSE_GUEST_SHUTDOWN;
76daa3
+}
76daa3
+
76daa3
 void vm_start(void);
76daa3
 int vm_prepare_start(void);
76daa3
 int vm_stop(RunState state);
76daa3
diff --git a/qapi/event.json b/qapi/event.json
76daa3
index e80f3f4..6d22b02 100644
76daa3
--- a/qapi/event.json
76daa3
+++ b/qapi/event.json
76daa3
@@ -10,6 +10,10 @@
76daa3
 # Emitted when the virtual machine has shut down, indicating that qemu is
76daa3
 # about to exit.
76daa3
 #
76daa3
+# @guest: If true, the shutdown was triggered by a guest request (such as
76daa3
+# a guest-initiated ACPI shutdown request or other hardware-specific action)
76daa3
+# rather than a host request (such as sending qemu a SIGINT). (since 2.10)
76daa3
+#
76daa3
 # Note: If the command-line option "-no-shutdown" has been specified, qemu will
76daa3
 # not exit, and a STOP event will eventually follow the SHUTDOWN event
76daa3
 #
76daa3
@@ -17,11 +21,11 @@
76daa3
 #
76daa3
 # Example:
76daa3
 #
76daa3
-# <- { "event": "SHUTDOWN",
76daa3
+# <- { "event": "SHUTDOWN", "data": { "guest": true },
76daa3
 #      "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
76daa3
 #
76daa3
 ##
76daa3
-{ 'event': 'SHUTDOWN' }
76daa3
+{ 'event': 'SHUTDOWN', 'data': { 'guest': 'bool' } }
76daa3
 
76daa3
 ##
76daa3
 # @POWERDOWN:
76daa3
@@ -44,15 +48,20 @@
76daa3
 #
76daa3
 # Emitted when the virtual machine is reset
76daa3
 #
76daa3
+# @guest: If true, the reset was triggered by a guest request (such as
76daa3
+# a guest-initiated ACPI reboot request or other hardware-specific action)
76daa3
+# rather than a host request (such as the QMP command system_reset).
76daa3
+# (since 2.10)
76daa3
+#
76daa3
 # Since: 0.12.0
76daa3
 #
76daa3
 # Example:
76daa3
 #
76daa3
-# <- { "event": "RESET",
76daa3
+# <- { "event": "RESET", "data": { "guest": false },
76daa3
 #      "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
76daa3
 #
76daa3
 ##
76daa3
-{ 'event': 'RESET' }
76daa3
+{ 'event': 'RESET', 'data': { 'guest': 'bool' } }
76daa3
 
76daa3
 ##
76daa3
 # @STOP:
76daa3
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
76daa3
index dd879f1..1d5e28d 100644
76daa3
--- a/tests/qemu-iotests/071.out
76daa3
+++ b/tests/qemu-iotests/071.out
76daa3
@@ -46,7 +46,7 @@ QMP_VERSION
76daa3
 read failed: Input/output error
76daa3
 {"return": ""}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 
76daa3
 === Testing blkverify on existing block device ===
76daa3
@@ -85,7 +85,7 @@ wrote 512/512 bytes at offset 0
76daa3
 read failed: Input/output error
76daa3
 {"return": ""}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 QEMU_PROG: Failed to flush the L2 table cache: Input/output error
76daa3
 QEMU_PROG: Failed to flush the refcount block cache: Input/output error
76daa3
 
76daa3
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
76daa3
index 97df69d..2533c31 100644
76daa3
--- a/tests/qemu-iotests/081.out
76daa3
+++ b/tests/qemu-iotests/081.out
76daa3
@@ -36,7 +36,7 @@ read 10485760/10485760 bytes at offset 0
76daa3
 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
 {"return": ""}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 
76daa3
 == using quorum rewrite corrupted mode ==
76daa3
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
76daa3
index dc6baf9..59c5208 100644
76daa3
--- a/tests/qemu-iotests/087.out
76daa3
+++ b/tests/qemu-iotests/087.out
76daa3
@@ -8,7 +8,7 @@ QMP_VERSION
76daa3
 {"return": {}}
76daa3
 {"error": {"class": "GenericError", "desc": "'node-name' must be specified for the root node"}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 
76daa3
 === Duplicate ID ===
76daa3
@@ -19,7 +19,7 @@ QMP_VERSION
76daa3
 {"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}}
76daa3
 {"error": {"class": "GenericError", "desc": "Duplicate node name"}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 
76daa3
 === aio=native without O_DIRECT ===
76daa3
@@ -29,7 +29,7 @@ QMP_VERSION
76daa3
 {"return": {}}
76daa3
 {"error": {"class": "GenericError", "desc": "aio=native was specified, but it requires cache.direct=on, which was not specified."}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 
76daa3
 === Encrypted image ===
76daa3
@@ -40,14 +40,14 @@ QMP_VERSION
76daa3
 {"return": {}}
76daa3
 {"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 Testing:
76daa3
 QMP_VERSION
76daa3
 {"return": {}}
76daa3
 {"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 
76daa3
 === Missing driver ===
76daa3
@@ -58,6 +58,6 @@ QMP_VERSION
76daa3
 {"return": {}}
76daa3
 {"error": {"class": "GenericError", "desc": "Parameter 'driver' is missing"}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 *** done
76daa3
diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out
76daa3
index b66dc07..f52baff 100644
76daa3
--- a/tests/qemu-iotests/094.out
76daa3
+++ b/tests/qemu-iotests/094.out
76daa3
@@ -7,5 +7,5 @@ Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864
76daa3
 {"return": {}}
76daa3
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 *** done
76daa3
diff --git a/tests/qemu-iotests/117.out b/tests/qemu-iotests/117.out
76daa3
index f52dc1a..851e214 100644
76daa3
--- a/tests/qemu-iotests/117.out
76daa3
+++ b/tests/qemu-iotests/117.out
76daa3
@@ -7,7 +7,7 @@ wrote 65536/65536 bytes at offset 0
76daa3
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
 {"return": ""}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 No errors were found on the image.
76daa3
 read 65536/65536 bytes at offset 0
76daa3
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
diff --git a/tests/qemu-iotests/119.out b/tests/qemu-iotests/119.out
76daa3
index 58e7114..a8743b8 100644
76daa3
--- a/tests/qemu-iotests/119.out
76daa3
+++ b/tests/qemu-iotests/119.out
76daa3
@@ -6,6 +6,6 @@ read 65536/65536 bytes at offset 0
76daa3
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
 {"return": ""}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 *** done
76daa3
diff --git a/tests/qemu-iotests/120.out b/tests/qemu-iotests/120.out
76daa3
index 9131b1b..1af1aeb 100644
76daa3
--- a/tests/qemu-iotests/120.out
76daa3
+++ b/tests/qemu-iotests/120.out
76daa3
@@ -6,7 +6,7 @@ wrote 65536/65536 bytes at offset 0
76daa3
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
 {"return": ""}
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 read 65536/65536 bytes at offset 0
76daa3
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
 read 65536/65536 bytes at offset 0
76daa3
diff --git a/tests/qemu-iotests/140.out b/tests/qemu-iotests/140.out
76daa3
index 6c04456..0689b2b 100644
76daa3
--- a/tests/qemu-iotests/140.out
76daa3
+++ b/tests/qemu-iotests/140.out
76daa3
@@ -10,5 +10,5 @@ read 65536/65536 bytes at offset 0
76daa3
 {"return": {}}
76daa3
 can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: No export with name 'drv' available
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 *** done
76daa3
diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out
76daa3
index d24ad20..0978b89 100644
76daa3
--- a/tests/qemu-iotests/143.out
76daa3
+++ b/tests/qemu-iotests/143.out
76daa3
@@ -3,5 +3,5 @@ QA output created by 143
76daa3
 {"return": {}}
76daa3
 can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: No export with name 'no_such_export' available
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 *** done
76daa3
diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out
76daa3
index 3af82ae..f96a564 100644
76daa3
--- a/tests/qemu-iotests/156.out
76daa3
+++ b/tests/qemu-iotests/156.out
76daa3
@@ -34,7 +34,7 @@ read 65536/65536 bytes at offset 196608
76daa3
 {"return": ""}
76daa3
 
76daa3
 {"return": {}}
76daa3
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
76daa3
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
76daa3
 
76daa3
 read 65536/65536 bytes at offset 0
76daa3
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76daa3
diff --git a/vl.c b/vl.c
76daa3
index 76d7708..518b3cb 100644
76daa3
--- a/vl.c
76daa3
+++ b/vl.c
76daa3
@@ -1704,8 +1704,8 @@ void qemu_system_reset(ShutdownCause reason)
76daa3
         qemu_devices_reset();
76daa3
     }
76daa3
     if (reason) {
76daa3
-        /* TODO update event based on reason */
76daa3
-        qapi_event_send_reset(&error_abort);
76daa3
+        qapi_event_send_reset(shutdown_caused_by_guest(reason),
76daa3
+                              &error_abort);
76daa3
     }
76daa3
     cpu_synchronize_all_post_reset();
76daa3
 }
76daa3
@@ -1862,8 +1862,8 @@ static bool main_loop_should_exit(void)
76daa3
     request = qemu_shutdown_requested();
76daa3
     if (request) {
76daa3
         qemu_kill_report();
76daa3
-        /* TODO update event based on request */
76daa3
-        qapi_event_send_shutdown(&error_abort);
76daa3
+        qapi_event_send_shutdown(shutdown_caused_by_guest(request),
76daa3
+                                 &error_abort);
76daa3
         if (no_shutdown) {
76daa3
             vm_stop(RUN_STATE_SHUTDOWN);
76daa3
         } else {
76daa3
-- 
76daa3
1.8.3.1
76daa3