* block_job_completed(). */
bdrv_ref(src);
bdrv_ref(mirror_top_bs);
+ bdrv_ref(target_bs);
+
+ /* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
+ * inserting target_bs at s->to_replace, where we might not be able to get
+ * these permissions. */
+ blk_unref(s->target);
+ s->target = NULL;
/* We don't access the source any more. Dropping any WRITE/RESIZE is
* required before it could become a backing file of target_bs. */
/* 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);
aio_context_release(replace_aio_context);
}
g_free(s->replaces);
- blk_unref(s->target);
- s->target = NULL;
+ bdrv_unref(target_bs);
/* Remove the mirror filter driver from the graph. Before this, get rid of
* the blockers on the intermediate nodes so that the resulting state is
- * valid. */
+ * valid. Also give up permissions on mirror_top_bs->backing, which might
+ * block the removal. */
block_job_remove_all_bdrv(job);
- bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
+ bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
+ 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);
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
if (!s->dirty_bitmap) {
- g_free(s->replaces);
- blk_unref(s->target);
- block_job_unref(&s->common);
- return;
+ goto fail;
}
/* Required permissions are already taken with blk_new() */
block_job_unref(&s->common);
}
- bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
+ bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
+ bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
}
void mirror_start(const char *job_id, BlockDriverState *bs,