Signed-off-by: Kevin Wolf <kw...@redhat.com> Reviewed-by: Max Reitz <mre...@redhat.com> --- block.c | 42 +++++++++++++++++++++++++++++++++++++++--- block/commit.c | 4 ++-- include/block/block.h | 4 +++- 3 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/block.c b/block.c index 3de83e6..6268e37 100644 --- a/block.c +++ b/block.c @@ -1636,6 +1636,9 @@ typedef struct BlockReopenQueueEntry { * * bs is the BlockDriverState to add to the reopen queue. * + * options contains the changed options for the associated bs + * (the BlockReopenQueue takes ownership) + * * flags contains the open flags for the associated bs * * returns a pointer to bs_queue, which is either the newly allocated @@ -1643,18 +1646,28 @@ typedef struct BlockReopenQueueEntry { * */ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, - BlockDriverState *bs, int flags) + BlockDriverState *bs, + QDict *options, int flags) { assert(bs != NULL); BlockReopenQueueEntry *bs_entry; BdrvChild *child; + QDict *old_options; if (bs_queue == NULL) { bs_queue = g_new0(BlockReopenQueue, 1); QSIMPLEQ_INIT(bs_queue); } + if (!options) { + options = qdict_new(); + } + + old_options = qdict_clone_shallow(bs->options); + qdict_join(options, old_options, false); + QDECREF(old_options); + /* bdrv_open() masks this flag out */ flags &= ~BDRV_O_PROTOCOL; @@ -1666,13 +1679,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, } child_flags = child->role->inherit_flags(flags); - bdrv_reopen_queue(bs_queue, child->bs, child_flags); + /* TODO Pass down child flags (backing.*, extents.*, ...) */ + bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags); } bs_entry = g_new0(BlockReopenQueueEntry, 1); QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); bs_entry->state.bs = bs; + bs_entry->state.options = options; bs_entry->state.flags = flags; return bs_queue; @@ -1725,6 +1740,7 @@ cleanup: if (ret && bs_entry->prepared) { bdrv_reopen_abort(&bs_entry->state); } + QDECREF(bs_entry->state.options); g_free(bs_entry); } g_free(bs_queue); @@ -1737,7 +1753,7 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) { int ret = -1; Error *local_err = NULL; - BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, bdrv_flags); + BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags); ret = bdrv_reopen_multiple(queue, &local_err); if (local_err != NULL) { @@ -1813,6 +1829,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, goto error; } + /* Options that are not handled are only okay if they are unchanged + * compared to the old state. It is expected that some options are only + * used for the initial open, but not reopen (e.g. filename) */ + if (qdict_size(reopen_state->options)) { + const QDictEntry *entry = qdict_first(reopen_state->options); + + do { + QString *new_obj = qobject_to_qstring(entry->value); + const char *new = qstring_get_str(new_obj); + const char *old = qdict_get_try_str(reopen_state->bs->options, + entry->key); + + if (!old || strcmp(new, old)) { + error_setg(errp, "Cannot change the option '%s'", entry->key); + ret = -EINVAL; + goto error; + } + } while ((entry = qdict_next(reopen_state->options, entry))); + } + ret = 0; error: diff --git a/block/commit.c b/block/commit.c index 7312a5b..d12e26f 100644 --- a/block/commit.c +++ b/block/commit.c @@ -236,11 +236,11 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, /* convert base & overlay_bs to r/w, if necessary */ if (!(orig_base_flags & BDRV_O_RDWR)) { - reopen_queue = bdrv_reopen_queue(reopen_queue, base, + reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL, orig_base_flags | BDRV_O_RDWR); } if (!(orig_overlay_flags & BDRV_O_RDWR)) { - reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, + reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL, orig_overlay_flags | BDRV_O_RDWR); } if (reopen_queue) { diff --git a/include/block/block.h b/include/block/block.h index e539194..ef67353 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -147,6 +147,7 @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; typedef struct BDRVReopenState { BlockDriverState *bs; int flags; + QDict *options; void *opaque; } BDRVReopenState; @@ -218,7 +219,8 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp); int bdrv_open(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, Error **errp); BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, - BlockDriverState *bs, int flags); + BlockDriverState *bs, + QDict *options, int flags); int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp); int bdrv_reopen_prepare(BDRVReopenState *reopen_state, -- 1.8.3.1