blkdebug: store list of active rules

This prepares for the next patch, where some active rules may actually
not trigger depending on input to readv/writev.  Store the active rules
in a SIMPLEQ (so that it can be emptied easily with QSIMPLEQ_INIT), and
fetch the errno/once/immediately arguments from there.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2012-06-06 08:10:42 +02:00 committed by Kevin Wolf
parent e130225587
commit 571cd43e57
1 changed files with 31 additions and 38 deletions

View File

@ -26,24 +26,10 @@
#include "block_int.h" #include "block_int.h"
#include "module.h" #include "module.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 { typedef struct BDRVBlkdebugState {
BlkdebugVars vars; int state;
QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
} BDRVBlkdebugState; } BDRVBlkdebugState;
typedef struct BlkdebugAIOCB { typedef struct BlkdebugAIOCB {
@ -79,6 +65,7 @@ typedef struct BlkdebugRule {
} set_state; } set_state;
} options; } options;
QLIST_ENTRY(BlkdebugRule) next; QLIST_ENTRY(BlkdebugRule) next;
QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
} BlkdebugRule; } BlkdebugRule;
static QemuOptsList inject_error_opts = { static QemuOptsList inject_error_opts = {
@ -300,7 +287,7 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
filename = c + 1; filename = c + 1;
/* Set initial state */ /* Set initial state */
s->vars.state = 1; s->state = 1;
/* Open the backing file */ /* Open the backing file */
ret = bdrv_file_open(&bs->file, filename, flags); ret = bdrv_file_open(&bs->file, filename, flags);
@ -326,18 +313,18 @@ static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
} }
static BlockDriverAIOCB *inject_error(BlockDriverState *bs, static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque) BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
int error = s->vars.inject_errno; int error = rule->options.inject.error;
struct BlkdebugAIOCB *acb; struct BlkdebugAIOCB *acb;
QEMUBH *bh; QEMUBH *bh;
if (s->vars.inject_once) { if (rule->options.inject.once) {
s->vars.inject_errno = 0; QSIMPLEQ_INIT(&s->active_rules);
} }
if (s->vars.inject_immediately) { if (rule->options.inject.immediately) {
return NULL; return NULL;
} }
@ -356,9 +343,10 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque) BlockDriverCompletionFunc *cb, void *opaque)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = QSIMPLEQ_FIRST(&s->active_rules);
if (s->vars.inject_errno) { if (rule && rule->options.inject.error) {
return inject_error(bs, cb, opaque); return inject_error(bs, cb, opaque, rule);
} }
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
@ -369,9 +357,10 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque) BlockDriverCompletionFunc *cb, void *opaque)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = QSIMPLEQ_FIRST(&s->active_rules);
if (s->vars.inject_errno) { if (rule && rule->options.inject.error) {
return inject_error(bs, cb, opaque); return inject_error(bs, cb, opaque, rule);
} }
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
@ -391,41 +380,45 @@ static void blkdebug_close(BlockDriverState *bs)
} }
} }
static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
BlkdebugVars *old_vars) int old_state, bool injected)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugVars *vars = &s->vars;
/* Only process rules for the current state */ /* Only process rules for the current state */
if (rule->state && rule->state != old_vars->state) { if (rule->state && rule->state != old_state) {
return; return injected;
} }
/* Take the action */ /* Take the action */
switch (rule->action) { switch (rule->action) {
case ACTION_INJECT_ERROR: case ACTION_INJECT_ERROR:
vars->inject_errno = rule->options.inject.error; if (!injected) {
vars->inject_once = rule->options.inject.once; QSIMPLEQ_INIT(&s->active_rules);
vars->inject_immediately = rule->options.inject.immediately; injected = true;
}
QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
break; break;
case ACTION_SET_STATE: case ACTION_SET_STATE:
vars->state = rule->options.set_state.new_state; s->state = rule->options.set_state.new_state;
break; break;
} }
return injected;
} }
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule; struct BlkdebugRule *rule;
BlkdebugVars old_vars = s->vars; int old_state = s->state;
bool injected;
assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
injected = false;
QLIST_FOREACH(rule, &s->rules[event], next) { QLIST_FOREACH(rule, &s->rules[event], next) {
process_rule(bs, rule, &old_vars); injected = process_rule(bs, rule, old_state, injected);
} }
} }