Blame qemu-fix-qcow2-backing-file-with-virtio.patch

Mark McLoughlin 6d739f
From 1df18d4a961a66b9ea28ab83b409f4d9d470f148 Mon Sep 17 00:00:00 2001
Mark McLoughlin 6d739f
From: Kevin Wolf <kwolf@redhat.com>
Mark McLoughlin 6d739f
Date: Thu, 8 Oct 2009 15:02:08 +0200
Mark McLoughlin 6d739f
Subject: [PATCH] qcow2: Bring synchronous read/write back to life
Mark McLoughlin 6d739f
Mark McLoughlin 6d739f
When the synchronous read and write functions were dropped, they were replaced
Mark McLoughlin 6d739f
by generic emulation functions. Unfortunately, these emulation functions don't
Mark McLoughlin 6d739f
provide the same semantics as the original functions did.
Mark McLoughlin 6d739f
Mark McLoughlin 6d739f
The original bdrv_read would mean that we read some data synchronously and that
Mark McLoughlin 6d739f
we won't be interrupted during this read. The latter assumption is no longer
Mark McLoughlin 6d739f
true with the emulation function which needs to use qemu_aio_poll and therefore
Mark McLoughlin 6d739f
allows the callback of any other concurrent AIO request to be run during the
Mark McLoughlin 6d739f
read. Which in turn means that (meta)data read earlier could have changed and
Mark McLoughlin 6d739f
be invalid now. qcow2 is not prepared to work in this way and it's just scary
Mark McLoughlin 6d739f
how many places there are where other requests could run.
Mark McLoughlin 6d739f
Mark McLoughlin 6d739f
I'm not sure yet where exactly it breaks, but you'll see breakage with virtio
Mark McLoughlin 6d739f
on qcow2 with a backing file. Providing synchronous functions again fixes the
Mark McLoughlin 6d739f
problem for me.
Mark McLoughlin 6d739f
Mark McLoughlin 6d739f
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Mark McLoughlin 6d739f
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Mark McLoughlin 6d739f
Fedora-patch: qemu-fix-qcow2-backing-file-with-virtio.patch
Mark McLoughlin 6d739f
---
Mark McLoughlin 6d739f
 block/qcow2-cluster.c |    6 ++--
Mark McLoughlin 6d739f
 block/qcow2.c         |   51 +++++++++++++++++++++++++++++++++++++++++++++++-
Mark McLoughlin 6d739f
 block/qcow2.h         |    3 ++
Mark McLoughlin 6d739f
 3 files changed, 55 insertions(+), 5 deletions(-)
Mark McLoughlin 6d739f
Mark McLoughlin 6d739f
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
Mark McLoughlin 6d739f
index d4631c3..4d0ce16 100644
Mark McLoughlin 6d739f
--- a/block/qcow2-cluster.c
Mark McLoughlin 6d739f
+++ b/block/qcow2-cluster.c
Mark McLoughlin 6d739f
@@ -306,8 +306,8 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
Mark McLoughlin 6d739f
 }
Mark McLoughlin 6d739f
 
Mark McLoughlin 6d739f
 
Mark McLoughlin 6d739f
-static int qcow_read(BlockDriverState *bs, int64_t sector_num,
Mark McLoughlin 6d739f
-                     uint8_t *buf, int nb_sectors)
Mark McLoughlin 6d739f
+int qcow2_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
Mark McLoughlin 6d739f
+    int nb_sectors)
Mark McLoughlin 6d739f
 {
Mark McLoughlin 6d739f
     BDRVQcowState *s = bs->opaque;
Mark McLoughlin 6d739f
     int ret, index_in_cluster, n, n1;
Mark McLoughlin 6d739f
@@ -358,7 +358,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
Mark McLoughlin 6d739f
     n = n_end - n_start;
Mark McLoughlin 6d739f
     if (n <= 0)
Mark McLoughlin 6d739f
         return 0;
Mark McLoughlin 6d739f
-    ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
Mark McLoughlin 6d739f
+    ret = qcow2_read(bs, start_sect + n_start, s->cluster_data, n);
Mark McLoughlin 6d739f
     if (ret < 0)
Mark McLoughlin 6d739f
         return ret;
Mark McLoughlin 6d739f
     if (s->crypt_method) {
Mark McLoughlin 6d739f
diff --git a/block/qcow2.c b/block/qcow2.c
Mark McLoughlin 6d739f
index dd32ea2..ced257e 100644
Mark McLoughlin 6d739f
--- a/block/qcow2.c
Mark McLoughlin 6d739f
+++ b/block/qcow2.c
Mark McLoughlin 6d739f
@@ -855,6 +855,51 @@ static int qcow_make_empty(BlockDriverState *bs)
Mark McLoughlin 6d739f
     return 0;
Mark McLoughlin 6d739f
 }
Mark McLoughlin 6d739f
 
Mark McLoughlin 6d739f
+static int qcow2_write(BlockDriverState *bs, int64_t sector_num,
Mark McLoughlin 6d739f
+                     const uint8_t *buf, int nb_sectors)
Mark McLoughlin 6d739f
+{
Mark McLoughlin 6d739f
+    BDRVQcowState *s = bs->opaque;
Mark McLoughlin 6d739f
+    int ret, index_in_cluster, n;
Mark McLoughlin 6d739f
+    uint64_t cluster_offset;
Mark McLoughlin 6d739f
+    int n_end;
Mark McLoughlin 6d739f
+    QCowL2Meta l2meta;
Mark McLoughlin 6d739f
+
Mark McLoughlin 6d739f
+    while (nb_sectors > 0) {
Mark McLoughlin 6d739f
+        memset(&l2meta, 0, sizeof(l2meta));
Mark McLoughlin 6d739f
+
Mark McLoughlin 6d739f
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
Mark McLoughlin 6d739f
+        n_end = index_in_cluster + nb_sectors;
Mark McLoughlin 6d739f
+        if (s->crypt_method &&
Mark McLoughlin 6d739f
+            n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
Mark McLoughlin 6d739f
+            n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
Mark McLoughlin 6d739f
+        cluster_offset = qcow2_alloc_cluster_offset(bs, sector_num << 9,
Mark McLoughlin 6d739f
+                                              index_in_cluster,
Mark McLoughlin 6d739f
+                                              n_end, &n, &l2meta);
Mark McLoughlin 6d739f
+        if (!cluster_offset)
Mark McLoughlin 6d739f
+            return -1;
Mark McLoughlin 6d739f
+        if (s->crypt_method) {
Mark McLoughlin 6d739f
+            qcow2_encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
Mark McLoughlin 6d739f
+                            &s->aes_encrypt_key);
Mark McLoughlin 6d739f
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
Mark McLoughlin 6d739f
+                              s->cluster_data, n * 512);
Mark McLoughlin 6d739f
+        } else {
Mark McLoughlin 6d739f
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
Mark McLoughlin 6d739f
+        }
Mark McLoughlin 6d739f
+        if (ret != n * 512 || qcow2_alloc_cluster_link_l2(bs, cluster_offset, &l2meta) < 0) {
Mark McLoughlin 6d739f
+            qcow2_free_any_clusters(bs, cluster_offset, l2meta.nb_clusters);
Mark McLoughlin 6d739f
+            return -1;
Mark McLoughlin 6d739f
+        }
Mark McLoughlin 6d739f
+        nb_sectors -= n;
Mark McLoughlin 6d739f
+        sector_num += n;
Mark McLoughlin 6d739f
+        buf += n * 512;
Mark McLoughlin 6d739f
+        if (l2meta.nb_clusters != 0) {
Mark McLoughlin 6d739f
+            LIST_REMOVE(&l2meta, next_in_flight);
Mark McLoughlin 6d739f
+        }
Mark McLoughlin 6d739f
+    }
Mark McLoughlin 6d739f
+    s->cluster_cache_offset = -1; /* disable compressed cache */
Mark McLoughlin 6d739f
+    return 0;
Mark McLoughlin 6d739f
+}
Mark McLoughlin 6d739f
+
Mark McLoughlin 6d739f
 /* XXX: put compressed sectors first, then all the cluster aligned
Mark McLoughlin 6d739f
    tables to avoid losing bytes in alignment */
Mark McLoughlin 6d739f
 static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
Mark McLoughlin 6d739f
@@ -1037,8 +1082,10 @@ static BlockDriver bdrv_qcow2 = {
Mark McLoughlin 6d739f
     .bdrv_set_key	= qcow_set_key,
Mark McLoughlin 6d739f
     .bdrv_make_empty	= qcow_make_empty,
Mark McLoughlin 6d739f
 
Mark McLoughlin 6d739f
-    .bdrv_aio_readv	= qcow_aio_readv,
Mark McLoughlin 6d739f
-    .bdrv_aio_writev	= qcow_aio_writev,
Mark McLoughlin 6d739f
+    .bdrv_read          = qcow2_read,
Mark McLoughlin 6d739f
+    .bdrv_write         = qcow2_write,
Mark McLoughlin 6d739f
+    .bdrv_aio_readv     = qcow_aio_readv,
Mark McLoughlin 6d739f
+    .bdrv_aio_writev    = qcow_aio_writev,
Mark McLoughlin 6d739f
     .bdrv_write_compressed = qcow_write_compressed,
Mark McLoughlin 6d739f
 
Mark McLoughlin 6d739f
     .bdrv_snapshot_create   = qcow2_snapshot_create,
Mark McLoughlin 6d739f
diff --git a/block/qcow2.h b/block/qcow2.h
Mark McLoughlin 6d739f
index 965a2f4..b41aa63 100644
Mark McLoughlin 6d739f
--- a/block/qcow2.h
Mark McLoughlin 6d739f
+++ b/block/qcow2.h
Mark McLoughlin 6d739f
@@ -202,6 +202,9 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
Mark McLoughlin 6d739f
 int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
Mark McLoughlin 6d739f
     QCowL2Meta *m);
Mark McLoughlin 6d739f
 
Mark McLoughlin 6d739f
+int qcow2_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
Mark McLoughlin 6d739f
+    int nb_sectors);
Mark McLoughlin 6d739f
+
Mark McLoughlin 6d739f
 /* qcow2-snapshot.c functions */
Mark McLoughlin 6d739f
 int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
Mark McLoughlin 6d739f
 int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
Mark McLoughlin 6d739f
-- 
Mark McLoughlin 6d739f
1.6.2.5
Mark McLoughlin 6d739f