} BDRVBlkdebugState;
typedef struct BlkdebugAIOCB {
- BlockDriverAIOCB common;
+ BlockAIOCB common;
QEMUBH *bh;
int ret;
} BlkdebugAIOCB;
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 {
[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)
struct add_rule_data {
BDRVBlkdebugState *s;
int action;
+ Error **errp;
};
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;
}
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:
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);
- if (acb->bh) {
- qemu_bh_delete(acb->bh);
- acb->bh = NULL;
- }
- 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;
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;
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;
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}
-static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque)
+static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
+ BlockCompletionFunc *cb, void *opaque)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;
static void blkdebug_refresh_filename(BlockDriverState *bs)
{
- BDRVBlkdebugState *s = bs->opaque;
- struct BlkdebugRule *rule;
QDict *opts;
- QList *inject_error_list = NULL, *set_state_list = NULL;
- QList *suspend_list = NULL;
- int event;
+ 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 (!bs->file->full_open_options) {
+ 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 (event = 0; event < BLKDBG_EVENT_MAX; event++) {
- QLIST_FOREACH(rule, &s->rules[event], next) {
- if (rule->action == ACTION_INJECT_ERROR) {
- QDict *inject_error = qdict_new();
-
- qdict_put_obj(inject_error, "event", QOBJECT(qstring_from_str(
- BlkdebugEvent_lookup[rule->event])));
- qdict_put_obj(inject_error, "state",
- QOBJECT(qint_from_int(rule->state)));
- qdict_put_obj(inject_error, "errno", QOBJECT(qint_from_int(
- rule->options.inject.error)));
- qdict_put_obj(inject_error, "sector", QOBJECT(qint_from_int(
- rule->options.inject.sector)));
- qdict_put_obj(inject_error, "once", QOBJECT(qbool_from_int(
- rule->options.inject.once)));
- qdict_put_obj(inject_error, "immediately",
- QOBJECT(qbool_from_int(
- rule->options.inject.immediately)));
-
- if (!inject_error_list) {
- inject_error_list = qlist_new();
- }
-
- qlist_append_obj(inject_error_list, QOBJECT(inject_error));
- } else if (rule->action == ACTION_SET_STATE) {
- QDict *set_state = qdict_new();
-
- qdict_put_obj(set_state, "event", QOBJECT(qstring_from_str(
- BlkdebugEvent_lookup[rule->event])));
- qdict_put_obj(set_state, "state",
- QOBJECT(qint_from_int(rule->state)));
- qdict_put_obj(set_state, "new_state", QOBJECT(qint_from_int(
- rule->options.set_state.new_state)));
-
- if (!set_state_list) {
- set_state_list = qlist_new();
- }
-
- qlist_append_obj(set_state_list, QOBJECT(set_state));
- } else if (rule->action == ACTION_SUSPEND) {
- QDict *suspend = qdict_new();
-
- qdict_put_obj(suspend, "event", QOBJECT(qstring_from_str(
- BlkdebugEvent_lookup[rule->event])));
- qdict_put_obj(suspend, "state",
- QOBJECT(qint_from_int(rule->state)));
- qdict_put_obj(suspend, "tag", QOBJECT(qstring_from_str(
- rule->options.suspend.tag)));
-
- if (!suspend_list) {
- suspend_list = qlist_new();
- }
-
- qlist_append_obj(suspend_list, QOBJECT(suspend));
- }
+ 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));
}
}
- if (inject_error_list) {
- qdict_put_obj(opts, "inject-error", QOBJECT(inject_error_list));
- }
- if (set_state_list) {
- qdict_put_obj(opts, "set-state", QOBJECT(set_state_list));
- }
- if (suspend_list) {
- qdict_put_obj(opts, "suspend", QOBJECT(suspend_list));
- }
-
bs->full_open_options = opts;
}