This state is similar to io-error, but is not entered on I/O errors but
instead when a request takes longer than a user-defined time (set via
the delay-stop-ns property on a block device, which is not yet available
but will be added by a future patch in this series).

In contrast to other stop states, this state does not drain block
devices.  That is because it is entered only when a request hangs, which
means that draining would be counter-productive.

Signed-off-by: Hanna Czenczek <[email protected]>
---
 qapi/run-state.json |  7 ++++++-
 system/runstate.c   | 25 ++++++++++++++++++-------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/qapi/run-state.json b/qapi/run-state.json
index 8bbd9884087..cf3f43579de 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -53,12 +53,17 @@
 # @colo: guest is paused to save/restore VM state under colo
 #     checkpoint, VM can not get into this state unless colo
 #     capability is enabled for migration.  (since 2.8)
+#
+# @io-hang: An I/O operation has been delayed for too long and the
+#     device is configured to stop the VM when that happens.  In
+#     contrast to other paused states, the VM's block devices will not
+#     be drained when entering this run state.  (since 11.2)
 ##
 { 'enum': 'RunState',
   'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
             'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
             'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
-            'guest-panicked', 'colo' ] }
+            'guest-panicked', 'colo', 'io-hang' ] }
 
 ##
 # @ShutdownCause:
diff --git a/system/runstate.c b/system/runstate.c
index 7b3233f77f6..c5b56308735 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -98,6 +98,7 @@ static const RunStateTransition runstate_transitions_def[] = {
     { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
     { RUN_STATE_INMIGRATE, RUN_STATE_POSTMIGRATE },
     { RUN_STATE_INMIGRATE, RUN_STATE_COLO },
+    { RUN_STATE_INMIGRATE, RUN_STATE_IO_HANG },
 
     { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
     { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
@@ -135,6 +136,7 @@ static const RunStateTransition runstate_transitions_def[] 
= {
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_SUSPENDED },
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_WATCHDOG },
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_GUEST_PANICKED },
+    { RUN_STATE_FINISH_MIGRATE, RUN_STATE_IO_HANG },
 
     { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
     { RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH },
@@ -155,6 +157,7 @@ static const RunStateTransition runstate_transitions_def[] 
= {
     { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
     { RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED },
     { RUN_STATE_RUNNING, RUN_STATE_COLO},
+    { RUN_STATE_RUNNING, RUN_STATE_IO_HANG },
 
     { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
     { RUN_STATE_SAVE_VM, RUN_STATE_SUSPENDED },
@@ -175,6 +178,7 @@ static const RunStateTransition runstate_transitions_def[] 
= {
     { RUN_STATE_SUSPENDED, RUN_STATE_RESTORE_VM },
     { RUN_STATE_SUSPENDED, RUN_STATE_SHUTDOWN },
     { RUN_STATE_SUSPENDED, RUN_STATE_IO_ERROR },
+    { RUN_STATE_SUSPENDED, RUN_STATE_IO_HANG },
 
     { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
     { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
@@ -185,6 +189,11 @@ static const RunStateTransition runstate_transitions_def[] 
= {
     { RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE },
     { RUN_STATE_GUEST_PANICKED, RUN_STATE_PRELAUNCH },
 
+    { RUN_STATE_IO_HANG, RUN_STATE_RUNNING },
+    { RUN_STATE_IO_HANG, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_IO_HANG, RUN_STATE_PRELAUNCH },
+    { RUN_STATE_IO_HANG, RUN_STATE_SUSPENDED },
+
     { RUN_STATE__MAX, RUN_STATE__MAX },
 };
 
@@ -445,13 +454,15 @@ static int do_vm_stop(RunState state, bool send_stop)
         }
     }
 
-    bdrv_drain_all();
-    /*
-     * Even if vm_state_notify() return failure,
-     * it would be better to flush as before.
-     */
-    ret |= bdrv_flush_all();
-    trace_vm_stop_flush_all(ret);
+    if (state != RUN_STATE_IO_HANG) {
+        bdrv_drain_all();
+        /*
+         * Even if vm_state_notify() return failure,
+         * it would be better to flush as before.
+         */
+        ret |= bdrv_flush_all();
+        trace_vm_stop_flush_all(ret);
+    }
 
     return ret;
 }
-- 
2.55.0


Reply via email to