All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/7] blkdebug
@ 2010-03-22 10:00 Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 1/7] qemu-config: qemu_read_config_file() reads the normal config file Kevin Wolf
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

This patch series introduces a new block driver which acts as a protocol and
whose purpose it is to fail requests. To be more precise, I want it to fail in
configurable places, so that qemu-iotests can be extended with tests for the
error paths (for example for the case when something with metadata writes goes
wrong deep in qcow2).

It works like this (I think this is self-explanatory):

$ cat /tmp/blkdebug.cfg
[inject-error]
event = "l1_update"
errno = "5"
immediately = "on"
$ qemu-io blkdebug:/tmp/blkdebug.cfg:/tmp/empty.qcow2
qemu-io> read 0 4k
read 4096/4096 bytes at offset 0
4 KiB, 1 ops; 0.0000 sec (195.312 MiB/sec and 50000.0000 ops/sec)
qemu-io> write 0 4k
write failed: Input/output error

Changes in comparison to the RFC:
- Had to rebase qemu-config changes
- Code cleanup (including resolving TODOs and FIXMEs)
- More events all over qcow2
- No debug messages on stderr any more

Kevin Wolf (7):
  qemu-config: qemu_read_config_file() reads the normal config file
  qemu-config: Make qemu_config_parse more generic
  blkdebug: Basic request passthrough
  blkdebug: Inject errors
  Make qemu-config available for tools
  blkdebug: Add events and rules
  qcow2: Trigger blkdebug events

 Makefile.objs          |    6 +-
 block.c                |   12 ++
 block.h                |   53 ++++++
 block/blkdebug.c       |  474 ++++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2-cluster.c  |   15 ++
 block/qcow2-refcount.c |   18 ++
 block/qcow2.c          |    6 +
 block_int.h            |    2 +
 hw/qdev-properties.c   |   19 ++-
 hw/qdev.h              |    1 -
 qemu-config.c          |   48 +++---
 qemu-config.h          |    4 +-
 qemu-tool.c            |    4 +
 vl.c                   |   38 ++---
 14 files changed, 647 insertions(+), 53 deletions(-)
 create mode 100644 block/blkdebug.c

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/7] qemu-config: qemu_read_config_file() reads the normal config file
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 2/7] qemu-config: Make qemu_config_parse more generic Kevin Wolf
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

Introduce a new function qemu_read_config_file which reads the VM configuration
from a config file. Unlike qemu_config_parse it doesn't take a open file but a
filename and reduces code duplication as a side effect.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-config.c |   15 +++++++++++++++
 qemu-config.h |    2 ++
 vl.c          |   38 +++++++++++++-------------------------
 3 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/qemu-config.c b/qemu-config.c
index 150157c..57dc9a5 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -489,3 +489,18 @@ out:
     loc_pop(&loc);
     return res;
 }
+
+int qemu_read_config_file(const char *filename)
+{
+    FILE *f = fopen(filename, "r");
+    if (f == NULL) {
+        return -errno;
+    }
+
+    if (qemu_config_parse(f, filename) != 0) {
+        return -EINVAL;
+    }
+    fclose(f);
+
+    return 0;
+}
diff --git a/qemu-config.h b/qemu-config.h
index f217c58..07a7a27 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -19,4 +19,6 @@ void qemu_add_globals(void);
 void qemu_config_write(FILE *fp);
 int qemu_config_parse(FILE *fp, const char *fname);
 
+int qemu_read_config_file(const char *filename);
+
 #endif /* QEMU_CONFIG_H */
diff --git a/vl.c b/vl.c
index 6948157..08294ff 100644
--- a/vl.c
+++ b/vl.c
@@ -3828,25 +3828,17 @@ int main(int argc, char **argv, char **envp)
     }
 
     if (defconfig) {
-        const char *fname;
-        FILE *fp;
+        int ret;
 
-        fname = CONFIG_QEMU_CONFDIR "/qemu.conf";
-        fp = fopen(fname, "r");
-        if (fp) {
-            if (qemu_config_parse(fp, fname) != 0) {
-                exit(1);
-            }
-            fclose(fp);
+        ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf");
+        if (ret == -EINVAL) {
+            exit(1);
         }
 
-        fname = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf";
-        fp = fopen(fname, "r");
-        if (fp) {
-            if (qemu_config_parse(fp, fname) != 0) {
-                exit(1);
-            }
-            fclose(fp);
+        ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR
+            "/target-" TARGET_ARCH ".conf");
+        if (ret == -EINVAL) {
+            exit(1);
         }
     }
 #if defined(cpudef_setup)
@@ -4522,16 +4514,12 @@ int main(int argc, char **argv, char **envp)
 #endif
             case QEMU_OPTION_readconfig:
                 {
-                    FILE *fp;
-                    fp = fopen(optarg, "r");
-                    if (fp == NULL) {
-                        fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
+                    int ret = qemu_read_config_file(optarg);
+                    if (ret < 0) {
+                        fprintf(stderr, "read config %s: %s\n", optarg,
+                            strerror(-ret));
                         exit(1);
                     }
-                    if (qemu_config_parse(fp, optarg) != 0) {
-                        exit(1);
-                    }
-                    fclose(fp);
                     break;
                 }
             case QEMU_OPTION_writeconfig:
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/7] qemu-config: Make qemu_config_parse more generic
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 1/7] qemu-config: qemu_read_config_file() reads the normal config file Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 3/7] blkdebug: Basic request passthrough Kevin Wolf
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

qemu_config_parse gets the option groups as a parameter now instead of
hardcoding the VM configuration groups. This way it can be used for other
configurations, too.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-config.c |   18 ++++++++++++------
 qemu-config.h |    2 +-
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/qemu-config.c b/qemu-config.c
index 57dc9a5..dedf177 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -296,7 +296,7 @@ QemuOptsList qemu_cpudef_opts = {
     },
 };
 
-static QemuOptsList *lists[] = {
+static QemuOptsList *vm_config_groups[] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
     &qemu_device_opts,
@@ -309,7 +309,7 @@ static QemuOptsList *lists[] = {
     NULL,
 };
 
-QemuOptsList *qemu_find_opts(const char *group)
+static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
 {
     int i;
 
@@ -323,6 +323,11 @@ QemuOptsList *qemu_find_opts(const char *group)
     return lists[i];
 }
 
+QemuOptsList *qemu_find_opts(const char *group)
+{
+    return find_list(vm_config_groups, group);
+}
+
 int qemu_set_option(const char *str)
 {
     char group[64], id[64], arg[64];
@@ -421,6 +426,7 @@ static int config_write_opts(QemuOpts *opts, void *opaque)
 void qemu_config_write(FILE *fp)
 {
     struct ConfigWriteData data = { .fp = fp };
+    QemuOptsList **lists = vm_config_groups;
     int i;
 
     fprintf(fp, "# qemu config file\n\n");
@@ -430,7 +436,7 @@ void qemu_config_write(FILE *fp)
     }
 }
 
-int qemu_config_parse(FILE *fp, const char *fname)
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
 {
     char line[1024], group[64], id[64], arg[64], value[1024];
     Location loc;
@@ -451,7 +457,7 @@ int qemu_config_parse(FILE *fp, const char *fname)
         }
         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
             /* group with id */
-            list = qemu_find_opts(group);
+            list = find_list(lists, group);
             if (list == NULL)
                 goto out;
             opts = qemu_opts_create(list, id, 1);
@@ -459,7 +465,7 @@ int qemu_config_parse(FILE *fp, const char *fname)
         }
         if (sscanf(line, "[%63[^]]]", group) == 1) {
             /* group without id */
-            list = qemu_find_opts(group);
+            list = find_list(lists, group);
             if (list == NULL)
                 goto out;
             opts = qemu_opts_create(list, NULL, 0);
@@ -497,7 +503,7 @@ int qemu_read_config_file(const char *filename)
         return -errno;
     }
 
-    if (qemu_config_parse(f, filename) != 0) {
+    if (qemu_config_parse(f, vm_config_groups, filename) != 0) {
         return -EINVAL;
     }
     fclose(f);
diff --git a/qemu-config.h b/qemu-config.h
index 07a7a27..dd299c2 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -17,7 +17,7 @@ int qemu_global_option(const char *str);
 void qemu_add_globals(void);
 
 void qemu_config_write(FILE *fp);
-int qemu_config_parse(FILE *fp, const char *fname);
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
 
 int qemu_read_config_file(const char *filename);
 
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 3/7] blkdebug: Basic request passthrough
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 1/7] qemu-config: qemu_read_config_file() reads the normal config file Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 2/7] qemu-config: Make qemu_config_parse more generic Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 4/7] blkdebug: Inject errors Kevin Wolf
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

This isn't doing anything interesting. It creates the blkdebug block driver as
a protocol which just passes everything through to raw.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 Makefile.objs    |    2 +-
 block/blkdebug.c |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 1 deletions(-)
 create mode 100644 block/blkdebug.c

diff --git a/Makefile.objs b/Makefile.objs
index e791dd5..ece02d5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -14,7 +14,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
 block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
-block-nested-y += parallels.o nbd.o
+block-nested-y += parallels.o nbd.o blkdebug.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
 block-nested-$(CONFIG_CURL) += curl.o
diff --git a/block/blkdebug.c b/block/blkdebug.c
new file mode 100644
index 0000000..2c7e0dd
--- /dev/null
+++ b/block/blkdebug.c
@@ -0,0 +1,104 @@
+/*
+ * Block protocol for I/O error injection
+ *
+ * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+typedef struct BDRVBlkdebugState {
+    BlockDriverState *hd;
+} BDRVBlkdebugState;
+
+static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+
+    if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
+        return -EINVAL;
+    }
+    filename += strlen("blkdebug:");
+
+    return bdrv_file_open(&s->hd, filename, flags);
+}
+
+static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
+    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    BlockDriverAIOCB *acb =
+        bdrv_aio_readv(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
+    return acb;
+}
+
+static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
+    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    BlockDriverAIOCB *acb =
+        bdrv_aio_writev(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
+    return acb;
+}
+
+static void blkdebug_close(BlockDriverState *bs)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    bdrv_delete(s->hd);
+}
+
+static void blkdebug_flush(BlockDriverState *bs)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    bdrv_flush(s->hd);
+}
+
+static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    return bdrv_aio_flush(s->hd, cb, opaque);
+}
+
+static BlockDriver bdrv_blkdebug = {
+    .format_name        = "blkdebug",
+    .protocol_name      = "blkdebug",
+
+    .instance_size      = sizeof(BDRVBlkdebugState),
+
+    .bdrv_open          = blkdebug_open,
+    .bdrv_close         = blkdebug_close,
+    .bdrv_flush         = blkdebug_flush,
+
+    .bdrv_aio_readv     = blkdebug_aio_readv,
+    .bdrv_aio_writev    = blkdebug_aio_writev,
+    .bdrv_aio_flush     = blkdebug_aio_flush,
+};
+
+static void bdrv_blkdebug_init(void)
+{
+    bdrv_register(&bdrv_blkdebug);
+}
+
+block_init(bdrv_blkdebug_init);
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 4/7] blkdebug: Inject errors
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
                   ` (2 preceding siblings ...)
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 3/7] blkdebug: Basic request passthrough Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 5/7] Make qemu-config available for tools Kevin Wolf
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

Add a mechanism to inject errors instead of passing requests on. With no
further patches applied, you can use it by setting inject_errno in gdb.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/blkdebug.c |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/block/blkdebug.c b/block/blkdebug.c
index 2c7e0dd..dad3ac6 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -26,10 +26,41 @@
 #include "block_int.h"
 #include "module.h"
 
+#include <stdbool.h>
+
+typedef struct BlkdebugVars {
+    int state;
+
+    /* If inject_errno != 0, an error is injected for requests */
+    int inject_errno;
+
+    /* Decides if all future requests fail (false) or only the next one and
+     * after the next request inject_errno is reset to 0 (true) */
+    bool inject_once;
+
+    /* Decides if aio_readv/writev fails right away (true) or returns an error
+     * return value only in the callback (false) */
+    bool inject_immediately;
+} BlkdebugVars;
+
 typedef struct BDRVBlkdebugState {
     BlockDriverState *hd;
+    BlkdebugVars vars;
 } BDRVBlkdebugState;
 
+typedef struct BlkdebugAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} BlkdebugAIOCB;
+
+static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
+
+static AIOPool blkdebug_aio_pool = {
+    .aiocb_size = sizeof(BlkdebugAIOCB),
+    .cancel     = blkdebug_aio_cancel,
+};
+
 static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVBlkdebugState *s = bs->opaque;
@@ -42,11 +73,56 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
     return bdrv_file_open(&s->hd, filename, flags);
 }
 
+static void error_callback_bh(void *opaque)
+{
+    struct BlkdebugAIOCB *acb = opaque;
+    qemu_bh_delete(acb->bh);
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_aio_release(acb);
+}
+
+static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    BlkdebugAIOCB *acb = (BlkdebugAIOCB*) blockacb;
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    int error = s->vars.inject_errno;
+    struct BlkdebugAIOCB *acb;
+    QEMUBH *bh;
+
+    if (s->vars.inject_once) {
+        s->vars.inject_errno = 0;
+    }
+
+    if (s->vars.inject_immediately) {
+        return NULL;
+    }
+
+    acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
+    acb->ret = -error;
+
+    bh = qemu_bh_new(error_callback_bh, acb);
+    acb->bh = bh;
+    qemu_bh_schedule(bh);
+
+    return (BlockDriverAIOCB*) acb;
+}
+
 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
     BlockDriverCompletionFunc *cb, void *opaque)
 {
     BDRVBlkdebugState *s = bs->opaque;
+
+    if (s->vars.inject_errno) {
+        return inject_error(bs, cb, opaque);
+    }
+
     BlockDriverAIOCB *acb =
         bdrv_aio_readv(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
     return acb;
@@ -57,6 +133,11 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
     BlockDriverCompletionFunc *cb, void *opaque)
 {
     BDRVBlkdebugState *s = bs->opaque;
+
+    if (s->vars.inject_errno) {
+        return inject_error(bs, cb, opaque);
+    }
+
     BlockDriverAIOCB *acb =
         bdrv_aio_writev(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
     return acb;
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 5/7] Make qemu-config available for tools
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
                   ` (3 preceding siblings ...)
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 4/7] blkdebug: Inject errors Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 6/7] blkdebug: Add events and rules Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 7/7] qcow2: Trigger blkdebug events Kevin Wolf
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

To be able to use config files for blkdebug, we need to make these functions
available in the tools. This involves moving two functions that can only be
built in the context of the emulator.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 Makefile.objs        |    4 ++--
 hw/qdev-properties.c |   19 ++++++++++++++++++-
 hw/qdev.h            |    1 -
 qemu-config.c        |   17 -----------------
 qemu-tool.c          |    4 ++++
 5 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/Makefile.objs b/Makefile.objs
index ece02d5..930408b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -8,7 +8,7 @@ qobject-obj-y += qerror.o
 # block-obj-y is code used by both qemu system emulation and qemu-img
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
-block-obj-y += nbd.o block.o aio.o aes.o osdep.o
+block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
@@ -76,7 +76,7 @@ common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
 common-obj-y += qemu-char.o savevm.o #aio.o
 common-obj-y += msmouse.o ps2.o
 common-obj-y += qdev.o qdev-properties.o
-common-obj-y += qemu-config.o block-migration.o
+common-obj-y += block-migration.o
 
 common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 92d6793..d344b80 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -660,7 +660,7 @@ void qdev_prop_set_defaults(DeviceState *dev, Property *props)
 
 static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props);
 
-void qdev_prop_register_global(GlobalProperty *prop)
+static void qdev_prop_register_global(GlobalProperty *prop)
 {
     QTAILQ_INSERT_TAIL(&global_props, prop, next);
 }
@@ -688,3 +688,20 @@ void qdev_prop_set_globals(DeviceState *dev)
         }
     }
 }
+
+static int qdev_add_one_global(QemuOpts *opts, void *opaque)
+{
+    GlobalProperty *g;
+
+    g = qemu_mallocz(sizeof(*g));
+    g->driver   = qemu_opt_get(opts, "driver");
+    g->property = qemu_opt_get(opts, "property");
+    g->value    = qemu_opt_get(opts, "value");
+    qdev_prop_register_global(g);
+    return 0;
+}
+
+void qemu_add_globals(void)
+{
+    qemu_opts_foreach(&qemu_global_opts, qdev_add_one_global, NULL, 0);
+}
diff --git a/hw/qdev.h b/hw/qdev.h
index 9475705..3a8e801 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -273,7 +273,6 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
 void qdev_prop_set_defaults(DeviceState *dev, Property *props);
 
-void qdev_prop_register_global(GlobalProperty *prop);
 void qdev_prop_register_global_list(GlobalProperty *props);
 void qdev_prop_set_globals(DeviceState *dev);
 
diff --git a/qemu-config.c b/qemu-config.c
index dedf177..ad91133 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -378,23 +378,6 @@ int qemu_global_option(const char *str)
     return 0;
 }
 
-static int qemu_add_one_global(QemuOpts *opts, void *opaque)
-{
-    GlobalProperty *g;
-
-    g = qemu_mallocz(sizeof(*g));
-    g->driver   = qemu_opt_get(opts, "driver");
-    g->property = qemu_opt_get(opts, "property");
-    g->value    = qemu_opt_get(opts, "value");
-    qdev_prop_register_global(g);
-    return 0;
-}
-
-void qemu_add_globals(void)
-{
-    qemu_opts_foreach(&qemu_global_opts, qemu_add_one_global, NULL, 0);
-}
-
 struct ConfigWriteData {
     QemuOptsList *list;
     FILE *fp;
diff --git a/qemu-tool.c b/qemu-tool.c
index 97ca949..619b7b1 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -128,6 +128,10 @@ void loc_restore(Location *loc)
 {
 }
 
+void loc_set_file(const char *fname, int lno)
+{
+}
+
 void error_report(const char *fmt, ...)
 {
     va_list args;
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 6/7] blkdebug: Add events and rules
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
                   ` (4 preceding siblings ...)
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 5/7] Make qemu-config available for tools Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 7/7] qcow2: Trigger blkdebug events Kevin Wolf
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

Block drivers can trigger a blkdebug event whenever they reach a place where it
could be useful to inject an error for testing/debugging purposes.

Rules are read from a blkdebug config file and describe which action is taken
when an event is triggered. For now this is only injecting an error (with a few
options) or changing the state (which is an integer). Rules can be declared to
be active only in a specific state; this way later rules can distiguish on
which path we came to trigger their event.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c          |   12 +++
 block.h          |    9 ++
 block/blkdebug.c |  249 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 block_int.h      |    2 +
 4 files changed, 271 insertions(+), 1 deletions(-)

diff --git a/block.c b/block.c
index e891544..122a620 100644
--- a/block.c
+++ b/block.c
@@ -1535,6 +1535,18 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
     return drv->bdrv_load_vmstate(bs, buf, pos, size);
 }
 
+void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv || !drv->bdrv_debug_event) {
+        return;
+    }
+
+    return drv->bdrv_debug_event(bs, event);
+
+}
+
 /**************************************************************/
 /* handling of snapshots */
 
diff --git a/block.h b/block.h
index edf5704..2fd8361 100644
--- a/block.h
+++ b/block.h
@@ -207,4 +207,13 @@ int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
 void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
                       int nr_sectors);
 int64_t bdrv_get_dirty_count(BlockDriverState *bs);
+
+
+typedef enum {
+    BLKDBG_EVENT_MAX,
+} BlkDebugEvent;
+
+#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
+void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
+
 #endif
diff --git a/block/blkdebug.c b/block/blkdebug.c
index dad3ac6..0878a1b 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -46,6 +46,7 @@ typedef struct BlkdebugVars {
 typedef struct BDRVBlkdebugState {
     BlockDriverState *hd;
     BlkdebugVars vars;
+    QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
 } BDRVBlkdebugState;
 
 typedef struct BlkdebugAIOCB {
@@ -61,16 +62,210 @@ static AIOPool blkdebug_aio_pool = {
     .cancel     = blkdebug_aio_cancel,
 };
 
+enum {
+    ACTION_INJECT_ERROR,
+    ACTION_SET_STATE,
+};
+
+typedef struct BlkdebugRule {
+    BlkDebugEvent event;
+    int action;
+    int state;
+    union {
+        struct {
+            int error;
+            int immediately;
+            int once;
+        } inject;
+        struct {
+            int new_state;
+        } set_state;
+    } options;
+    QLIST_ENTRY(BlkdebugRule) next;
+} BlkdebugRule;
+
+static QemuOptsList inject_error_opts = {
+    .name = "inject-error",
+    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
+    .desc = {
+        {
+            .name = "event",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "state",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "errno",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "once",
+            .type = QEMU_OPT_BOOL,
+        },
+        {
+            .name = "immediately",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList set_state_opts = {
+    .name = "set-state",
+    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
+    .desc = {
+        {
+            .name = "event",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "state",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "new_state",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList *config_groups[] = {
+    &inject_error_opts,
+    &set_state_opts,
+    NULL
+};
+
+static const char *event_names[BLKDBG_EVENT_MAX] = {
+};
+
+static int get_event_by_name(const char *name, BlkDebugEvent *event)
+{
+    int i;
+
+    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
+        if (!strcmp(event_names[i], name)) {
+            *event = i;
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+struct add_rule_data {
+    BDRVBlkdebugState *s;
+    int action;
+};
+
+static int add_rule(QemuOpts *opts, void *opaque)
+{
+    struct add_rule_data *d = opaque;
+    BDRVBlkdebugState *s = d->s;
+    const char* event_name;
+    BlkDebugEvent event;
+    struct BlkdebugRule *rule;
+
+    /* Find the right event for the rule */
+    event_name = qemu_opt_get(opts, "event");
+    if (!event_name || get_event_by_name(event_name, &event) < 0) {
+        return -1;
+    }
+
+    /* Set attributes common for all actions */
+    rule = qemu_mallocz(sizeof(*rule));
+    *rule = (struct BlkdebugRule) {
+        .event  = event,
+        .action = d->action,
+        .state  = qemu_opt_get_number(opts, "state", 0),
+    };
+
+    /* Parse action-specific options */
+    switch (d->action) {
+    case ACTION_INJECT_ERROR:
+        rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
+        rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
+        rule->options.inject.immediately =
+            qemu_opt_get_bool(opts, "immediately", 0);
+        break;
+
+    case ACTION_SET_STATE:
+        rule->options.set_state.new_state =
+            qemu_opt_get_number(opts, "new_state", 0);
+        break;
+    };
+
+    /* Add the rule */
+    QLIST_INSERT_HEAD(&s->rules[event], rule, next);
+
+    return 0;
+}
+
+static int read_config(BDRVBlkdebugState *s, const char *filename)
+{
+    FILE *f;
+    int ret;
+    struct add_rule_data d;
+
+    f = fopen(filename, "r");
+    if (f == NULL) {
+        return -errno;
+    }
+
+    ret = qemu_config_parse(f, config_groups, filename);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    d.s = s;
+    d.action = ACTION_INJECT_ERROR;
+    qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
+
+    d.action = ACTION_SET_STATE;
+    qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
+
+    ret = 0;
+fail:
+    fclose(f);
+    return ret;
+}
+
+/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
 static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVBlkdebugState *s = bs->opaque;
+    int ret;
+    char *config, *c;
 
+    /* Parse the blkdebug: prefix */
     if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
         return -EINVAL;
     }
     filename += strlen("blkdebug:");
 
-    return bdrv_file_open(&s->hd, filename, flags);
+    /* Read rules from config file */
+    c = strchr(filename, ':');
+    if (c == NULL) {
+        return -EINVAL;
+    }
+
+    config = strdup(filename);
+    config[c - filename] = '\0';
+    ret = read_config(s, config);
+    if (ret < 0) {
+        return ret;
+    }
+    filename = c + 1;
+
+    /* Open the backing file */
+    ret = bdrv_file_open(&s->hd, filename, flags);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
 }
 
 static void error_callback_bh(void *opaque)
@@ -146,6 +341,16 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
 static void blkdebug_close(BlockDriverState *bs)
 {
     BDRVBlkdebugState *s = bs->opaque;
+    BlkdebugRule *rule, *next;
+    int i;
+
+    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
+        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
+            QLIST_REMOVE(rule, next);
+            qemu_free(rule);
+        }
+    }
+
     bdrv_delete(s->hd);
 }
 
@@ -162,6 +367,46 @@ static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
     return bdrv_aio_flush(s->hd, cb, opaque);
 }
 
+static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
+    BlkdebugVars *old_vars)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    BlkdebugVars *vars = &s->vars;
+
+    /* Only process rules for the current state */
+    if (rule->state && rule->state != old_vars->state) {
+        return;
+    }
+
+    /* Take the action */
+    switch (rule->action) {
+    case ACTION_INJECT_ERROR:
+        vars->inject_errno       = rule->options.inject.error;
+        vars->inject_once        = rule->options.inject.once;
+        vars->inject_immediately = rule->options.inject.immediately;
+        break;
+
+    case ACTION_SET_STATE:
+        vars->state              = rule->options.set_state.new_state;
+        break;
+    }
+}
+
+static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    struct BlkdebugRule *rule;
+    BlkdebugVars old_vars = s->vars;
+
+    if (event < 0 || event >= BLKDBG_EVENT_MAX) {
+        return;
+    }
+
+    QLIST_FOREACH(rule, &s->rules[event], next) {
+        process_rule(bs, rule, &old_vars);
+    }
+}
+
 static BlockDriver bdrv_blkdebug = {
     .format_name        = "blkdebug",
     .protocol_name      = "blkdebug",
@@ -175,6 +420,8 @@ static BlockDriver bdrv_blkdebug = {
     .bdrv_aio_readv     = blkdebug_aio_readv,
     .bdrv_aio_writev    = blkdebug_aio_writev,
     .bdrv_aio_flush     = blkdebug_aio_flush,
+
+    .bdrv_debug_event   = blkdebug_debug_event,
 };
 
 static void bdrv_blkdebug_init(void)
diff --git a/block_int.h b/block_int.h
index 71b633b..e7e1e7e 100644
--- a/block_int.h
+++ b/block_int.h
@@ -120,6 +120,8 @@ struct BlockDriver {
     /* Returns number of errors in image, -errno for internal errors */
     int (*bdrv_check)(BlockDriverState* bs);
 
+    void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event);
+
     /* Set if newly created images are not guaranteed to contain only zeros */
     int no_zero_init;
 
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 7/7] qcow2: Trigger blkdebug events
  2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
                   ` (5 preceding siblings ...)
  2010-03-22 10:00 ` [Qemu-devel] [PATCH 6/7] blkdebug: Add events and rules Kevin Wolf
@ 2010-03-22 10:00 ` Kevin Wolf
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2010-03-22 10:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf

This adds blkdebug events to qcow2 to allow injecting I/O errors in specific
places.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.h                |   44 ++++++++++++++++++++++++++++++++++++++++++++
 block/blkdebug.c       |   42 ++++++++++++++++++++++++++++++++++++++++++
 block/qcow2-cluster.c  |   15 +++++++++++++++
 block/qcow2-refcount.c |   18 ++++++++++++++++++
 block/qcow2.c          |    6 ++++++
 5 files changed, 125 insertions(+), 0 deletions(-)

diff --git a/block.h b/block.h
index 2fd8361..14443f1 100644
--- a/block.h
+++ b/block.h
@@ -210,6 +210,50 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs);
 
 
 typedef enum {
+    BLKDBG_L1_UPDATE,
+
+    BLKDBG_L1_GROW_ALLOC_TABLE,
+    BLKDBG_L1_GROW_WRITE_TABLE,
+    BLKDBG_L1_GROW_ACTIVATE_TABLE,
+
+    BLKDBG_L2_LOAD,
+    BLKDBG_L2_UPDATE,
+    BLKDBG_L2_UPDATE_COMPRESSED,
+    BLKDBG_L2_ALLOC_COW_READ,
+    BLKDBG_L2_ALLOC_WRITE,
+
+    BLKDBG_READ,
+    BLKDBG_READ_AIO,
+    BLKDBG_READ_BACKING,
+    BLKDBG_READ_BACKING_AIO,
+    BLKDBG_READ_COMPRESSED,
+
+    BLKDBG_WRITE_AIO,
+    BLKDBG_WRITE_COMPRESSED,
+
+    BLKDBG_VMSTATE_LOAD,
+    BLKDBG_VMSTATE_SAVE,
+
+    BLKDBG_COW_READ,
+    BLKDBG_COW_WRITE,
+
+    BLKDBG_REFTABLE_LOAD,
+    BLKDBG_REFTABLE_GROW,
+
+    BLKDBG_REFBLOCK_LOAD,
+    BLKDBG_REFBLOCK_UPDATE,
+    BLKDBG_REFBLOCK_UPDATE_PART,
+    BLKDBG_REFBLOCK_ALLOC,
+    BLKDBG_REFBLOCK_ALLOC_HOOKUP,
+    BLKDBG_REFBLOCK_ALLOC_WRITE,
+    BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS,
+    BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE,
+    BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE,
+
+    BLKDBG_CLUSTER_ALLOC,
+    BLKDBG_CLUSTER_ALLOC_BYTES,
+    BLKDBG_CLUSTER_FREE,
+
     BLKDBG_EVENT_MAX,
 } BlkDebugEvent;
 
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 0878a1b..4a0bfe3 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -139,6 +139,48 @@ static QemuOptsList *config_groups[] = {
 };
 
 static const char *event_names[BLKDBG_EVENT_MAX] = {
+    [BLKDBG_L1_UPDATE]                      = "l1_update",
+    [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
+    [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
+    [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
+
+    [BLKDBG_L2_LOAD]                        = "l2_load",
+    [BLKDBG_L2_UPDATE]                      = "l2_update",
+    [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
+    [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
+    [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
+
+    [BLKDBG_READ]                           = "read",
+    [BLKDBG_READ_AIO]                       = "read_aio",
+    [BLKDBG_READ_BACKING]                   = "read_backing",
+    [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
+    [BLKDBG_READ_COMPRESSED]                = "read_compressed",
+
+    [BLKDBG_WRITE_AIO]                      = "write_aio",
+    [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
+
+    [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
+    [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
+
+    [BLKDBG_COW_READ]                       = "cow_read",
+    [BLKDBG_COW_WRITE]                      = "cow_write",
+
+    [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
+    [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
+
+    [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
+    [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
+    [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
+    [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
+    [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
+    [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
+    [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
+    [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
+    [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
+
+    [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
+    [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
+    [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
 };
 
 static int get_event_by_name(const char *name, BlkDebugEvent *event)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index b13b693..9b3d686 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -54,12 +54,14 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
     memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
 
     /* write new table (align to cluster) */
+    BLKDBG_EVENT(s->hd, BLKDBG_L1_GROW_ALLOC_TABLE);
     new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
     if (new_l1_table_offset < 0) {
         qemu_free(new_l1_table);
         return new_l1_table_offset;
     }
 
+    BLKDBG_EVENT(s->hd, BLKDBG_L1_GROW_WRITE_TABLE);
     for(i = 0; i < s->l1_size; i++)
         new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
     ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
@@ -69,6 +71,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
         new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
 
     /* set new table */
+    BLKDBG_EVENT(s->hd, BLKDBG_L1_GROW_ACTIVATE_TABLE);
     cpu_to_be32w((uint32_t*)data, new_l1_size);
     cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
     ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
@@ -170,6 +173,8 @@ static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset)
 
     min_index = l2_cache_new_entry(bs);
     l2_table = s->l2_cache + (min_index << s->l2_bits);
+
+    BLKDBG_EVENT(s->hd, BLKDBG_L2_LOAD);
     if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
         s->l2_size * sizeof(uint64_t))
         return NULL;
@@ -195,6 +200,7 @@ static int write_l1_entry(BDRVQcowState *s, int l1_index)
         buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
     }
 
+    BLKDBG_EVENT(s->hd, BLKDBG_L1_UPDATE);
     if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index,
         buf, sizeof(buf)) != sizeof(buf))
     {
@@ -248,12 +254,14 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
         memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
     } else {
         /* if there was an old l2 table, read it from the disk */
+        BLKDBG_EVENT(s->hd, BLKDBG_L2_ALLOC_COW_READ);
         if (bdrv_pread(s->hd, old_l2_offset,
                        l2_table, s->l2_size * sizeof(uint64_t)) !=
             s->l2_size * sizeof(uint64_t))
             return NULL;
     }
     /* write the l2 table to the file */
+    BLKDBG_EVENT(s->hd, BLKDBG_L2_ALLOC_WRITE);
     if (bdrv_pwrite(s->hd, l2_offset,
                     l2_table, s->l2_size * sizeof(uint64_t)) !=
         s->l2_size * sizeof(uint64_t))
@@ -335,6 +343,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
                 /* read from the base image */
                 n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n);
                 if (n1 > 0) {
+                    BLKDBG_EVENT(s->hd, BLKDBG_READ_BACKING);
                     ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
                     if (ret < 0)
                         return -1;
@@ -347,6 +356,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
                 return -1;
             memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
         } else {
+            BLKDBG_EVENT(s->hd, BLKDBG_READ);
             ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
             if (ret != n * 512)
                 return -1;
@@ -371,6 +381,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
     n = n_end - n_start;
     if (n <= 0)
         return 0;
+    BLKDBG_EVENT(s->hd, BLKDBG_COW_READ);
     ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
     if (ret < 0)
         return ret;
@@ -380,6 +391,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
                         s->cluster_data, n, 1,
                         &s->aes_encrypt_key);
     }
+    BLKDBG_EVENT(s->hd, BLKDBG_COW_WRITE);
     ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
                      s->cluster_data, n);
     if (ret < 0)
@@ -592,6 +604,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 
     /* compressed clusters never have the copied flag */
 
+    BLKDBG_EVENT(s->hd, BLKDBG_L2_UPDATE_COMPRESSED);
     l2_table[l2_index] = cpu_to_be64(cluster_offset);
     if (bdrv_pwrite(s->hd,
                     l2_offset + l2_index * sizeof(uint64_t),
@@ -615,6 +628,7 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
     int end_offset = (8 * (l2_index + num) + 511) & ~511;
     size_t len = end_offset - start_offset;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_L2_UPDATE);
     if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index],
         len) != len)
     {
@@ -865,6 +879,7 @@ int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
         nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
         sector_offset = coffset & 511;
         csize = nb_csectors * 512 - sector_offset;
+        BLKDBG_EVENT(s->hd, BLKDBG_READ_COMPRESSED);
         ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
         if (ret < 0) {
             return -1;
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 917fc88..47c9978 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -42,6 +42,7 @@ static int write_refcount_block(BDRVQcowState *s)
         return 0;
     }
 
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_UPDATE);
     if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset,
             s->refcount_block_cache, size) != size)
     {
@@ -63,6 +64,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
     refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
     s->refcount_table = qemu_malloc(refcount_table_size2);
     if (s->refcount_table_size > 0) {
+        BLKDBG_EVENT(s->hd, BLKDBG_REFTABLE_LOAD);
         ret = bdrv_pread(s->hd, s->refcount_table_offset,
                          s->refcount_table, refcount_table_size2);
         if (ret != refcount_table_size2)
@@ -93,6 +95,7 @@ static int load_refcount_block(BlockDriverState *bs,
         write_refcount_block(s);
     }
 
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_LOAD);
     ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
                      s->cluster_size);
     if (ret != s->cluster_size)
@@ -164,6 +167,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     unsigned int refcount_table_index;
     int ret;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC);
+
     /* Find the refcount block for the given cluster */
     refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
 
@@ -239,6 +244,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     }
 
     /* Now the new refcount block needs to be written to disk */
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_WRITE);
     ret = bdrv_pwrite(s->hd, new_block, s->refcount_block_cache,
         s->cluster_size);
     if (ret < 0) {
@@ -248,6 +254,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     /* If the refcount table is big enough, just hook the block up there */
     if (refcount_table_index < s->refcount_table_size) {
         uint64_t data64 = cpu_to_be64(new_block);
+        BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
         ret = bdrv_pwrite(s->hd,
             s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
             &data64, sizeof(data64));
@@ -270,6 +277,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
      * refcount table at once without producing an inconsistent state in
      * between.
      */
+    BLKDBG_EVENT(s->hd, BLKDBG_REFTABLE_GROW);
+
     /* Calculate the number of refcount blocks needed so far */
     uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
     uint64_t blocks_used = (s->free_cluster_index +
@@ -325,6 +334,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     }
 
     /* Write refcount blocks to disk */
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
     ret = bdrv_pwrite(s->hd, meta_offset, new_blocks,
         blocks_clusters * s->cluster_size);
     qemu_free(new_blocks);
@@ -337,6 +347,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
         cpu_to_be64s(&new_table[i]);
     }
 
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
     ret = bdrv_pwrite(s->hd, table_offset, new_table,
         table_size * sizeof(uint64_t));
     if (ret < 0) {
@@ -351,6 +362,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     uint8_t data[12];
     cpu_to_be64w((uint64_t*)data, table_offset);
     cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
     ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
         data, sizeof(data));
     if (ret < 0) {
@@ -400,6 +412,7 @@ static int write_refcount_block_entries(BDRVQcowState *s,
         & ~(REFCOUNTS_PER_SECTOR - 1);
 
     size = (last_index - first_index) << REFCOUNT_SHIFT;
+    BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_UPDATE_PART);
     if (bdrv_pwrite(s->hd,
         refcount_block_offset + (first_index << REFCOUNT_SHIFT),
         &s->refcount_block_cache[first_index], size) != size)
@@ -555,9 +568,11 @@ retry:
 
 int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
 {
+    BDRVQcowState *s = bs->opaque;
     int64_t offset;
     int ret;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_CLUSTER_ALLOC);
     offset = alloc_clusters_noref(bs, size);
     ret = update_refcount(bs, offset, size, 1);
     if (ret < 0) {
@@ -574,6 +589,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
     int64_t offset, cluster_offset;
     int free_in_cluster;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_CLUSTER_ALLOC_BYTES);
     assert(size > 0 && size <= s->cluster_size);
     if (s->free_byte_offset == 0) {
         s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
@@ -615,8 +631,10 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
 void qcow2_free_clusters(BlockDriverState *bs,
                           int64_t offset, int64_t size)
 {
+    BDRVQcowState *s = bs->opaque;
     int ret;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_CLUSTER_FREE);
     ret = update_refcount(bs, offset, size, -1);
     if (ret < 0) {
         fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
diff --git a/block/qcow2.c b/block/qcow2.c
index 5b6dad9..50c42c0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -429,6 +429,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
                 acb->hd_iov.iov_base = (void *)acb->buf;
                 acb->hd_iov.iov_len = acb->cur_nr_sectors * 512;
                 qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+                BLKDBG_EVENT(s->hd, BLKDBG_READ_BACKING_AIO);
                 acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
                                     &acb->hd_qiov, acb->cur_nr_sectors,
 				    qcow_aio_read_cb, acb);
@@ -464,6 +465,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
         acb->hd_iov.iov_base = (void *)acb->buf;
         acb->hd_iov.iov_len = acb->cur_nr_sectors * 512;
         qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        BLKDBG_EVENT(s->hd, BLKDBG_READ_AIO);
         acb->hd_aiocb = bdrv_aio_readv(s->hd,
                             (acb->cluster_offset >> 9) + index_in_cluster,
                             &acb->hd_qiov, acb->cur_nr_sectors,
@@ -617,6 +619,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
     acb->hd_iov.iov_base = (void *)src_buf;
     acb->hd_iov.iov_len = acb->cur_nr_sectors * 512;
     qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+    BLKDBG_EVENT(s->hd, BLKDBG_WRITE_AIO);
     acb->hd_aiocb = bdrv_aio_writev(s->hd,
                                     (acb->cluster_offset >> 9) + index_in_cluster,
                                     &acb->hd_qiov, acb->cur_nr_sectors,
@@ -1133,6 +1136,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
         if (!cluster_offset)
             return -1;
         cluster_offset &= s->cluster_offset_mask;
+        BLKDBG_EVENT(s->hd, BLKDBG_WRITE_COMPRESSED);
         if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
             qemu_free(out_buf);
             return -1;
@@ -1203,6 +1207,7 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
     int growable = bs->growable;
     int ret;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_VMSTATE_SAVE);
     bs->growable = 1;
     ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
     bs->growable = growable;
@@ -1217,6 +1222,7 @@ static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
     int growable = bs->growable;
     int ret;
 
+    BLKDBG_EVENT(s->hd, BLKDBG_VMSTATE_LOAD);
     bs->growable = 1;
     ret = bdrv_pread(bs, qcow_vm_state_offset(s) + pos, buf, size);
     bs->growable = growable;
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-03-22 10:01 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-22 10:00 [Qemu-devel] [PATCH 0/7] blkdebug Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 1/7] qemu-config: qemu_read_config_file() reads the normal config file Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 2/7] qemu-config: Make qemu_config_parse more generic Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 3/7] blkdebug: Basic request passthrough Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 4/7] blkdebug: Inject errors Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 5/7] Make qemu-config available for tools Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 6/7] blkdebug: Add events and rules Kevin Wolf
2010-03-22 10:00 ` [Qemu-devel] [PATCH 7/7] qcow2: Trigger blkdebug events Kevin Wolf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.