summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2014-04-03 13:47:50 +0200
committerKevin Wolf <kwolf@redhat.com>2014-04-04 14:12:26 +0200
commit4c2e5f8f46a17966dc45b5a3e07b97434c0eabdf (patch)
treeaa545165b570b6c297d75dd0ae623abd3861e4f1 /block
parentcbee81f6de57ddc1b21ba28f01f6a3b5d87428a5 (diff)
downloadqemu-4c2e5f8f46a17966dc45b5a3e07b97434c0eabdf.tar.gz
qemu-4c2e5f8f46a17966dc45b5a3e07b97434c0eabdf.tar.bz2
qemu-4c2e5f8f46a17966dc45b5a3e07b97434c0eabdf.zip
qcow2: Flush metadata during read-only reopen
If lazy refcounts are enabled for a backing file, committing to this backing file may leave it in a dirty state even if the commit succeeds. The reason is that the bdrv_flush() call in bdrv_commit() doesn't flush refcount updates with lazy refcounts enabled, and qcow2_reopen_prepare() doesn't take care to flush metadata. In order to fix this, this patch also fixes qcow2_mark_clean(), which contains another ineffective bdrv_flush() call beause lazy refcounts are disabled only afterwards. All existing callers of qcow2_mark_clean() either don't modify refcounts or already flush manually, so that this fixes only a latent, but not yet actually triggerable bug. Another instance of the same problem is live snapshots. Again, a real corruption is prevented by an explicit flush for non-read-only images in external_snapshot_prepare(), but images using lazy refcounts stay dirty. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/qcow2.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index 333e26d733..e903d971c3 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -269,12 +269,15 @@ static int qcow2_mark_clean(BlockDriverState *bs)
BDRVQcowState *s = bs->opaque;
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
- int ret = bdrv_flush(bs);
+ int ret;
+
+ s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
+
+ ret = bdrv_flush(bs);
if (ret < 0) {
return ret;
}
- s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
return qcow2_update_header(bs);
}
return 0;
@@ -900,11 +903,25 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
return 0;
}
-/* We have nothing to do for QCOW2 reopen, stubs just return
- * success */
+/* We have no actual commit/abort logic for qcow2, but we need to write out any
+ * unwritten data if we reopen read-only. */
static int qcow2_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
+ int ret;
+
+ if ((state->flags & BDRV_O_RDWR) == 0) {
+ ret = bdrv_flush(state->bs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = qcow2_mark_clean(state->bs);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
return 0;
}