X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/a89d97df1f6d9f5bd6403a9d91d9d7cd86bdd394..e5a5604f8fdabfc788fbf75354b7f92eb349dcff:/block/blkdebug.c diff --git a/block/blkdebug.c b/block/blkdebug.c index 380c736101..9ce35cd035 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -26,6 +26,10 @@ #include "qemu/config-file.h" #include "block/block_int.h" #include "qemu/module.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qint.h" +#include "qapi/qmp/qstring.h" typedef struct BDRVBlkdebugState { int state; @@ -37,7 +41,7 @@ typedef struct BDRVBlkdebugState { } BDRVBlkdebugState; typedef struct BlkdebugAIOCB { - BlockDriverAIOCB common; + BlockAIOCB common; QEMUBH *bh; int ret; } BlkdebugAIOCB; @@ -48,11 +52,8 @@ typedef struct BlkdebugSuspendedReq { QLIST_ENTRY(BlkdebugSuspendedReq) next; } BlkdebugSuspendedReq; -static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); - static const AIOCBInfo blkdebug_aiocb_info = { - .aiocb_size = sizeof(BlkdebugAIOCB), - .cancel = blkdebug_aio_cancel, + .aiocb_size = sizeof(BlkdebugAIOCB), }; enum { @@ -194,6 +195,8 @@ static const char *event_names[BLKDBG_EVENT_MAX] = { [BLKDBG_PWRITEV] = "pwritev", [BLKDBG_PWRITEV_ZERO] = "pwritev_zero", [BLKDBG_PWRITEV_DONE] = "pwritev_done", + + [BLKDBG_EMPTY_IMAGE_PREPARE] = "empty_image_prepare", }; static int get_event_by_name(const char *name, BlkDebugEvent *event) @@ -213,6 +216,7 @@ static int get_event_by_name(const char *name, BlkDebugEvent *event) struct add_rule_data { BDRVBlkdebugState *s; int action; + Error **errp; }; static int add_rule(QemuOpts *opts, void *opaque) @@ -225,7 +229,11 @@ static int add_rule(QemuOpts *opts, void *opaque) /* Find the right event for the rule */ event_name = qemu_opt_get(opts, "event"); - if (!event_name || get_event_by_name(event_name, &event) < 0) { + if (!event_name) { + error_setg(d->errp, "Missing event name for rule"); + return -1; + } else if (get_event_by_name(event_name, &event) < 0) { + error_setg(d->errp, "Invalid event name \"%s\"", event_name); return -1; } @@ -311,10 +319,21 @@ static int read_config(BDRVBlkdebugState *s, const char *filename, d.s = s; d.action = ACTION_INJECT_ERROR; - qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0); + d.errp = &local_err; + qemu_opts_foreach(&inject_error_opts, add_rule, &d, 1); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } d.action = ACTION_SET_STATE; - qemu_opts_foreach(&set_state_opts, add_rule, &d, 0); + qemu_opts_foreach(&set_state_opts, add_rule, &d, 1); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } ret = 0; fail: @@ -443,17 +462,11 @@ 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); + qemu_aio_unref(acb); } -static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) -{ - BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); - qemu_aio_release(acb); -} - -static BlockDriverAIOCB *inject_error(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule) +static BlockAIOCB *inject_error(BlockDriverState *bs, + BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule) { BDRVBlkdebugState *s = bs->opaque; int error = rule->options.inject.error; @@ -471,16 +484,16 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs, acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); acb->ret = -error; - bh = qemu_bh_new(error_callback_bh, acb); + bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb); acb->bh = bh; qemu_bh_schedule(bh); return &acb->common; } -static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, +static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) + BlockCompletionFunc *cb, void *opaque) { BDRVBlkdebugState *s = bs->opaque; BlkdebugRule *rule = NULL; @@ -500,9 +513,9 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); } -static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, +static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) + BlockCompletionFunc *cb, void *opaque) { BDRVBlkdebugState *s = bs->opaque; BlkdebugRule *rule = NULL; @@ -522,6 +535,25 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); } +static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs, + BlockCompletionFunc *cb, void *opaque) +{ + BDRVBlkdebugState *s = bs->opaque; + BlkdebugRule *rule = NULL; + + QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { + if (rule->options.inject.sector == -1) { + break; + } + } + + if (rule && rule->options.inject.error) { + return inject_error(bs, cb, opaque, rule); + } + + return bdrv_aio_flush(bs->file, cb, opaque); +} + static void blkdebug_close(BlockDriverState *bs) { @@ -687,6 +719,55 @@ static int64_t blkdebug_getlength(BlockDriverState *bs) return bdrv_getlength(bs->file); } +static void blkdebug_refresh_filename(BlockDriverState *bs) +{ + QDict *opts; + const QDictEntry *e; + bool force_json = false; + + for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { + if (strcmp(qdict_entry_key(e), "config") && + strcmp(qdict_entry_key(e), "x-image") && + strcmp(qdict_entry_key(e), "image") && + strncmp(qdict_entry_key(e), "image.", strlen("image."))) + { + force_json = true; + break; + } + } + + if (force_json && !bs->file->full_open_options) { + /* The config file cannot be recreated, so creating a plain filename + * is impossible */ + return; + } + + if (!force_json && bs->file->exact_filename[0]) { + snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "blkdebug:%s:%s", + qdict_get_try_str(bs->options, "config") ?: "", + bs->file->exact_filename); + } + + opts = qdict_new(); + qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug"))); + + QINCREF(bs->file->full_open_options); + qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options)); + + for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { + if (strcmp(qdict_entry_key(e), "x-image") && + strcmp(qdict_entry_key(e), "image") && + strncmp(qdict_entry_key(e), "image.", strlen("image."))) + { + qobject_incref(qdict_entry_value(e)); + qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); + } + } + + bs->full_open_options = opts; +} + static BlockDriver bdrv_blkdebug = { .format_name = "blkdebug", .protocol_name = "blkdebug", @@ -696,9 +777,11 @@ static BlockDriver bdrv_blkdebug = { .bdrv_file_open = blkdebug_open, .bdrv_close = blkdebug_close, .bdrv_getlength = blkdebug_getlength, + .bdrv_refresh_filename = blkdebug_refresh_filename, .bdrv_aio_readv = blkdebug_aio_readv, .bdrv_aio_writev = blkdebug_aio_writev, + .bdrv_aio_flush = blkdebug_aio_flush, .bdrv_debug_event = blkdebug_debug_event, .bdrv_debug_breakpoint = blkdebug_debug_breakpoint,