summary refs log tree commit diff stats
path: root/block/commit.c
diff options
context:
space:
mode:
authorAlberto Garcia <berto@igalia.com>2015-10-28 15:43:49 +0200
committerKevin Wolf <kwolf@redhat.com>2015-11-11 16:25:47 +0100
commit3db2bd5508c86a1605258bc77c9672d93b5c350e (patch)
tree430d334eb2a56fe4b7063933fa0d641fb94fbdf0 /block/commit.c
parent89e3a2d86d31212d09ca688193ccecb92c0c77b5 (diff)
downloadfocaccia-qemu-3db2bd5508c86a1605258bc77c9672d93b5c350e.tar.gz
focaccia-qemu-3db2bd5508c86a1605258bc77c9672d93b5c350e.zip
commit: reopen overlay_bs before base
'block-commit' needs write access to two different nodes of the chain:

- 'base', because that's where the data is written to.
- the overlay of 'top', because it needs to update the backing file
  string to point to 'base' after the operation.

Both images have to be opened in read-write mode, and commit_start()
takes care of reopening them if necessary.

With the current implementation, however, when overlay_bs is reopened
in read-write mode it has the side effect of making 'base' read-only
again, eventually making 'block-commit' fail.

This needs to be fixed in bdrv_reopen(), but until we get to that it
can be worked around simply by swapping the order of base and
overlay_bs in the reopen queue.

In order to reproduce this bug, overlay_bs needs to be initially in
read-only mode. That is: the 'top' parameter of 'block-commit' cannot
be the active layer nor its immediate backing chain.

Cc: qemu-stable@nongnu.org
Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block/commit.c')
-rw-r--r--block/commit.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/block/commit.c b/block/commit.c
index fdebe87c16..a5d02aa560 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -236,14 +236,14 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
     orig_overlay_flags = bdrv_get_flags(overlay_bs);
 
     /* convert base & overlay_bs to r/w, if necessary */
-    if (!(orig_base_flags & BDRV_O_RDWR)) {
-        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, NULL,
                                          orig_overlay_flags | BDRV_O_RDWR);
     }
+    if (!(orig_base_flags & BDRV_O_RDWR)) {
+        reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
+                                         orig_base_flags | BDRV_O_RDWR);
+    }
     if (reopen_queue) {
         bdrv_reopen_multiple(reopen_queue, &local_err);
         if (local_err != NULL) {