*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include "trace.h"
#include "block/blockjob_int.h"
#include "block/block_int.h"
/* The mirror job has no requests in flight any more, but we need to
* drain potential other users of the BDS before changing the graph. */
bdrv_drained_begin(target_bs);
- bdrv_replace_in_backing_chain(to_replace, target_bs);
+ bdrv_replace_node(to_replace, target_bs, &local_err);
bdrv_drained_end(target_bs);
+ if (local_err) {
+ error_report_err(local_err);
+ data->ret = -EPERM;
+ }
}
if (s->to_replace) {
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
* valid. Also give up permissions on mirror_top_bs->backing, which might
* block the removal. */
block_job_remove_all_bdrv(job);
- bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
- bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
+ bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
+ &error_abort);
+ bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
/* We just changed the BDS the job BB refers to (with either or both of the
- * bdrv_replace_in_backing_chain() calls), so switch the BB back so the
- * cleanup does the right thing. We don't need any permissions any more
- * now. */
+ * bdrv_replace_node() calls), so switch the BB back so the cleanup does
+ * the right thing. We don't need any permissions any more now. */
blk_remove_bs(job->blk);
blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
blk_insert_bs(job->blk, mirror_top_bs, &error_abort);
}
if (s->in_flight >= MAX_IN_FLIGHT) {
- trace_mirror_yield(s, s->in_flight, s->buf_free_count, -1);
+ trace_mirror_yield(s, UINT64_MAX, s->buf_free_count,
+ s->in_flight);
mirror_wait_for_io(s);
continue;
}
}
if (s->bdev_length > base_length) {
- ret = blk_truncate(s->target, s->bdev_length);
+ ret = blk_truncate(s->target, s->bdev_length, NULL);
if (ret < 0) {
goto immediate_exit;
}
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
(cnt == 0 && s->in_flight > 0)) {
- trace_mirror_yield(s, s->in_flight, s->buf_free_count, cnt);
+ trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight);
mirror_wait_for_io(s);
continue;
} else if (cnt != 0) {
return bdrv_co_pdiscard(bs->backing->bs, offset, count);
}
+static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
+{
+ bdrv_refresh_filename(bs->backing->bs);
+ pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
+ bs->backing->bs->filename);
+}
+
static void bdrv_mirror_top_close(BlockDriverState *bs)
{
}
.bdrv_co_pdiscard = bdrv_mirror_top_pdiscard,
.bdrv_co_flush = bdrv_mirror_top_flush,
.bdrv_co_get_block_status = bdrv_mirror_top_get_block_status,
+ .bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
.bdrv_close = bdrv_mirror_top_close,
.bdrv_child_perm = bdrv_mirror_top_child_perm,
};
BlockdevOnError on_target_error,
bool unmap,
BlockCompletionFunc *cb,
- void *opaque, Error **errp,
+ void *opaque,
const BlockJobDriver *driver,
bool is_none_mode, BlockDriverState *base,
- bool auto_complete, const char *filter_node_name)
+ bool auto_complete, const char *filter_node_name,
+ Error **errp)
{
MirrorBlockJob *s;
BlockDriverState *mirror_top_bs;
return;
}
mirror_top_bs->total_sectors = bs->total_sectors;
+ bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
- * it alive until block_job_create() even if bs has no parent. */
+ * it alive until block_job_create() succeeds even if bs has no parent. */
bdrv_ref(mirror_top_bs);
bdrv_drained_begin(bs);
bdrv_append(mirror_top_bs, bs, &local_err);
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,
creation_flags, cb, opaque, errp);
- bdrv_unref(mirror_top_bs);
if (!s) {
goto fail;
}
+ /* The block job now has a reference to this node */
+ bdrv_unref(mirror_top_bs);
+
s->source = bs;
s->mirror_top_bs = mirror_top_bs;
fail:
if (s) {
+ /* Make sure this BDS does not go away until we have completed the graph
+ * changes below */
+ bdrv_ref(mirror_top_bs);
+
g_free(s->replaces);
blk_unref(s->target);
- block_job_unref(&s->common);
+ block_job_early_fail(&s->common);
}
- bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
- bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
+ bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
+ &error_abort);
+ bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
+
+ bdrv_unref(mirror_top_bs);
}
void mirror_start(const char *job_id, BlockDriverState *bs,
base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL;
mirror_start_job(job_id, bs, BLOCK_JOB_DEFAULT, target, replaces,
speed, granularity, buf_size, backing_mode,
- on_source_error, on_target_error, unmap, NULL, NULL, errp,
+ on_source_error, on_target_error, unmap, NULL, NULL,
&mirror_job_driver, is_none_mode, base, false,
- filter_node_name);
+ filter_node_name, errp);
}
void commit_active_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *base, int creation_flags,
int64_t speed, BlockdevOnError on_error,
const char *filter_node_name,
- BlockCompletionFunc *cb, void *opaque, Error **errp,
- bool auto_complete)
+ BlockCompletionFunc *cb, void *opaque,
+ bool auto_complete, Error **errp)
{
int orig_base_flags;
Error *local_err = NULL;
mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
MIRROR_LEAVE_BACKING_CHAIN,
- on_error, on_error, true, cb, opaque, &local_err,
+ on_error, on_error, true, cb, opaque,
&commit_active_job_driver, false, base, auto_complete,
- filter_node_name);
+ filter_node_name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto error_restore_flags;