From 28409ef05260973788a1ca3c4a41350db6a49f90 Mon Sep 17 00:00:00 2001
Message-Id: <28409ef05260973788a1ca3c4a41350db6a49f90.1429902956.git.jen@redhat.com>
In-Reply-To: <67968bc615637394c3ef7dfefa360dab90f33d5d.1429902956.git.jen@redhat.com>
References: <67968bc615637394c3ef7dfefa360dab90f33d5d.1429902956.git.jen@redhat.com>
From: Max Reitz <mreitz@redhat.com>
Date: Wed, 18 Mar 2015 19:21:57 -0500
Subject: [CHANGE 14/42] qcow2: Add qcow2_signal_corruption()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To: rhvirt-patches@redhat.com,
    jen@redhat.com

RH-Author: Max Reitz <mreitz@redhat.com>
Message-id: <1426706542-30384-15-git-send-email-mreitz@redhat.com>
Patchwork-id: 64478
O-Subject: [RHEL-6.7 qemu-kvm PATCH v2 14/39] qcow2: Add qcow2_signal_corruption()
Bugzilla: 1129892
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>

BZ: 1129892

Add a helper function for easily marking an image corrupt (on fatal
corruptions) while outputting an informative message to stderr and via
QAPI.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Message-id: 1409926039-29044-3-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 85186ebdac7e183242deaa55d5049988de832be1)
Signed-off-by: Jeff E. Nelson <jen@redhat.com>

Conflicts:
	block/qcow2.c
	block/qcow2.h

Different handling of QMP events downstream and different reaction to
fatal corruptions: The image cannot be marked corrupt, it can only be
made unusable for this QEMU instance, and because there is no corruption
flag, the new function requires an additional flag for determining
whether a fatal corruption has been signaled before.

Not having nice event emission function downstreams means preparing the
JSON format string manually; because both 'offset' and 'size' are
optional, this would in theory result in four different combinations. In
practice, 'offset' and 'size' are both either given or not, though,
which reduces the number of combinations to a much nicer two.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.h |  5 +++++
 2 files changed, 67 insertions(+)

Signed-off-by: Jeff E. Nelson <jen@redhat.com>
---
 block/qcow2.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.h |  5 +++++
 2 files changed, 67 insertions(+)

diff --git a/block/qcow2.c b/block/qcow2.c
index aaf2729..b2c175f 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -31,6 +31,8 @@
 #include "qerror.h"
 #include "qapi/util.h"
 #include "qapi-visit.h"
+#include "qemu-objects.h"
+#include "monitor.h"
 
 /*
   Differences with QCOW:
@@ -1488,6 +1490,66 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
     return ret;
 }
 
+/*
+ * If offset or size are negative, respectively, they will not be included in
+ * the BLOCK_IMAGE_CORRUPTED event emitted.
+ * fatal will be ignored for read-only BDS; corruptions found there will always
+ * be considered non-fatal.
+ */
+void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
+                             int64_t size, const char *message_format, ...)
+{
+    BDRVQcowState *s = bs->opaque;
+    char *message;
+    QObject *data;
+    va_list ap;
+
+    fatal = fatal && !bs->read_only;
+
+    if (fatal ? s->signaled_fatal_corruption : s->signaled_corruption) {
+        return;
+    }
+
+    va_start(ap, message_format);
+    message = g_strdup_vprintf(message_format, ap);
+    va_end(ap);
+
+    if (fatal) {
+        fprintf(stderr, "qcow2: Image is corrupt (further access will be "
+                "prevented): %s; please use qemu-img check -r. Further "
+                "corruption events will be suppressed\n", message);
+    } else {
+        fprintf(stderr, "qcow2: Image is corrupt: %s; please use qemu-img "
+                "check -r. Further non-fatal corruption events will be "
+                "suppressed\n", message);
+    }
+
+    assert((offset >= 0) == (size >= 0));
+
+    if (offset >= 0) {
+        data = qobject_from_jsonf("{ 'device': %s, 'msg': %s, 'offset': %"
+                                  PRId64 ", 'size': %" PRId64 ", 'fatal': %s }",
+                                  bdrv_get_device_name(bs), message,
+                                  offset, size, fatal ? "true" : "false");
+    } else {
+        data = qobject_from_jsonf("{ 'device': %s, 'msg': %s, 'fatal': %s }",
+                                  bdrv_get_device_name(bs), message,
+                                  fatal ? "true" : "false");
+    }
+
+    monitor_protocol_event(QEVENT_BLOCK_IMAGE_CORRUPTED, data);
+    qobject_decref(data);
+
+    g_free(message);
+
+    if (fatal) {
+        bs->drv = NULL; /* make BDS unusable */
+        s->signaled_fatal_corruption = true;
+    }
+
+    s->signaled_corruption = true;
+}
+
 static QEMUOptionParameter qcow2_create_options[] = {
     {
         .name = BLOCK_OPT_SIZE,
diff --git a/block/qcow2.h b/block/qcow2.h
index 10b9c0a..767f373 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -165,6 +165,7 @@ typedef struct BDRVQcowState {
     QCowSnapshot *snapshots;
 
     int overlap_check; /* bitmask of Qcow2MetadataOverlap values */
+    bool signaled_corruption, signaled_fatal_corruption;
 
     QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
 } BDRVQcowState;
@@ -297,6 +298,10 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
                   int64_t sector_num, int nb_sectors);
 int qcow2_update_header(BlockDriverState *bs);
 
+void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
+                             int64_t size, const char *message_format, ...)
+                             GCC_FMT_ATTR(5, 6);
+
 /* qcow2-refcount.c functions */
 int qcow2_refcount_init(BlockDriverState *bs);
 void qcow2_refcount_close(BlockDriverState *bs);
-- 
2.1.0

