summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorAlberto Garcia <berto@igalia.com>2016-10-28 10:08:10 +0300
committerKevin Wolf <kwolf@redhat.com>2016-10-31 16:52:38 +0100
commit61b49e48b379db45f0ea91c93a61c873695549a9 (patch)
tree67dac53b67ee625ec04cfa2ec0610dfd5693a457 /block
parentf3ede4b05d1407d48314f0edada5e402865e641e (diff)
downloadqemu-61b49e48b379db45f0ea91c93a61c873695549a9.tar.gz
block: Support streaming to an intermediate layer
This makes sure that the image we are streaming into is open in read-write mode during the operation. Operation blockers are also set in all intermediate nodes, since they will be removed from the chain afterwards. Finally, this also unblocks the stream operation in backing files. Signed-off-by: Alberto Garcia <berto@igalia.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/stream.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/block/stream.c b/block/stream.c
index 31874817c2..b8ab89a105 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -37,6 +37,7 @@ typedef struct StreamBlockJob {
BlockDriverState *base;
BlockdevOnError on_error;
char *backing_file_str;
+ int bs_flags;
} StreamBlockJob;
static int coroutine_fn stream_populate(BlockBackend *blk,
@@ -81,6 +82,11 @@ static void stream_complete(BlockJob *job, void *opaque)
bdrv_set_backing_hd(bs, base);
}
+ /* Reopen the image back in read-only mode if necessary */
+ if (s->bs_flags != bdrv_get_flags(bs)) {
+ bdrv_reopen(bs, s->bs_flags, NULL);
+ }
+
g_free(s->backing_file_str);
block_job_completed(&s->common, data->ret);
g_free(data);
@@ -220,6 +226,8 @@ void stream_start(const char *job_id, BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque, Error **errp)
{
StreamBlockJob *s;
+ BlockDriverState *iter;
+ int orig_bs_flags;
s = block_job_create(job_id, &stream_job_driver, bs, speed,
cb, opaque, errp);
@@ -227,8 +235,24 @@ void stream_start(const char *job_id, BlockDriverState *bs,
return;
}
+ /* Make sure that the image is opened in read-write mode */
+ orig_bs_flags = bdrv_get_flags(bs);
+ if (!(orig_bs_flags & BDRV_O_RDWR)) {
+ if (bdrv_reopen(bs, orig_bs_flags | BDRV_O_RDWR, errp) != 0) {
+ block_job_unref(&s->common);
+ return;
+ }
+ }
+
+ /* Block all intermediate nodes between bs and base, because they
+ * will disappear from the chain after this operation */
+ for (iter = backing_bs(bs); iter && iter != base; iter = backing_bs(iter)) {
+ block_job_add_bdrv(&s->common, iter);
+ }
+
s->base = base;
s->backing_file_str = g_strdup(backing_file_str);
+ s->bs_flags = orig_bs_flags;
s->on_error = on_error;
s->common.co = qemu_coroutine_create(stream_run, s);