diff options
-rw-r--r-- | block/blkdebug.c | 50 | ||||
-rw-r--r-- | qapi/block-core.json | 26 |
2 files changed, 67 insertions, 9 deletions
diff --git a/block/blkdebug.c b/block/blkdebug.c index efd9441625..3f3ec11230 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -75,6 +75,7 @@ typedef struct BlkdebugRule { int state; union { struct { + uint64_t iotype_mask; int error; int immediately; int once; @@ -91,6 +92,9 @@ typedef struct BlkdebugRule { QSIMPLEQ_ENTRY(BlkdebugRule) active_next; } BlkdebugRule; +QEMU_BUILD_BUG_MSG(BLKDEBUG_IO_TYPE__MAX > 64, + "BlkdebugIOType mask does not fit into an uint64_t"); + static QemuOptsList inject_error_opts = { .name = "inject-error", .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), @@ -104,6 +108,10 @@ static QemuOptsList inject_error_opts = { .type = QEMU_OPT_NUMBER, }, { + .name = "iotype", + .type = QEMU_OPT_STRING, + }, + { .name = "errno", .type = QEMU_OPT_NUMBER, }, @@ -162,6 +170,8 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp) int event; struct BlkdebugRule *rule; int64_t sector; + BlkdebugIOType iotype; + Error *local_error = NULL; /* Find the right event for the rule */ event_name = qemu_opt_get(opts, "event"); @@ -192,6 +202,26 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp) sector = qemu_opt_get_number(opts, "sector", -1); rule->options.inject.offset = sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; + + iotype = qapi_enum_parse(&BlkdebugIOType_lookup, + qemu_opt_get(opts, "iotype"), + BLKDEBUG_IO_TYPE__MAX, &local_error); + if (local_error) { + error_propagate(errp, local_error); + return -1; + } + if (iotype != BLKDEBUG_IO_TYPE__MAX) { + rule->options.inject.iotype_mask = (1ull << iotype); + } else { + /* Apply the default */ + rule->options.inject.iotype_mask = + (1ull << BLKDEBUG_IO_TYPE_READ) + | (1ull << BLKDEBUG_IO_TYPE_WRITE) + | (1ull << BLKDEBUG_IO_TYPE_WRITE_ZEROES) + | (1ull << BLKDEBUG_IO_TYPE_DISCARD) + | (1ull << BLKDEBUG_IO_TYPE_FLUSH); + } + break; case ACTION_SET_STATE: @@ -470,7 +500,8 @@ out: return ret; } -static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes) +static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + BlkdebugIOType iotype) { BDRVBlkdebugState *s = bs->opaque; BlkdebugRule *rule = NULL; @@ -480,9 +511,10 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes) QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { uint64_t inject_offset = rule->options.inject.offset; - if (inject_offset == -1 || - (bytes && inject_offset >= offset && - inject_offset < offset + bytes)) + if ((inject_offset == -1 || + (bytes && inject_offset >= offset && + inject_offset < offset + bytes)) && + (rule->options.inject.iotype_mask & (1ull << iotype))) { break; } @@ -521,7 +553,7 @@ blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, assert(bytes <= bs->bl.max_transfer); } - err = rule_check(bs, offset, bytes); + err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_READ); if (err) { return err; } @@ -542,7 +574,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, assert(bytes <= bs->bl.max_transfer); } - err = rule_check(bs, offset, bytes); + err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE); if (err) { return err; } @@ -552,7 +584,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, static int blkdebug_co_flush(BlockDriverState *bs) { - int err = rule_check(bs, 0, 0); + int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH); if (err) { return err; @@ -586,7 +618,7 @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs, assert(bytes <= bs->bl.max_pwrite_zeroes); } - err = rule_check(bs, offset, bytes); + err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE_ZEROES); if (err) { return err; } @@ -620,7 +652,7 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, assert(bytes <= bs->bl.max_pdiscard); } - err = rule_check(bs, offset, bytes); + err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_DISCARD); if (err) { return err; } diff --git a/qapi/block-core.json b/qapi/block-core.json index c0ff3a83ef..34617a2c7a 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3265,6 +3265,26 @@ 'cor_write', 'cluster_alloc_space'] } ## +# @BlkdebugIOType: +# +# Kinds of I/O that blkdebug can inject errors in. +# +# @read: .bdrv_co_preadv() +# +# @write: .bdrv_co_pwritev() +# +# @write-zeroes: .bdrv_co_pwrite_zeroes() +# +# @discard: .bdrv_co_pdiscard() +# +# @flush: .bdrv_co_flush_to_disk() +# +# Since: 4.1 +## +{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE', + 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush' ] } + +## # @BlkdebugInjectErrorOptions: # # Describes a single error injection for blkdebug. @@ -3274,6 +3294,11 @@ # @state: the state identifier blkdebug needs to be in to # actually trigger the event; defaults to "any" # +# @iotype: the type of I/O operations on which this error should +# be injected; defaults to "all read, write, +# write-zeroes, discard, and flush operations" +# (since: 4.1) +# # @errno: error identifier (errno) to be returned; defaults to # EIO # @@ -3291,6 +3316,7 @@ { 'struct': 'BlkdebugInjectErrorOptions', 'data': { 'event': 'BlkdebugEvent', '*state': 'int', + '*iotype': 'BlkdebugIOType', '*errno': 'int', '*sector': 'int', '*once': 'bool', |