218e99
From 45958d24d6c9bcdc333844f69f47cacec29cfa0e Mon Sep 17 00:00:00 2001
218e99
From: Max Reitz <mreitz@redhat.com>
218e99
Date: Mon, 4 Nov 2013 22:32:26 +0100
218e99
Subject: [PATCH 33/87] qcow2: Switch L1 table in a single sequence
218e99
218e99
RH-Author: Max Reitz <mreitz@redhat.com>
218e99
Message-id: <1383604354-12743-36-git-send-email-mreitz@redhat.com>
218e99
Patchwork-id: 55335
218e99
O-Subject: [RHEL-7.0 qemu-kvm PATCH 35/43] qcow2: Switch L1 table in a single sequence
218e99
Bugzilla: 1004347
218e99
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
218e99
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
218e99
RH-Acked-by: Fam Zheng <famz@redhat.com>
218e99
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
218e99
218e99
BZ: 1004347
218e99
218e99
Switching the L1 table in memory should be an atomic operation, as far
218e99
as possible. Calling qcow2_free_clusters on the old L1 table on disk is
218e99
not a good idea when the old L1 table is no longer valid and the address
218e99
to the new one hasn't yet been written into the corresponding
218e99
BDRVQcowState field. To be more specific, this can lead to segfaults due
218e99
to qcow2_check_metadata_overlap trying to access the L1 table during the
218e99
free operation.
218e99
218e99
Signed-off-by: Max Reitz <mreitz@redhat.com>
218e99
Reviewed-by: Eric Blake <eblake@redhat.com>
218e99
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
218e99
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
218e99
(cherry picked from commit fda74f826baec78d685e5a87fd8a95bfb7bb2243)
218e99
218e99
Signed-off-by: Max Reitz <mreitz@redhat.com>
218e99
---
218e99
 block/qcow2-cluster.c | 7 +++++--
218e99
 1 file changed, 5 insertions(+), 2 deletions(-)
218e99
218e99
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
218e99
---
218e99
 block/qcow2-cluster.c |    7 +++++--
218e99
 1 files changed, 5 insertions(+), 2 deletions(-)
218e99
218e99
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
218e99
index 2d5aa92..c05f182 100644
218e99
--- a/block/qcow2-cluster.c
218e99
+++ b/block/qcow2-cluster.c
218e99
@@ -35,6 +35,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
218e99
     BDRVQcowState *s = bs->opaque;
218e99
     int new_l1_size2, ret, i;
218e99
     uint64_t *new_l1_table;
218e99
+    int64_t old_l1_table_offset, old_l1_size;
218e99
     int64_t new_l1_table_offset, new_l1_size;
218e99
     uint8_t data[12];
218e99
 
218e99
@@ -106,11 +107,13 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
218e99
         goto fail;
218e99
     }
218e99
     g_free(s->l1_table);
218e99
-    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t),
218e99
-                        QCOW2_DISCARD_OTHER);
218e99
+    old_l1_table_offset = s->l1_table_offset;
218e99
     s->l1_table_offset = new_l1_table_offset;
218e99
     s->l1_table = new_l1_table;
218e99
+    old_l1_size = s->l1_size;
218e99
     s->l1_size = new_l1_size;
218e99
+    qcow2_free_clusters(bs, old_l1_table_offset, old_l1_size * sizeof(uint64_t),
218e99
+                        QCOW2_DISCARD_OTHER);
218e99
     return 0;
218e99
  fail:
218e99
     g_free(new_l1_table);
218e99
-- 
218e99
1.7.1
218e99