From patchwork Sat Jun 29 18:02:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Bligh X-Patchwork-Id: 255753 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 010322C0077 for ; Sun, 30 Jun 2013 04:02:53 +1000 (EST) Received: from localhost ([::1]:50257 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UszU2-0006ru-Sm for incoming@patchwork.ozlabs.org; Sat, 29 Jun 2013 14:02:50 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34960) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UszTg-0006oP-QG for qemu-devel@nongnu.org; Sat, 29 Jun 2013 14:02:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UszTf-0004BE-Jm for qemu-devel@nongnu.org; Sat, 29 Jun 2013 14:02:28 -0400 Received: from mail.avalus.com ([2001:41c8:10:1dd::10]:46285) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UszTf-0004BA-2T for qemu-devel@nongnu.org; Sat, 29 Jun 2013 14:02:27 -0400 Received: by mail.avalus.com (Postfix) with ESMTPSA id 8D6C2C56195; Sat, 29 Jun 2013 19:02:26 +0100 (BST) From: Alex Bligh To: qemu-devel@nongnu.org Date: Sat, 29 Jun 2013 19:02:03 +0100 Message-Id: <1372528923-12354-2-git-send-email-alex@alex.org.uk> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1372528923-12354-1-git-send-email-alex@alex.org.uk> References: <1372528923-12354-1-git-send-email-alex@alex.org.uk> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:41c8:10:1dd::10 Cc: Alex Bligh Subject: [Qemu-devel] [PATCH] Add delay option to blkdebug X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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); }