Commit e376a788 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'kwolf/for-anthony' into staging



* kwolf/for-anthony: (43 commits)
  qcow2: Factor out handle_dependencies()
  qcow2: Execute run_dependent_requests() without lock
  qcow2: Enable dirty flag in qcow2_alloc_cluster_link_l2
  qcow2: Allocate l2meta only for cluster allocations
  qcow2: Drop l2meta.cluster_offset
  qcow2: Allocate l2meta dynamically
  qcow2: Introduce Qcow2COWRegion
  qcow2: Round QCowL2Meta.offset down to cluster boundary
  atapi: reset cdrom tray statuses on ide_reset
  qemu-iotests: Test concurrent cluster allocations
  qcow2: Move BLKDBG_EVENT out of the lock
  qemu-io: Add AIO debugging commands
  blkdebug: Implement suspend/resume of AIO requests
  blkdebug: Factor out remove_rule()
  blkdebug: Allow usage without config file
  create new function: qemu_opt_set_number
  use qemu_opts_create_nofail
  introduce qemu_opts_create_nofail function
  qemu-option: qemu_opt_set_bool(): fix code duplication
  qemu-option: qemu_opts_validate(): fix duplicated code
  ...

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents df933007 226c3c26
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -215,8 +215,3 @@ void aio_context_unref(AioContext *ctx)
{
    g_source_unref(&ctx->source);
}

void aio_flush(AioContext *ctx)
{
    while (aio_poll(ctx, true));
}
+141 −78
Original line number Diff line number Diff line
@@ -518,22 +518,16 @@ BlockDriver *bdrv_find_protocol(const char *filename)
    return NULL;
}

static int find_image_format(const char *filename, BlockDriver **pdrv)
static int find_image_format(BlockDriverState *bs, const char *filename,
                             BlockDriver **pdrv)
{
    int ret, score, score_max;
    int score, score_max;
    BlockDriver *drv1, *drv;
    uint8_t buf[2048];
    BlockDriverState *bs;

    ret = bdrv_file_open(&bs, filename, 0);
    if (ret < 0) {
        *pdrv = NULL;
        return ret;
    }
    int ret = 0;

    /* Return the raw BlockDriver * to scsi-generic devices or empty drives */
    if (bs->sg || !bdrv_is_inserted(bs)) {
        bdrv_delete(bs);
        drv = bdrv_find_format("raw");
        if (!drv) {
            ret = -ENOENT;
@@ -543,7 +537,6 @@ static int find_image_format(const char *filename, BlockDriver **pdrv)
    }

    ret = bdrv_pread(bs, 0, buf, sizeof(buf));
    bdrv_delete(bs);
    if (ret < 0) {
        *pdrv = NULL;
        return ret;
@@ -634,10 +627,31 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
    bs->copy_on_read--;
}

static int bdrv_open_flags(BlockDriverState *bs, int flags)
{
    int open_flags = flags | BDRV_O_CACHE_WB;

    /*
     * Clear flags that are internal to the block layer before opening the
     * image.
     */
    open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);

    /*
     * Snapshots should be writable.
     */
    if (bs->is_temporary) {
        open_flags |= BDRV_O_RDWR;
    }

    return open_flags;
}

/*
 * Common part for opening disk images and files
 */
static int bdrv_open_common(BlockDriverState *bs, const char *filename,
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
    const char *filename,
    int flags, BlockDriver *drv)
{
    int ret, open_flags;
@@ -665,32 +679,23 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
    bs->opaque = g_malloc0(drv->instance_size);

    bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
    open_flags = flags | BDRV_O_CACHE_WB;

    /*
     * Clear flags that are internal to the block layer before opening the
     * image.
     */
    open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);

    /*
     * Snapshots should be writable.
     */
    if (bs->is_temporary) {
        open_flags |= BDRV_O_RDWR;
    }
    open_flags = bdrv_open_flags(bs, flags);

    bs->read_only = !(open_flags & BDRV_O_RDWR);

    /* Open the image, either directly or using a protocol */
    if (drv->bdrv_file_open) {
        if (file != NULL) {
            bdrv_swap(file, bs);
            ret = 0;
        } else {
            ret = drv->bdrv_file_open(bs, filename, open_flags);
        }
    } else {
        ret = bdrv_file_open(&bs->file, filename, open_flags);
        if (ret >= 0) {
        assert(file != NULL);
        bs->file = file;
        ret = drv->bdrv_open(bs, open_flags);
    }
    }

    if (ret < 0) {
        goto free_and_fail;
@@ -709,10 +714,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
    return 0;

free_and_fail:
    if (bs->file) {
        bdrv_delete(bs->file);
    bs->file = NULL;
    }
    g_free(bs->opaque);
    bs->opaque = NULL;
    bs->drv = NULL;
@@ -734,7 +736,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
    }

    bs = bdrv_new("");
    ret = bdrv_open_common(bs, filename, flags, drv);
    ret = bdrv_open_common(bs, NULL, filename, flags, drv);
    if (ret < 0) {
        bdrv_delete(bs);
        return ret;
@@ -789,6 +791,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
    int ret;
    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
    char tmp_filename[PATH_MAX + 1];
    BlockDriverState *file = NULL;

    if (flags & BDRV_O_SNAPSHOT) {
        BlockDriverState *bs1;
@@ -848,25 +851,36 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
        bs->is_temporary = 1;
    }

    /* Open image file without format layer */
    if (flags & BDRV_O_RDWR) {
        flags |= BDRV_O_ALLOW_RDWR;
    }

    ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags));
    if (ret < 0) {
        return ret;
    }

    /* Find the right image format driver */
    if (!drv) {
        ret = find_image_format(filename, &drv);
        ret = find_image_format(file, filename, &drv);
    }

    if (!drv) {
        goto unlink_and_fail;
    }

    if (flags & BDRV_O_RDWR) {
        flags |= BDRV_O_ALLOW_RDWR;
    }

    /* Open the image */
    ret = bdrv_open_common(bs, filename, flags, drv);
    ret = bdrv_open_common(bs, file, filename, flags, drv);
    if (ret < 0) {
        goto unlink_and_fail;
    }

    if (bs->file != file) {
        bdrv_delete(file);
        file = NULL;
    }

    /* If there is a backing file, use it */
    if ((flags & BDRV_O_NO_BACKING) == 0) {
        ret = bdrv_open_backing_file(bs);
@@ -888,6 +902,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
    return 0;

unlink_and_fail:
    if (file != NULL) {
        bdrv_delete(file);
    }
    if (bs->is_temporary) {
        unlink(filename);
    }
@@ -3028,7 +3045,46 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
    }

    drv->bdrv_debug_event(bs, event);
}

int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
                          const char *tag)
{
    while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
        bs = bs->file;
    }

    if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) {
        return bs->drv->bdrv_debug_breakpoint(bs, event, tag);
    }

    return -ENOTSUP;
}

int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
{
    while (bs && bs->drv && !bs->drv->bdrv_debug_resume) {
        bs = bs->file;
    }

    if (bs && bs->drv && bs->drv->bdrv_debug_resume) {
        return bs->drv->bdrv_debug_resume(bs, tag);
    }

    return -ENOTSUP;
}

bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
{
    while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
        bs = bs->file;
    }

    if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) {
        return bs->drv->bdrv_debug_is_suspended(bs, tag);
    }

    return false;
}

/**************************************************************/
@@ -3778,12 +3834,20 @@ typedef struct BlockDriverAIOCBCoroutine {
    BlockDriverAIOCB common;
    BlockRequest req;
    bool is_write;
    bool *done;
    QEMUBH* bh;
} BlockDriverAIOCBCoroutine;

static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
{
    qemu_aio_flush();
    BlockDriverAIOCBCoroutine *acb =
        container_of(blockacb, BlockDriverAIOCBCoroutine, common);
    bool done = false;

    acb->done = &done;
    while (!done) {
        qemu_aio_wait();
    }
}

static const AIOCBInfo bdrv_em_co_aiocb_info = {
@@ -3796,6 +3860,11 @@ static void bdrv_co_em_bh(void *opaque)
    BlockDriverAIOCBCoroutine *acb = opaque;

    acb->common.cb(acb->common.opaque, acb->req.error);

    if (acb->done) {
        *acb->done = true;
    }

    qemu_bh_delete(acb->bh);
    qemu_aio_release(acb);
}
@@ -3834,6 +3903,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
    acb->req.nb_sectors = nb_sectors;
    acb->req.qiov = qiov;
    acb->is_write = is_write;
    acb->done = NULL;

    co = qemu_coroutine_create(bdrv_co_do_rw);
    qemu_coroutine_enter(co, acb);
@@ -3860,6 +3930,8 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
    BlockDriverAIOCBCoroutine *acb;

    acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
    acb->done = NULL;

    co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
    qemu_coroutine_enter(co, acb);

@@ -3888,6 +3960,7 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
    acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
    acb->req.sector = sector_num;
    acb->req.nb_sectors = nb_sectors;
    acb->done = NULL;
    co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
    qemu_coroutine_enter(co, acb);

@@ -4408,9 +4481,9 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
    bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
}

int bdrv_img_create(const char *filename, const char *fmt,
void bdrv_img_create(const char *filename, const char *fmt,
                     const char *base_filename, const char *base_fmt,
                    char *options, uint64_t img_size, int flags)
                     char *options, uint64_t img_size, int flags, Error **errp)
{
    QEMUOptionParameter *param = NULL, *create_options = NULL;
    QEMUOptionParameter *backing_fmt, *backing_file, *size;
@@ -4422,16 +4495,14 @@ int bdrv_img_create(const char *filename, const char *fmt,
    /* Find driver and parse its options */
    drv = bdrv_find_format(fmt);
    if (!drv) {
        error_report("Unknown file format '%s'", fmt);
        ret = -EINVAL;
        goto out;
        error_setg(errp, "Unknown file format '%s'", fmt);
        return;
    }

    proto_drv = bdrv_find_protocol(filename);
    if (!proto_drv) {
        error_report("Unknown protocol '%s'", filename);
        ret = -EINVAL;
        goto out;
        error_setg(errp, "Unknown protocol '%s'", filename);
        return;
    }

    create_options = append_option_parameters(create_options,
@@ -4448,8 +4519,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
    if (options) {
        param = parse_option_parameters(options, create_options, param);
        if (param == NULL) {
            error_report("Invalid options for file format '%s'.", fmt);
            ret = -EINVAL;
            error_setg(errp, "Invalid options for file format '%s'.", fmt);
            goto out;
        }
    }
@@ -4457,18 +4527,16 @@ int bdrv_img_create(const char *filename, const char *fmt,
    if (base_filename) {
        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
                                 base_filename)) {
            error_report("Backing file not supported for file format '%s'",
            error_setg(errp, "Backing file not supported for file format '%s'",
                       fmt);
            ret = -EINVAL;
            goto out;
        }
    }

    if (base_fmt) {
        if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
            error_report("Backing file format not supported for file "
            error_setg(errp, "Backing file format not supported for file "
                             "format '%s'", fmt);
            ret = -EINVAL;
            goto out;
        }
    }
@@ -4476,9 +4544,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
    if (backing_file && backing_file->value.s) {
        if (!strcmp(filename, backing_file->value.s)) {
            error_report("Error: Trying to create an image with the "
            error_setg(errp, "Error: Trying to create an image with the "
                             "same filename as the backing file");
            ret = -EINVAL;
            goto out;
        }
    }
@@ -4487,9 +4554,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
    if (backing_fmt && backing_fmt->value.s) {
        backing_drv = bdrv_find_format(backing_fmt->value.s);
        if (!backing_drv) {
            error_report("Unknown backing file format '%s'",
            error_setg(errp, "Unknown backing file format '%s'",
                       backing_fmt->value.s);
            ret = -EINVAL;
            goto out;
        }
    }
@@ -4511,7 +4577,8 @@ int bdrv_img_create(const char *filename, const char *fmt,

            ret = bdrv_open(bs, backing_file->value.s, back_flags, backing_drv);
            if (ret < 0) {
                error_report("Could not open '%s'", backing_file->value.s);
                error_setg_errno(errp, -ret, "Could not open '%s'",
                                 backing_file->value.s);
                goto out;
            }
            bdrv_get_geometry(bs, &size);
@@ -4520,8 +4587,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
            snprintf(buf, sizeof(buf), "%" PRId64, size);
            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
        } else {
            error_report("Image creation needs a size parameter");
            ret = -EINVAL;
            error_setg(errp, "Image creation needs a size parameter");
            goto out;
        }
    }
@@ -4531,16 +4597,15 @@ int bdrv_img_create(const char *filename, const char *fmt,
    puts("");

    ret = bdrv_create(drv, filename, param);

    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error_report("Formatting or formatting option not supported for "
            error_setg(errp,"Formatting or formatting option not supported for "
                            "file format '%s'", fmt);
        } else if (ret == -EFBIG) {
            error_report("The image size is too large for file format '%s'",
            error_setg(errp, "The image size is too large for file format '%s'",
                       fmt);
        } else {
            error_report("%s: error while creating %s: %s", filename, fmt,
            error_setg(errp, "%s: error while creating %s: %s", filename, fmt,
                       strerror(-ret));
        }
    }
@@ -4552,6 +4617,4 @@ out:
    if (bs) {
        bdrv_delete(bs);
    }

    return ret;
}
+8 −3
Original line number Diff line number Diff line
@@ -343,9 +343,9 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
                      int64_t pos, int size);

int bdrv_img_create(const char *filename, const char *fmt,
void bdrv_img_create(const char *filename, const char *fmt,
                     const char *base_filename, const char *base_fmt,
                    char *options, uint64_t img_size, int flags);
                     char *options, uint64_t img_size, int flags, Error **errp);

void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
@@ -431,4 +431,9 @@ typedef enum {
#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);

int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
                           const char *tag);
int bdrv_debug_resume(BlockDriverState *bs, const char *tag);
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);

#endif
+123 −5
Original line number Diff line number Diff line
@@ -29,8 +29,10 @@
typedef struct BDRVBlkdebugState {
    int state;
    int new_state;

    QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
    QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
    QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
} BDRVBlkdebugState;

typedef struct BlkdebugAIOCB {
@@ -39,6 +41,12 @@ typedef struct BlkdebugAIOCB {
    int ret;
} BlkdebugAIOCB;

typedef struct BlkdebugSuspendedReq {
    Coroutine *co;
    char *tag;
    QLIST_ENTRY(BlkdebugSuspendedReq) next;
} BlkdebugSuspendedReq;

static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);

static const AIOCBInfo blkdebug_aiocb_info = {
@@ -49,6 +57,7 @@ static const AIOCBInfo blkdebug_aiocb_info = {
enum {
    ACTION_INJECT_ERROR,
    ACTION_SET_STATE,
    ACTION_SUSPEND,
};

typedef struct BlkdebugRule {
@@ -65,6 +74,9 @@ typedef struct BlkdebugRule {
        struct {
            int new_state;
        } set_state;
        struct {
            char *tag;
        } suspend;
    } options;
    QLIST_ENTRY(BlkdebugRule) next;
    QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
@@ -226,6 +238,11 @@ static int add_rule(QemuOpts *opts, void *opaque)
        rule->options.set_state.new_state =
            qemu_opt_get_number(opts, "new_state", 0);
        break;

    case ACTION_SUSPEND:
        rule->options.suspend.tag =
            g_strdup(qemu_opt_get(opts, "tag"));
        break;
    };

    /* Add the rule */
@@ -234,12 +251,32 @@ static int add_rule(QemuOpts *opts, void *opaque)
    return 0;
}

static void remove_rule(BlkdebugRule *rule)
{
    switch (rule->action) {
    case ACTION_INJECT_ERROR:
    case ACTION_SET_STATE:
        break;
    case ACTION_SUSPEND:
        g_free(rule->options.suspend.tag);
        break;
    }

    QLIST_REMOVE(rule, next);
    g_free(rule);
}

static int read_config(BDRVBlkdebugState *s, const char *filename)
{
    FILE *f;
    int ret;
    struct add_rule_data d;

    /* Allow usage without config file */
    if (!*filename) {
        return 0;
    }

    f = fopen(filename, "r");
    if (f == NULL) {
        return -errno;
@@ -389,6 +426,7 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}


static void blkdebug_close(BlockDriverState *bs)
{
    BDRVBlkdebugState *s = bs->opaque;
@@ -397,12 +435,32 @@ static void blkdebug_close(BlockDriverState *bs)

    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
            QLIST_REMOVE(rule, next);
            g_free(rule);
            remove_rule(rule);
        }
    }
}

static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
{
    BDRVBlkdebugState *s = bs->opaque;
    BlkdebugSuspendedReq r;

    r = (BlkdebugSuspendedReq) {
        .co         = qemu_coroutine_self(),
        .tag        = g_strdup(rule->options.suspend.tag),
    };

    remove_rule(rule);
    QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);

    printf("blkdebug: Suspended request '%s'\n", r.tag);
    qemu_coroutine_yield();
    printf("blkdebug: Resuming request '%s'\n", r.tag);

    QLIST_REMOVE(&r, next);
    g_free(r.tag);
}

static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
    bool injected)
{
@@ -426,6 +484,10 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
    case ACTION_SET_STATE:
        s->new_state = rule->options.set_state.new_state;
        break;

    case ACTION_SUSPEND:
        suspend_request(bs, rule);
        break;
    }
    return injected;
}
@@ -433,19 +495,72 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
{
    BDRVBlkdebugState *s = bs->opaque;
    struct BlkdebugRule *rule;
    struct BlkdebugRule *rule, *next;
    bool injected;

    assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);

    injected = false;
    s->new_state = s->state;
    QLIST_FOREACH(rule, &s->rules[event], next) {
    QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
        injected = process_rule(bs, rule, injected);
    }
    s->state = s->new_state;
}

static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
                                     const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
    struct BlkdebugRule *rule;
    BlkDebugEvent blkdebug_event;

    if (get_event_by_name(event, &blkdebug_event) < 0) {
        return -ENOENT;
    }


    rule = g_malloc(sizeof(*rule));
    *rule = (struct BlkdebugRule) {
        .event  = blkdebug_event,
        .action = ACTION_SUSPEND,
        .state  = 0,
        .options.suspend.tag = g_strdup(tag),
    };

    QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);

    return 0;
}

static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
    BlkdebugSuspendedReq *r;

    QLIST_FOREACH(r, &s->suspended_reqs, next) {
        if (!strcmp(r->tag, tag)) {
            qemu_coroutine_enter(r->co, NULL);
            return 0;
        }
    }
    return -ENOENT;
}


static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
{
    BDRVBlkdebugState *s = bs->opaque;
    BlkdebugSuspendedReq *r;

    QLIST_FOREACH(r, &s->suspended_reqs, next) {
        if (!strcmp(r->tag, tag)) {
            return true;
        }
    }
    return false;
}

static int64_t blkdebug_getlength(BlockDriverState *bs)
{
    return bdrv_getlength(bs->file);
@@ -465,6 +580,9 @@ static BlockDriver bdrv_blkdebug = {
    .bdrv_aio_writev    = blkdebug_aio_writev,

    .bdrv_debug_event           = blkdebug_debug_event,
    .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
    .bdrv_debug_resume          = blkdebug_debug_resume,
    .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
};

static void bdrv_blkdebug_init(void)
+1 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ static void coroutine_fn commit_run(void *opaque)

wait:
        /* Note that even when no rate limit is applied we need to yield
         * with no pending I/O here so that qemu_aio_flush() returns.
         * with no pending I/O here so that bdrv_drain_all() returns.
         */
        block_job_sleep_ns(&s->common, rt_clock, delay_ns);
        if (block_job_is_cancelled(&s->common)) {
Loading