diff options
author | Kevin Wolf <kwolf@redhat.com> | 2010-02-19 16:24:35 +0100 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2010-04-23 16:08:45 +0200 |
commit | b9f66d96950b7c10253f9f27b9109df5ff8aa611 (patch) | |
tree | f633ce7a192eb1c3fdd8ef4f011b692b18b77e9c /block | |
parent | 6a1437273ca3685f4bc8065fd921834d9b5608e1 (diff) |
blkdebug: Inject errors
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>
Diffstat (limited to 'block')
-rw-r--r-- | block/blkdebug.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/block/blkdebug.c b/block/blkdebug.c index 2c7e0dd0b7..dad3ac6e91 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; |