qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] Add delay option to blkdebug


From: Alex Bligh
Subject: [Qemu-devel] [PATCH] Add delay option to blkdebug
Date: Sat, 29 Jun 2013 19:02:03 +0100

Add a delay option to blkdebug, allowing operations to be delayed by
a specifiable number of microseconds. Example configuration:

[inject-error]
event = "read_aio"
delay = "200000"

Signed-off-by: Alex Bligh <address@hidden>
---
 block/blkdebug.c |   83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/block/blkdebug.c b/block/blkdebug.c
index ccb627a..dafb805 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -40,6 +40,9 @@ typedef struct BlkdebugAIOCB {
     BlockDriverAIOCB common;
     QEMUBH *bh;
     int ret;
+    bool *finished;
+    int64_t delay;
+    int64_t starttime;
 } BlkdebugAIOCB;
 
 typedef struct BlkdebugSuspendedReq {
@@ -71,6 +74,7 @@ typedef struct BlkdebugRule {
             int immediately;
             int once;
             int64_t sector;
+            int64_t delay;
         } inject;
         struct {
             int new_state;
@@ -111,6 +115,10 @@ static QemuOptsList inject_error_opts = {
             .name = "immediately",
             .type = QEMU_OPT_BOOL,
         },
+        {
+            .name = "delay", /* delay in microseconds */
+            .type = QEMU_OPT_NUMBER,
+        },
         { /* end of list */ }
     },
 };
@@ -236,6 +244,10 @@ static int add_rule(QemuOpts *opts, void *opaque)
         rule->options.inject.immediately =
             qemu_opt_get_bool(opts, "immediately", 0);
         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
+        rule->options.inject.delay = qemu_opt_get_number(opts, "delay", 0);
+        if (rule->options.inject.delay) {
+            rule->options.inject.error = 0;
+        }
         break;
 
     case ACTION_SET_STATE:
@@ -399,6 +411,9 @@ fail:
 static void error_callback_bh(void *opaque)
 {
     struct BlkdebugAIOCB *acb = opaque;
+    if (acb->finished) {
+        *acb->finished = true;
+    }
     qemu_bh_delete(acb->bh);
     acb->common.cb(acb->common.opaque, acb->ret);
     qemu_aio_release(acb);
@@ -407,6 +422,13 @@ static void error_callback_bh(void *opaque)
 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
+    bool finished = false;
+
+    /* Wait until request completes, invokes its callback, and frees itself */
+    acb->finished = &finished;
+    while (!finished) {
+        qemu_aio_wait();
+    }
     qemu_aio_release(acb);
 }
 
@@ -427,6 +449,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
     }
 
     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
+    acb->finished = NULL;
     acb->ret = -error;
 
     bh = qemu_bh_new(error_callback_bh, acb);
@@ -436,6 +459,50 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
     return &acb->common;
 }
 
+static BlkdebugAIOCB *blkdebug_aio_get(BlockDriverState *bs, int64_t delay,
+                                       BlockDriverCompletionFunc *cb,
+                                       void *opaque)
+{
+    BlkdebugAIOCB *acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
+    
+    acb->bh = NULL;
+    acb->delay = delay;
+    acb->finished = NULL;
+    return acb;
+}
+
+static void blkdebug_aio_delay_bh(void *opaque)
+{
+    int64_t currenttime;
+    BlkdebugAIOCB *acb = opaque;
+
+    /* Unfortunately we cannot use a timer as under qemu-img for instance
+     * the timer loop is not run.
+     */
+    currenttime = qemu_get_clock_ns(rt_clock);
+    if ((currenttime - acb->starttime) < (acb->delay * 1000)) {
+        qemu_bh_schedule_idle(acb->bh);
+        return;
+    }
+
+    qemu_bh_delete(acb->bh);
+
+    acb->common.cb(acb->common.opaque, acb->ret);
+    if (acb->finished) {
+        *acb->finished = true;
+    }
+    qemu_aio_release(acb);
+}
+
+static void blkdebug_aio_delay_cb(void *opaque, int ret)
+{
+    BlkdebugAIOCB *acb = opaque;
+
+    acb->starttime = qemu_get_clock_ns(rt_clock);
+    acb->bh = qemu_bh_new(blkdebug_aio_delay_bh, acb);
+    qemu_bh_schedule_idle(acb->bh);
+}
+
 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
     BlockDriverCompletionFunc *cb, void *opaque)
@@ -455,6 +522,14 @@ static BlockDriverAIOCB 
*blkdebug_aio_readv(BlockDriverState *bs,
         return inject_error(bs, cb, opaque, rule);
     }
 
+    if (rule && rule->options.inject.delay) {
+        BlkdebugAIOCB *acb = blkdebug_aio_get(bs, rule->options.inject.delay, 
cb, opaque);
+        
+        bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
+                       blkdebug_aio_delay_cb, acb);
+        return &acb->common;
+    }
+
     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 }
 
@@ -477,6 +552,14 @@ static BlockDriverAIOCB 
*blkdebug_aio_writev(BlockDriverState *bs,
         return inject_error(bs, cb, opaque, rule);
     }
 
+    if (rule && rule->options.inject.delay) {
+        BlkdebugAIOCB *acb = blkdebug_aio_get(bs, rule->options.inject.delay, 
cb, opaque);
+        
+        bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
+                        blkdebug_aio_delay_cb, acb);
+        return &acb->common;
+    }
+
     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 }
 
-- 
1.7.9.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]