Commit 2c56d06b authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging



Block layer patches

# gpg: Signature made Wed 25 May 2016 18:32:40 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (31 commits)
  blockjob: Remove BlockJob.bs
  commit: Use BlockBackend for I/O
  backup: Use BlockBackend for I/O
  backup: Remove bs parameter from backup_do_cow()
  backup: Pack Notifier within BackupBlockJob
  backup: Don't leak BackupBlockJob in error path
  mirror: Use BlockBackend for I/O
  mirror: Allow target that already has a BlockBackend
  stream: Use BlockBackend for I/O
  block: Make blk_co_preadv/pwritev() public
  block: Convert block job core to BlockBackend
  block: Default to enabled write cache in blk_new()
  block: Cancel jobs first in bdrv_close_all()
  block: keep a list of block jobs
  block: Rename blk_write_zeroes()
  dma-helpers: change BlockBackend to opaque value in DMAIOFunc
  dma-helpers: change interface to byte-based
  block: Propagate .drained_begin/end callbacks
  block: Fix reconfiguring graph with drained nodes
  block: Make bdrv_drain() use bdrv_drained_begin/end()
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents a62c8911 b75536c9
Loading
Loading
Loading
Loading
+120 −125
Original line number Diff line number Diff line
@@ -64,16 +64,16 @@ static QTAILQ_HEAD(, BlockDriverState) all_bdrv_states =
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
    QLIST_HEAD_INITIALIZER(bdrv_drivers);

static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                             const char *reference, QDict *options, int flags,
static BlockDriverState *bdrv_open_inherit(const char *filename,
                                           const char *reference,
                                           QDict *options, int flags,
                                           BlockDriverState *parent,
                             const BdrvChildRole *child_role, Error **errp);
                                           const BdrvChildRole *child_role,
                                           Error **errp);

/* If non-zero, use only whitelisted block drivers */
static int use_bdrv_whitelist;

static void bdrv_close(BlockDriverState *bs);

#ifdef _WIN32
static int is_windows_drive_prefix(const char *filename)
{
@@ -220,11 +220,6 @@ void bdrv_register(BlockDriver *bdrv)
    QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
}

BlockDriverState *bdrv_new_root(void)
{
    return bdrv_new();
}

BlockDriverState *bdrv_new(void)
{
    BlockDriverState *bs;
@@ -664,6 +659,18 @@ int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
    return 0;
}

static void bdrv_child_cb_drained_begin(BdrvChild *child)
{
    BlockDriverState *bs = child->opaque;
    bdrv_drained_begin(bs);
}

static void bdrv_child_cb_drained_end(BdrvChild *child)
{
    BlockDriverState *bs = child->opaque;
    bdrv_drained_end(bs);
}

/*
 * Returns the options and flags that a temporary snapshot should get, based on
 * the originally requested flags (the originally requested image will have
@@ -710,6 +717,8 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,

const BdrvChildRole child_file = {
    .inherit_options = bdrv_inherited_options,
    .drained_begin   = bdrv_child_cb_drained_begin,
    .drained_end     = bdrv_child_cb_drained_end,
};

/*
@@ -728,6 +737,8 @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,

const BdrvChildRole child_format = {
    .inherit_options = bdrv_inherited_fmt_options,
    .drained_begin   = bdrv_child_cb_drained_begin,
    .drained_end     = bdrv_child_cb_drained_end,
};

/*
@@ -755,6 +766,8 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,

static const BdrvChildRole child_backing = {
    .inherit_options = bdrv_backing_options,
    .drained_begin   = bdrv_child_cb_drained_begin,
    .drained_end     = bdrv_child_cb_drained_end,
};

static int bdrv_open_flags(BlockDriverState *bs, int flags)
@@ -1155,18 +1168,41 @@ static int bdrv_fill_options(QDict **options, const char *filename,
    return 0;
}

static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
{
    BlockDriverState *old_bs = child->bs;

    if (old_bs) {
        if (old_bs->quiesce_counter && child->role->drained_end) {
            child->role->drained_end(child);
        }
        QLIST_REMOVE(child, next_parent);
    }

    child->bs = new_bs;

    if (new_bs) {
        QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
        if (new_bs->quiesce_counter && child->role->drained_begin) {
            child->role->drained_begin(child);
        }
    }
}

BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
                                  const char *child_name,
                                  const BdrvChildRole *child_role)
                                  const BdrvChildRole *child_role,
                                  void *opaque)
{
    BdrvChild *child = g_new(BdrvChild, 1);
    *child = (BdrvChild) {
        .bs     = child_bs,
        .bs     = NULL,
        .name   = g_strdup(child_name),
        .role   = child_role,
        .opaque = opaque,
    };

    QLIST_INSERT_HEAD(&child_bs->parents, child, next_parent);
    bdrv_replace_child(child, child_bs);

    return child;
}
@@ -1176,7 +1212,8 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
                             const char *child_name,
                             const BdrvChildRole *child_role)
{
    BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role);
    BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role,
                                              parent_bs);
    QLIST_INSERT_HEAD(&parent_bs->children, child, next);
    return child;
}
@@ -1187,7 +1224,9 @@ static void bdrv_detach_child(BdrvChild *child)
        QLIST_REMOVE(child, next);
        child->next.le_prev = NULL;
    }
    QLIST_REMOVE(child, next_parent);

    bdrv_replace_child(child, NULL);

    g_free(child->name);
    g_free(child);
}
@@ -1341,14 +1380,13 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
        qdict_put(options, "driver", qstring_from_str(bs->backing_format));
    }

    backing_hd = NULL;
    ret = bdrv_open_inherit(&backing_hd,
                            *backing_filename ? backing_filename : NULL,
    backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL,
                                   reference, options, 0, bs, &child_backing,
                                   errp);
    if (ret < 0) {
    if (!backing_hd) {
        bs->open_flags |= BDRV_O_NO_BACKING;
        error_prepend(errp, "Could not open backing file: ");
        ret = -EINVAL;
        goto free_exit;
    }

@@ -1388,7 +1426,6 @@ BdrvChild *bdrv_open_child(const char *filename,
    BdrvChild *c = NULL;
    BlockDriverState *bs;
    QDict *image_options;
    int ret;
    char *bdref_key_dot;
    const char *reference;

@@ -1408,10 +1445,9 @@ BdrvChild *bdrv_open_child(const char *filename,
        goto done;
    }

    bs = NULL;
    ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0,
    bs = bdrv_open_inherit(filename, reference, image_options, 0,
                           parent, child_role, errp);
    if (ret < 0) {
    if (!bs) {
        goto done;
    }

@@ -1422,15 +1458,16 @@ done:
    return c;
}

static int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags,
                                     QDict *snapshot_options, Error **errp)
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
                                                   int flags,
                                                   QDict *snapshot_options,
                                                   Error **errp)
{
    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
    char *tmp_filename = g_malloc0(PATH_MAX + 1);
    int64_t total_size;
    QemuOpts *opts = NULL;
    BlockDriverState *bs_snapshot;
    Error *local_err = NULL;
    int ret;

    /* if snapshot, we create a temporary backing file and open it
@@ -1439,7 +1476,6 @@ static int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags,
    /* Get the required size from the image */
    total_size = bdrv_getlength(bs);
    if (total_size < 0) {
        ret = total_size;
        error_setg_errno(errp, -total_size, "Could not get image size");
        goto out;
    }
@@ -1470,22 +1506,26 @@ static int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags,
    qdict_put(snapshot_options, "driver",
              qstring_from_str("qcow2"));

    bs_snapshot = bdrv_new();

    ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
                    flags, &local_err);
    bs_snapshot = bdrv_open(NULL, NULL, snapshot_options, flags, errp);
    snapshot_options = NULL;
    if (ret < 0) {
        error_propagate(errp, local_err);
    if (!bs_snapshot) {
        ret = -EINVAL;
        goto out;
    }

    /* bdrv_append() consumes a strong reference to bs_snapshot (i.e. it will
     * call bdrv_unref() on it), so in order to be able to return one, we have
     * to increase bs_snapshot's refcount here */
    bdrv_ref(bs_snapshot);
    bdrv_append(bs_snapshot, bs);

    g_free(tmp_filename);
    return bs_snapshot;

out:
    QDECREF(snapshot_options);
    g_free(tmp_filename);
    return ret;
    return NULL;
}

/*
@@ -1503,10 +1543,12 @@ out:
 * should be opened. If specified, neither options nor a filename may be given,
 * nor can an existing BDS be reused (that is, *pbs has to be NULL).
 */
static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                             const char *reference, QDict *options, int flags,
static BlockDriverState *bdrv_open_inherit(const char *filename,
                                           const char *reference,
                                           QDict *options, int flags,
                                           BlockDriverState *parent,
                             const BdrvChildRole *child_role, Error **errp)
                                           const BdrvChildRole *child_role,
                                           Error **errp)
{
    int ret;
    BdrvChild *file = NULL;
@@ -1518,7 +1560,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
    QDict *snapshot_options = NULL;
    int snapshot_flags = 0;

    assert(pbs);
    assert(!child_role || !flags);
    assert(!child_role == !parent);

@@ -1526,33 +1567,22 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
        bool options_non_empty = options ? qdict_size(options) : false;
        QDECREF(options);

        if (*pbs) {
            error_setg(errp, "Cannot reuse an existing BDS when referencing "
                       "another block device");
            return -EINVAL;
        }

        if (filename || options_non_empty) {
            error_setg(errp, "Cannot reference an existing block device with "
                       "additional options or a new filename");
            return -EINVAL;
            return NULL;
        }

        bs = bdrv_lookup_bs(reference, reference, errp);
        if (!bs) {
            return -ENODEV;
            return NULL;
        }

        bdrv_ref(bs);
        *pbs = bs;
        return 0;
        return bs;
    }

    if (*pbs) {
        bs = *pbs;
    } else {
    bs = bdrv_new();
    }

    /* NULL means an empty set of options */
    if (options == NULL) {
@@ -1562,7 +1592,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
    /* json: syntax counts as explicit options, as if in the QDict */
    parse_json_protocol(options, &filename, &local_err);
    if (local_err) {
        ret = -EINVAL;
        goto fail;
    }

@@ -1589,7 +1618,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
        drv = bdrv_find_format(drvname);
        if (!drv) {
            error_setg(errp, "Unknown driver: '%s'", drvname);
            ret = -EINVAL;
            goto fail;
        }
    }
@@ -1619,7 +1647,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
        file = bdrv_open_child(filename, options, "file", bs,
                               &child_file, true, &local_err);
        if (local_err) {
            ret = -EINVAL;
            goto fail;
        }
    }
@@ -1646,7 +1673,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
        qdict_put(options, "driver", qstring_from_str(drv->format_name));
    } else if (!drv) {
        error_setg(errp, "Must specify either driver or file");
        ret = -EINVAL;
        goto fail;
    }

@@ -1689,7 +1715,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                       drv->format_name, entry->key);
        }

        ret = -EINVAL;
        goto close_and_fail;
    }

@@ -1700,25 +1725,30 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
               && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
        error_setg(errp,
                   "Guest must be stopped for opening of encrypted image");
        ret = -EBUSY;
        goto close_and_fail;
    }

    QDECREF(options);
    *pbs = bs;

    /* For snapshot=on, create a temporary qcow2 overlay. bs points to the
     * temporary snapshot afterwards. */
    if (snapshot_flags) {
        ret = bdrv_append_temp_snapshot(bs, snapshot_flags, snapshot_options,
                                        &local_err);
        BlockDriverState *snapshot_bs;
        snapshot_bs = bdrv_append_temp_snapshot(bs, snapshot_flags,
                                                snapshot_options, &local_err);
        snapshot_options = NULL;
        if (local_err) {
            goto close_and_fail;
        }
        /* We are not going to return bs but the overlay on top of it
         * (snapshot_bs); thus, we have to drop the strong reference to bs
         * (which we obtained by calling bdrv_new()). bs will not be deleted,
         * though, because the overlay still has a reference to it. */
        bdrv_unref(bs);
        bs = snapshot_bs;
    }

    return 0;
    return bs;

fail:
    if (file != NULL) {
@@ -1729,36 +1759,26 @@ fail:
    QDECREF(bs->options);
    QDECREF(options);
    bs->options = NULL;
    if (!*pbs) {
        /* If *pbs is NULL, a new BDS has been created in this function and
           needs to be freed now. Otherwise, it does not need to be closed,
           since it has not really been opened yet. */
    bdrv_unref(bs);
    }
    if (local_err) {
        error_propagate(errp, local_err);
    }
    return ret;
    return NULL;

close_and_fail:
    /* See fail path, but now the BDS has to be always closed */
    if (*pbs) {
        bdrv_close(bs);
    } else {
    bdrv_unref(bs);
    }
    QDECREF(snapshot_options);
    QDECREF(options);
    if (local_err) {
        error_propagate(errp, local_err);
    }
    return ret;
    return NULL;
}

int bdrv_open(BlockDriverState **pbs, const char *filename,
              const char *reference, QDict *options, int flags, Error **errp)
BlockDriverState *bdrv_open(const char *filename, const char *reference,
                            QDict *options, int flags, Error **errp)
{
    return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL,
    return bdrv_open_inherit(filename, reference, options, flags, NULL,
                             NULL, errp);
}

@@ -2132,6 +2152,7 @@ static void bdrv_close(BlockDriverState *bs)
    BdrvAioNotifier *ban, *ban_next;

    assert(!bs->job);
    assert(!bs->refcnt);

    bdrv_drained_begin(bs); /* complete I/O */
    bdrv_flush(bs);
@@ -2140,8 +2161,6 @@ static void bdrv_close(BlockDriverState *bs)
    bdrv_release_named_dirty_bitmaps(bs);
    assert(QLIST_EMPTY(&bs->dirty_bitmaps));

    bdrv_parent_cb_change_media(bs, false);

    if (bs->drv) {
        BdrvChild *child, *next;

@@ -2190,8 +2209,7 @@ static void bdrv_close(BlockDriverState *bs)

void bdrv_close_all(void)
{
    BlockDriverState *bs;
    AioContext *aio_context;
    block_job_cancel_sync_all();

    /* Drop references from requests still in flight, such as canceled block
     * jobs whose AIO context has not been polled yet */
@@ -2200,25 +2218,7 @@ void bdrv_close_all(void)
    blk_remove_all_bs();
    blockdev_close_all_bdrv_states();

    /* Cancel all block jobs */
    while (!QTAILQ_EMPTY(&all_bdrv_states)) {
        QTAILQ_FOREACH(bs, &all_bdrv_states, bs_list) {
            aio_context = bdrv_get_aio_context(bs);

            aio_context_acquire(aio_context);
            if (bs->job) {
                block_job_cancel_sync(bs->job);
                aio_context_release(aio_context);
                break;
            }
            aio_context_release(aio_context);
        }

        /* All the remaining BlockDriverStates are referenced directly or
         * indirectly from block jobs, so there needs to be at least one BDS
         * directly used by a block job */
        assert(bs);
    }
    assert(QTAILQ_EMPTY(&all_bdrv_states));
}

static void change_parent_backing_link(BlockDriverState *from,
@@ -2228,10 +2228,8 @@ static void change_parent_backing_link(BlockDriverState *from,

    QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
        assert(c->role != &child_backing);
        c->bs = to;
        QLIST_REMOVE(c, next_parent);
        QLIST_INSERT_HEAD(&to->parents, c, next_parent);
        bdrv_ref(to);
        bdrv_replace_child(c, to);
        bdrv_unref(from);
    }
}
@@ -3195,9 +3193,9 @@ void bdrv_invalidate_cache_all(Error **errp)
{
    BlockDriverState *bs;
    Error *local_err = NULL;
    BdrvNextIterator *it = NULL;
    BdrvNextIterator it;

    while ((it = bdrv_next(it, &bs)) != NULL) {
    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
        AioContext *aio_context = bdrv_get_aio_context(bs);

        aio_context_acquire(aio_context);
@@ -3239,11 +3237,11 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
int bdrv_inactivate_all(void)
{
    BlockDriverState *bs = NULL;
    BdrvNextIterator *it = NULL;
    BdrvNextIterator it;
    int ret = 0;
    int pass;

    while ((it = bdrv_next(it, &bs)) != NULL) {
    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
        aio_context_acquire(bdrv_get_aio_context(bs));
    }

@@ -3252,8 +3250,7 @@ int bdrv_inactivate_all(void)
     * the second pass sets the BDRV_O_INACTIVE flag so that no further write
     * is allowed. */
    for (pass = 0; pass < 2; pass++) {
        it = NULL;
        while ((it = bdrv_next(it, &bs)) != NULL) {
        for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
            ret = bdrv_inactivate_recurse(bs, pass);
            if (ret < 0) {
                goto out;
@@ -3262,8 +3259,7 @@ int bdrv_inactivate_all(void)
    }

out:
    it = NULL;
    while ((it = bdrv_next(it, &bs)) != NULL) {
    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
        aio_context_release(bdrv_get_aio_context(bs));
    }

@@ -3547,11 +3543,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
                          qstring_from_str(backing_fmt));
            }

            bs = NULL;
            ret = bdrv_open(&bs, full_backing, NULL, backing_options,
                            back_flags, &local_err);
            bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
                           &local_err);
            g_free(full_backing);
            if (ret < 0) {
            if (!bs) {
                goto out;
            }
            size = bdrv_getlength(bs);
@@ -3753,10 +3748,10 @@ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
bool bdrv_is_first_non_filter(BlockDriverState *candidate)
{
    BlockDriverState *bs;
    BdrvNextIterator *it = NULL;
    BdrvNextIterator it;

    /* walk down the bs forest recursively */
    while ((it = bdrv_next(it, &bs)) != NULL) {
    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
        bool perm;

        /* try to recurse in this top level bs */
+35 −36
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ typedef struct CowRequest {

typedef struct BackupBlockJob {
    BlockJob common;
    BlockDriverState *target;
    BlockBackend *target;
    /* bitmap for sync=incremental */
    BdrvDirtyBitmap *sync_bitmap;
    MirrorSyncMode sync_mode;
@@ -47,6 +47,7 @@ typedef struct BackupBlockJob {
    uint64_t sectors_read;
    unsigned long *done_bitmap;
    int64_t cluster_size;
    NotifierWithReturn before_write;
    QLIST_HEAD(, CowRequest) inflight_reqs;
} BackupBlockJob;

@@ -93,12 +94,12 @@ static void cow_request_end(CowRequest *req)
    qemu_co_queue_restart_all(&req->wait_queue);
}

static int coroutine_fn backup_do_cow(BlockDriverState *bs,
static int coroutine_fn backup_do_cow(BackupBlockJob *job,
                                      int64_t sector_num, int nb_sectors,
                                      bool *error_is_read,
                                      bool is_write_notifier)
{
    BackupBlockJob *job = (BackupBlockJob *)bs->job;
    BlockBackend *blk = job->common.blk;
    CowRequest cow_request;
    struct iovec iov;
    QEMUIOVector bounce_qiov;
@@ -131,20 +132,15 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs,
                start * sectors_per_cluster);

        if (!bounce_buffer) {
            bounce_buffer = qemu_blockalign(bs, job->cluster_size);
            bounce_buffer = blk_blockalign(blk, job->cluster_size);
        }
        iov.iov_base = bounce_buffer;
        iov.iov_len = n * BDRV_SECTOR_SIZE;
        qemu_iovec_init_external(&bounce_qiov, &iov, 1);

        if (is_write_notifier) {
            ret = bdrv_co_readv_no_serialising(bs,
                                           start * sectors_per_cluster,
                                           n, &bounce_qiov);
        } else {
            ret = bdrv_co_readv(bs, start * sectors_per_cluster, n,
                                &bounce_qiov);
        }
        ret = blk_co_preadv(blk, start * job->cluster_size,
                            bounce_qiov.size, &bounce_qiov,
                            is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0);
        if (ret < 0) {
            trace_backup_do_cow_read_fail(job, start, ret);
            if (error_is_read) {
@@ -154,13 +150,11 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs,
        }

        if (buffer_is_zero(iov.iov_base, iov.iov_len)) {
            ret = bdrv_co_write_zeroes(job->target,
                                       start * sectors_per_cluster,
                                       n, BDRV_REQ_MAY_UNMAP);
            ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size,
                                       bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
        } else {
            ret = bdrv_co_writev(job->target,
                                 start * sectors_per_cluster, n,
                                 &bounce_qiov);
            ret = blk_co_pwritev(job->target, start * job->cluster_size,
                                 bounce_qiov.size, &bounce_qiov, 0);
        }
        if (ret < 0) {
            trace_backup_do_cow_write_fail(job, start, ret);
@@ -197,14 +191,16 @@ static int coroutine_fn backup_before_write_notify(
        NotifierWithReturn *notifier,
        void *opaque)
{
    BackupBlockJob *job = container_of(notifier, BackupBlockJob, before_write);
    BdrvTrackedRequest *req = opaque;
    int64_t sector_num = req->offset >> BDRV_SECTOR_BITS;
    int nb_sectors = req->bytes >> BDRV_SECTOR_BITS;

    assert(req->bs == blk_bs(job->common.blk));
    assert((req->offset & (BDRV_SECTOR_SIZE - 1)) == 0);
    assert((req->bytes & (BDRV_SECTOR_SIZE - 1)) == 0);

    return backup_do_cow(req->bs, sector_num, nb_sectors, NULL, true);
    return backup_do_cow(job, sector_num, nb_sectors, NULL, true);
}

static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
@@ -221,7 +217,7 @@ static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
{
    BdrvDirtyBitmap *bm;
    BlockDriverState *bs = job->common.bs;
    BlockDriverState *bs = blk_bs(job->common.blk);

    if (ret < 0 || block_job_is_cancelled(&job->common)) {
        /* Merge the successor back into the parent, delete nothing. */
@@ -279,7 +275,7 @@ static void backup_complete(BlockJob *job, void *opaque)
    BackupBlockJob *s = container_of(job, BackupBlockJob, common);
    BackupCompleteData *data = opaque;

    bdrv_unref(s->target);
    blk_unref(s->target);

    block_job_completed(job, data->ret);
    g_free(data);
@@ -321,7 +317,6 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
    int64_t end;
    int64_t last_cluster = -1;
    int64_t sectors_per_cluster = cluster_size_sectors(job);
    BlockDriverState *bs = job->common.bs;
    HBitmapIter hbi;

    granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
@@ -343,7 +338,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
                if (yield_and_check(job)) {
                    return ret;
                }
                ret = backup_do_cow(bs, cluster * sectors_per_cluster,
                ret = backup_do_cow(job, cluster * sectors_per_cluster,
                                    sectors_per_cluster, &error_is_read,
                                    false);
                if ((ret < 0) &&
@@ -376,11 +371,8 @@ static void coroutine_fn backup_run(void *opaque)
{
    BackupBlockJob *job = opaque;
    BackupCompleteData *data;
    BlockDriverState *bs = job->common.bs;
    BlockDriverState *target = job->target;
    NotifierWithReturn before_write = {
        .notify = backup_before_write_notify,
    };
    BlockDriverState *bs = blk_bs(job->common.blk);
    BlockBackend *target = job->target;
    int64_t start, end;
    int64_t sectors_per_cluster = cluster_size_sectors(job);
    int ret = 0;
@@ -393,7 +385,8 @@ static void coroutine_fn backup_run(void *opaque)

    job->done_bitmap = bitmap_new(end);

    bdrv_add_before_write_notifier(bs, &before_write);
    job->before_write.notify = backup_before_write_notify;
    bdrv_add_before_write_notifier(bs, &job->before_write);

    if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
        while (!block_job_is_cancelled(&job->common)) {
@@ -445,7 +438,7 @@ static void coroutine_fn backup_run(void *opaque)
                }
            }
            /* FULL sync mode we copy the whole drive. */
            ret = backup_do_cow(bs, start * sectors_per_cluster,
            ret = backup_do_cow(job, start * sectors_per_cluster,
                                sectors_per_cluster, &error_is_read, false);
            if (ret < 0) {
                /* Depending on error action, fail now or retry cluster */
@@ -461,14 +454,14 @@ static void coroutine_fn backup_run(void *opaque)
        }
    }

    notifier_with_return_remove(&before_write);
    notifier_with_return_remove(&job->before_write);

    /* wait until pending backup_do_cow() calls have completed */
    qemu_co_rwlock_wrlock(&job->flush_rwlock);
    qemu_co_rwlock_unlock(&job->flush_rwlock);
    g_free(job->done_bitmap);

    bdrv_op_unblock_all(target, job->common.blocker);
    bdrv_op_unblock_all(blk_bs(target), job->common.blocker);

    data = g_malloc(sizeof(*data));
    data->ret = ret;
@@ -485,6 +478,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
{
    int64_t len;
    BlockDriverInfo bdi;
    BackupBlockJob *job = NULL;
    int ret;

    assert(bs);
@@ -542,15 +536,16 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
        goto error;
    }

    BackupBlockJob *job = block_job_create(&backup_job_driver, bs, speed,
                                           cb, opaque, errp);
    job = block_job_create(&backup_job_driver, bs, speed, cb, opaque, errp);
    if (!job) {
        goto error;
    }

    job->target = blk_new();
    blk_insert_bs(job->target, target);

    job->on_source_error = on_source_error;
    job->on_target_error = on_target_error;
    job->target = target;
    job->sync_mode = sync_mode;
    job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ?
                       sync_bitmap : NULL;
@@ -558,7 +553,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
    /* If there is no backing file on the target, we cannot rely on COW if our
     * backup cluster size is smaller than the target cluster size. Even for
     * targets with a backing file, try to avoid COW if possible. */
    ret = bdrv_get_info(job->target, &bdi);
    ret = bdrv_get_info(target, &bdi);
    if (ret < 0 && !target->backing) {
        error_setg_errno(errp, -ret,
            "Couldn't determine the cluster size of the target image, "
@@ -584,4 +579,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
    if (sync_bitmap) {
        bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
    }
    if (job) {
        blk_unref(job->target);
        block_job_unref(&job->common);
    }
}
+52 −71

File changed.

Preview size limit exceeded, changes collapsed.

+33 −20

File changed.

Preview size limit exceeded, changes collapsed.

+37 −60

File changed.

Preview size limit exceeded, changes collapsed.

Loading