diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2017-04-07 15:23:48 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2017-04-07 15:23:48 +0100 |
| commit | 5daf9b3025baef10ee7b77daa003d5696b58d5dc (patch) | |
| tree | 069acb65d303c4cb21563ff732a185c9bfe3a59a /block | |
| parent | 5fe2339e6b09da7d6f48b9bef0f1a7360392b489 (diff) | |
| parent | 19dd29e8a77cd820515de5289f566508e0ed4926 (diff) | |
| download | focaccia-qemu-5daf9b3025baef10ee7b77daa003d5696b58d5dc.tar.gz focaccia-qemu-5daf9b3025baef10ee7b77daa003d5696b58d5dc.zip | |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer fixes for 2.9.0-rc4 # gpg: Signature made Fri 07 Apr 2017 13:44:17 BST # gpg: using RSA key 0x7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: mirror: Fix aio context of mirror_top_bs block: Assert attached child node has right aio context block: Fix unpaired aio_disable_external in external snapshot block: Don't check permissions for copy on read qemu-img: img_create does not support image-opts, fix docs iotests: Add mirror tests for orphaned source block/mirror: Fix use-after-free commit: Set commit_top_bs->total_sectors commit: Set commit_top_bs->aio_context block: Ignore guest dev permissions during incoming migration Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'block')
| -rw-r--r-- | block/block-backend.c | 40 | ||||
| -rw-r--r-- | block/commit.c | 3 | ||||
| -rw-r--r-- | block/io.c | 9 | ||||
| -rw-r--r-- | block/mirror.c | 13 |
4 files changed, 61 insertions, 4 deletions
diff --git a/block/block-backend.c b/block/block-backend.c index 0b6377332c..18ece99c6e 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -61,6 +61,7 @@ struct BlockBackend { uint64_t perm; uint64_t shared_perm; + bool disable_perm; bool allow_write_beyond_eof; @@ -578,7 +579,7 @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, { int ret; - if (blk->root) { + if (blk->root && !blk->disable_perm) { ret = bdrv_child_try_set_perm(blk->root, perm, shared_perm, errp); if (ret < 0) { return ret; @@ -597,15 +598,52 @@ void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm) *shared_perm = blk->shared_perm; } +/* + * Notifies the user of all BlockBackends that migration has completed. qdev + * devices can tighten their permissions in response (specifically revoke + * shared write permissions that we needed for storage migration). + * + * If an error is returned, the VM cannot be allowed to be resumed. + */ +void blk_resume_after_migration(Error **errp) +{ + BlockBackend *blk; + Error *local_err = NULL; + + for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) { + if (!blk->disable_perm) { + continue; + } + + blk->disable_perm = false; + + blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err); + if (local_err) { + error_propagate(errp, local_err); + blk->disable_perm = true; + return; + } + } +} + static int blk_do_attach_dev(BlockBackend *blk, void *dev) { if (blk->dev) { return -EBUSY; } + + /* While migration is still incoming, we don't need to apply the + * permissions of guest device BlockBackends. We might still have a block + * job or NBD server writing to the image for storage migration. */ + if (runstate_check(RUN_STATE_INMIGRATE)) { + blk->disable_perm = true; + } + blk_ref(blk); blk->dev = dev; blk->legacy_dev = false; blk_iostatus_reset(blk); + return 0; } diff --git a/block/commit.c b/block/commit.c index 28324820a4..91d2c344f6 100644 --- a/block/commit.c +++ b/block/commit.c @@ -335,6 +335,8 @@ void commit_start(const char *job_id, BlockDriverState *bs, if (commit_top_bs == NULL) { goto fail; } + commit_top_bs->total_sectors = top->total_sectors; + bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top)); bdrv_set_backing_hd(commit_top_bs, top, &local_err); if (local_err) { @@ -482,6 +484,7 @@ int bdrv_commit(BlockDriverState *bs) error_report_err(local_err); goto ro_cleanup; } + bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(backing_file_bs)); bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort); bdrv_set_backing_hd(bs, commit_top_bs, &error_abort); diff --git a/block/io.c b/block/io.c index 2709a7007f..7321ddab3d 100644 --- a/block/io.c +++ b/block/io.c @@ -945,7 +945,14 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, size_t skip_bytes; int ret; - assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE)); + /* FIXME We cannot require callers to have write permissions when all they + * are doing is a read request. If we did things right, write permissions + * would be obtained anyway, but internally by the copy-on-read code. As + * long as it is implemented here rather than in a separat filter driver, + * the copy-on-read code doesn't have its own BdrvChild, however, for which + * it could request permissions. Therefore we have to bypass the permission + * system for the moment. */ + // assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE)); /* Cover entire cluster so no additional backing file I/O is required when * allocating cluster in the image file. diff --git a/block/mirror.c b/block/mirror.c index 9e2fecc15e..164438f422 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1148,9 +1148,10 @@ static void mirror_start_job(const char *job_id, BlockDriverState *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); @@ -1168,10 +1169,12 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, 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; @@ -1242,6 +1245,10 @@ static void mirror_start_job(const char *job_id, BlockDriverState *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); @@ -1250,6 +1257,8 @@ fail: 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, |