From 44f3e45bee17ae8672afed90b0c58b52f1787cec Mon Sep 17 00:00:00 2001
From: Luiz Capitulino <lcapitulino@redhat.com>
Date: Fri, 1 May 2015 13:47:09 +0200
Subject: [PATCH 2/6] qmp: add error reason to the BLOCK_IO_ERROR event

Message-id: <1430488030-11529-2-git-send-email-lcapitulino@redhat.com>
Patchwork-id: 64969
O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH 1/2] qmp: add error reason to the BLOCK_IO_ERROR event
Bugzilla: 1199174
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Eric Blake <eblake@redhat.com>

This commit forward ports the following RHEL-7.0 commit to RHEL-7.2:

  commit 771a3a333eb0c9299a69a78ddb9c4181850b827d
  Author: Laszlo Ersek <lersek@redhat.com>
  Date:   Thu Nov 21 16:27:18 2013 +0100

  error reason in BLOCK_IO_ERROR / BLOCK_JOB_ERROR events (RHEL 6->7 fwd)

I had to redo the work because now events use the QAPI, but it
was straightforward.

There's one significant difference though: this commit does not
extend the BLOCK_JOB_ERROR event as did the RHEL-7.0 commit. The
reason is that this extension was supposed to be used only by vdsm
and I don't think there's a requirement to have the extension
in BLOCK_JOB_ERROR too. Let's not spread it.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
 block.c                 | 27 +++++++++++++++++++++++----
 docs/qmp/qmp-events.txt |  9 ++++++++-
 qapi/block-core.json    | 12 +++++++++++-
 3 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/block.c b/block.c
index f2f8ae7..2193868 100644
--- a/block.c
+++ b/block.c
@@ -3666,9 +3666,25 @@ BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int e
     }
 }
 
+/* https://bugzilla.redhat.com/show_bug.cgi?id=1199174 */
+static RHEL7BlockErrorReason get_rhel7_error_reason(int error)
+{
+	switch (error) {
+	case ENOSPC:
+        return RHEL7_BLOCK_ERROR_REASON_ENOSPC;
+	case EPERM:
+        return RHEL7_BLOCK_ERROR_REASON_EPERM;
+	case EIO:
+        return RHEL7_BLOCK_ERROR_REASON_EIO;
+	default:
+        return RHEL7_BLOCK_ERROR_REASON_EOTHER;
+    }
+}
+
 static void send_qmp_error_event(BlockDriverState *bs,
                                  BlockErrorAction action,
-                                 bool is_read, int error)
+                                 bool is_read, int error,
+                                 RHEL7BlockErrorReason res)
 {
     IoOperationType optype;
 
@@ -3676,7 +3692,7 @@ static void send_qmp_error_event(BlockDriverState *bs,
     qapi_event_send_block_io_error(bdrv_get_device_name(bs), optype, action,
                                    bdrv_iostatus_is_enabled(bs),
                                    error == ENOSPC, strerror(error),
-                                   &error_abort);
+                                   res, &error_abort);
 }
 
 /* This is done by device models because, while the block layer knows
@@ -3686,7 +3702,10 @@ static void send_qmp_error_event(BlockDriverState *bs,
 void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
                        bool is_read, int error)
 {
+    RHEL7BlockErrorReason res;
+
     assert(error >= 0);
+    res = get_rhel7_error_reason(error);
 
     if (action == BLOCK_ERROR_ACTION_STOP) {
         /* First set the iostatus, so that "info block" returns an iostatus
@@ -3704,10 +3723,10 @@ void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
          * also ensures that the STOP/RESUME pair of events is emitted.
          */
         qemu_system_vmstop_request_prepare();
-        send_qmp_error_event(bs, action, is_read, error);
+        send_qmp_error_event(bs, action, is_read, error, res);
         qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
     } else {
-        send_qmp_error_event(bs, action, is_read, error);
+        send_qmp_error_event(bs, action, is_read, error, res);
     }
 }
 
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index d759d19..40c2917 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -63,13 +63,20 @@ Data:
     "ignore": error has been ignored
     "report": error has been reported to the device
     "stop": the VM is going to stop because of the error
+- "__com.redhat_reason": error reason, this is a RHEL7 extension, it's one of
+  the following (json-string):
+    "eio": errno EIO
+	"eperm": errno EPERM
+	"enospc": errno ENOSPC
+	"eother": any other errno (other than EIO, EPERM, ENOSPC)
 
 Example:
 
 { "event": "BLOCK_IO_ERROR",
     "data": { "device": "ide0-hd1",
               "operation": "write",
-              "action": "stop" },
+              "action": "stop",
+              "__com.redhat_reason": "enospc" },
     "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
 
 Note: If action is "stop", a STOP event will eventually follow the
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 7873084..8796eaf 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1780,6 +1780,14 @@
             'fatal'  : 'bool' } }
 
 ##
+# @RHEL7BlockErrorReason
+#
+# Block I/O error reason
+##
+{ 'enum': 'RHEL7BlockErrorReason',
+  'data': [ 'enospc', 'eperm', 'eio', 'eother' ] }
+
+##
 # @BLOCK_IO_ERROR
 #
 # Emitted when a disk I/O error occurs
@@ -1799,6 +1807,8 @@
 #          (This field is a debugging aid for humans, it should not
 #           be parsed by applications) (since: 2.2)
 #
+# @__com.redhat_reason: error reason (RHEL7 vendor extension)
+#
 # Note: If action is "stop", a STOP event will eventually follow the
 # BLOCK_IO_ERROR event
 #
@@ -1807,7 +1817,7 @@
 { 'event': 'BLOCK_IO_ERROR',
   'data': { 'device': 'str', 'operation': 'IoOperationType',
             'action': 'BlockErrorAction', '*nospace': 'bool',
-            'reason': 'str' } }
+            'reason': 'str', '__com.redhat_reason': 'RHEL7BlockErrorReason' } }
 
 ##
 # @BLOCK_JOB_COMPLETED
-- 
1.8.3.1