Commit 27eb6c09 authored by Kevin Wolf's avatar Kevin Wolf Committed by Stefan Hajnoczi
Browse files

qcow2: Don't write with BDRV_O_INCOMING



qcow2_open() causes writes when repairing an image with the dirty flag
set and when clearing autoclear flags. It shouldn't do this when another
qemu instance is still actively working on this image file.

One effect of the bug is that images may have a cleared dirty flag while
the migration source host still has it in use with lazy refcounts
enabled, so refcounts are not accurate and the dirty flag must remain
set.

Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
parent d475e5ac
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -644,7 +644,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
    }

    /* Clear unknown autoclear feature bits */
    if (!bs->read_only && s->autoclear_features != 0) {
    if (!bs->read_only && !(flags & BDRV_O_INCOMING) && s->autoclear_features) {
        s->autoclear_features = 0;
        ret = qcow2_update_header(bs);
        if (ret < 0) {
@@ -657,7 +657,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
    qemu_co_mutex_init(&s->lock);

    /* Repair image if dirty */
    if (!(flags & BDRV_O_CHECK) && !bs->read_only &&
    if (!(flags & (BDRV_O_CHECK | BDRV_O_INCOMING)) && !bs->read_only &&
        (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
        BdrvCheckResult result = {0};

@@ -1137,10 +1137,12 @@ static void qcow2_close(BlockDriverState *bs)
    /* else pre-write overlap checks in cache_destroy may crash */
    s->l1_table = NULL;

    if (!(bs->open_flags & BDRV_O_INCOMING)) {
        qcow2_cache_flush(bs, s->l2_table_cache);
        qcow2_cache_flush(bs, s->refcount_block_cache);

        qcow2_mark_clean(bs);
    }

    qcow2_cache_destroy(bs, s->l2_table_cache);
    qcow2_cache_destroy(bs, s->refcount_block_cache);