int new_state;
int align;
+ /* For blkdebug_refresh_filename() */
+ char *config_file;
+
QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
typedef struct BlkdebugAIOCB {
BlockAIOCB common;
- QEMUBH *bh;
int ret;
} BlkdebugAIOCB;
QLIST_ENTRY(BlkdebugSuspendedReq) next;
} BlkdebugSuspendedReq;
-static const AIOCBInfo blkdebug_aiocb_info = {
- .aiocb_size = sizeof(BlkdebugAIOCB),
-};
-
enum {
ACTION_INJECT_ERROR,
ACTION_SET_STATE,
int error;
int immediately;
int once;
- int64_t sector;
+ int64_t offset;
} inject;
struct {
int new_state;
const char* event_name;
BlkdebugEvent event;
struct BlkdebugRule *rule;
+ int64_t sector;
/* Find the right event for the rule */
event_name = qemu_opt_get(opts, "event");
rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
rule->options.inject.immediately =
qemu_opt_get_bool(opts, "immediately", 0);
- rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
+ sector = qemu_opt_get_number(opts, "sector", -1);
+ rule->options.inject.offset =
+ sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
break;
case ACTION_SET_STATE:
BDRVBlkdebugState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
- const char *config;
uint64_t align;
int ret;
}
/* Read rules from config file or command line options */
- config = qemu_opt_get(opts, "config");
- ret = read_config(s, config, options, errp);
+ s->config_file = g_strdup(qemu_opt_get(opts, "config"));
+ ret = read_config(s, s->config_file, options, errp);
if (ret) {
goto out;
}
fail_unref:
bdrv_unref_child(bs, bs->file);
out:
+ if (ret < 0) {
+ g_free(s->config_file);
+ }
qemu_opts_del(opts);
return ret;
}
-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_unref(acb);
-}
-
-static BlockAIOCB *inject_error(BlockDriverState *bs,
- BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
+static int inject_error(BlockDriverState *bs, BlkdebugRule *rule)
{
BDRVBlkdebugState *s = bs->opaque;
int error = rule->options.inject.error;
- struct BlkdebugAIOCB *acb;
- QEMUBH *bh;
bool immediately = rule->options.inject.immediately;
if (rule->options.inject.once) {
remove_rule(rule);
}
- if (immediately) {
- return NULL;
+ if (!immediately) {
+ aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
+ qemu_coroutine_yield();
}
- acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
- acb->ret = -error;
-
- bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
- acb->bh = bh;
- qemu_bh_schedule(bh);
-
- return &acb->common;
+ return -error;
}
-static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque)
+static int coroutine_fn
+blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
- if (rule->options.inject.sector == -1 ||
- (rule->options.inject.sector >= sector_num &&
- rule->options.inject.sector < sector_num + nb_sectors)) {
+ uint64_t inject_offset = rule->options.inject.offset;
+
+ if (inject_offset == -1 ||
+ (inject_offset >= offset && inject_offset < offset + bytes))
+ {
break;
}
}
if (rule && rule->options.inject.error) {
- return inject_error(bs, cb, opaque, rule);
+ return inject_error(bs, rule);
}
- return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
- cb, opaque);
+ return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
}
-static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque)
+static int coroutine_fn
+blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
- if (rule->options.inject.sector == -1 ||
- (rule->options.inject.sector >= sector_num &&
- rule->options.inject.sector < sector_num + nb_sectors)) {
+ uint64_t inject_offset = rule->options.inject.offset;
+
+ if (inject_offset == -1 ||
+ (inject_offset >= offset && inject_offset < offset + bytes))
+ {
break;
}
}
if (rule && rule->options.inject.error) {
- return inject_error(bs, cb, opaque, rule);
+ return inject_error(bs, rule);
}
- return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
- cb, opaque);
+ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
}
-static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
- BlockCompletionFunc *cb, void *opaque)
+static int blkdebug_co_flush(BlockDriverState *bs)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
- if (rule->options.inject.sector == -1) {
+ if (rule->options.inject.offset == -1) {
break;
}
}
if (rule && rule->options.inject.error) {
- return inject_error(bs, cb, opaque, rule);
+ return inject_error(bs, rule);
}
- return bdrv_aio_flush(bs->file->bs, cb, opaque);
+ return bdrv_co_flush(bs->file->bs);
}
remove_rule(rule);
}
}
+
+ g_free(s->config_file);
}
static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
if (!strcmp(r->tag, tag)) {
- qemu_coroutine_enter(r->co, NULL);
+ qemu_coroutine_enter(r->co);
return 0;
}
}
}
QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
if (!strcmp(r->tag, tag)) {
- qemu_coroutine_enter(r->co, NULL);
+ qemu_coroutine_enter(r->co);
ret = 0;
}
}
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
{
- return bdrv_truncate(bs->file->bs, offset);
+ return bdrv_truncate(bs->file, offset);
}
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
{
+ BDRVBlkdebugState *s = bs->opaque;
QDict *opts;
const QDictEntry *e;
bool force_json = false;
if (!force_json && bs->file->bs->exact_filename[0]) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "blkdebug:%s:%s",
- qdict_get_try_str(options, "config") ?: "",
+ "blkdebug:%s:%s", s->config_file ?: "",
bs->file->bs->exact_filename);
}
.bdrv_file_open = blkdebug_open,
.bdrv_close = blkdebug_close,
.bdrv_reopen_prepare = blkdebug_reopen_prepare,
+ .bdrv_child_perm = bdrv_filter_default_perms,
+
.bdrv_getlength = blkdebug_getlength,
.bdrv_truncate = blkdebug_truncate,
.bdrv_refresh_filename = blkdebug_refresh_filename,
.bdrv_refresh_limits = blkdebug_refresh_limits,
- .bdrv_aio_readv = blkdebug_aio_readv,
- .bdrv_aio_writev = blkdebug_aio_writev,
- .bdrv_aio_flush = blkdebug_aio_flush,
+ .bdrv_co_preadv = blkdebug_co_preadv,
+ .bdrv_co_pwritev = blkdebug_co_pwritev,
+ .bdrv_co_flush_to_disk = blkdebug_co_flush,
.bdrv_debug_event = blkdebug_debug_event,
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,