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 <kw...@redhat.com> --- block/blkdebug.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 63 insertions(+), 0 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 2c7e0dd..f8ccd3c 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -26,10 +26,26 @@ #include "block_int.h" #include "module.h" +#include <stdbool.h> + typedef struct BDRVBlkdebugState { BlockDriverState *hd; + + int inject_errno; + 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; } BDRVBlkdebugState; +struct callback_data { + QEMUBH *bh; + BlockDriverCompletionFunc *cb; + int ret; + void *opaque; +}; + static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) { BDRVBlkdebugState *s = bs->opaque; @@ -42,11 +58,53 @@ 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 callback_data *d = opaque; + qemu_bh_delete(d->bh); + d->cb(d->opaque, d->ret); + qemu_free(d); +} + +static BlockDriverAIOCB *inject_error(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BDRVBlkdebugState *s = bs->opaque; + int error = s->inject_errno; + struct callback_data *d; + QEMUBH *bh; + + if (s->inject_once) { + s->inject_errno = 0; + } + + if (s->inject_immediately) { + return NULL; + } + + d = qemu_mallocz(sizeof(*d)); + d->ret = error; + d->opaque = opaque; + d->cb = cb; + + bh = qemu_bh_new(error_callback_bh, d); + d->bh = bh; + qemu_bh_schedule(bh); + + // TODO Use a real AIOCB + return (BlockDriverAIOCB*) 42; +} + 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->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 +115,11 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { BDRVBlkdebugState *s = bs->opaque; + + if (s->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