yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-qcow2-Add-refcount-update-reason-to-all-callers.patch

9ae3a8
From 2e86e4a584cd9054a99d6bb8d3d4d7e8878bff4a Mon Sep 17 00:00:00 2001
9ae3a8
From: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Date: Mon, 9 Sep 2013 14:28:00 +0200
9ae3a8
Subject: [PATCH 09/38] qcow2: Add refcount update reason to all callers
9ae3a8
9ae3a8
RH-Author: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Message-id: <1378736903-18489-10-git-send-email-kwolf@redhat.com>
9ae3a8
Patchwork-id: 54198
9ae3a8
O-Subject: [RHEL-7.0 qemu-kvm PATCH 09/32] qcow2: Add refcount update reason to all callers
9ae3a8
Bugzilla: 1005818
9ae3a8
RH-Acked-by: Fam Zheng <famz@redhat.com>
9ae3a8
RH-Acked-by: Max Reitz <mreitz@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
Bugzilla: 1005818
9ae3a8
9ae3a8
This adds a refcount update reason to all callers of update_refcounts(),
9ae3a8
so that a follow-up patch can use this information to decide whether
9ae3a8
clusters that reach a refcount of 0 should be discarded in the image
9ae3a8
file.
9ae3a8
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
(cherry picked from commit 6cfcb9b8b91d303ab51b78623f2299b5288d2d51)
9ae3a8
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
---
9ae3a8
 block/qcow2-cluster.c  | 19 +++++++++++------
9ae3a8
 block/qcow2-refcount.c | 55 +++++++++++++++++++++++++++++++-------------------
9ae3a8
 block/qcow2-snapshot.c |  6 ++++--
9ae3a8
 block/qcow2.c          |  3 ++-
9ae3a8
 block/qcow2.h          | 16 ++++++++++++---
9ae3a8
 5 files changed, 66 insertions(+), 33 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 block/qcow2-cluster.c  |   19 +++++++++++-----
9ae3a8
 block/qcow2-refcount.c |   55 +++++++++++++++++++++++++++++------------------
9ae3a8
 block/qcow2-snapshot.c |    6 +++-
9ae3a8
 block/qcow2.c          |    3 +-
9ae3a8
 block/qcow2.h          |   16 +++++++++++--
9ae3a8
 5 files changed, 66 insertions(+), 33 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
9ae3a8
index 76f30e5..3191d6b 100644
9ae3a8
--- a/block/qcow2-cluster.c
9ae3a8
+++ b/block/qcow2-cluster.c
9ae3a8
@@ -98,14 +98,16 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
9ae3a8
         goto fail;
9ae3a8
     }
9ae3a8
     g_free(s->l1_table);
9ae3a8
-    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
9ae3a8
+    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t),
9ae3a8
+                        QCOW2_DISCARD_OTHER);
9ae3a8
     s->l1_table_offset = new_l1_table_offset;
9ae3a8
     s->l1_table = new_l1_table;
9ae3a8
     s->l1_size = new_l1_size;
9ae3a8
     return 0;
9ae3a8
  fail:
9ae3a8
     g_free(new_l1_table);
9ae3a8
-    qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
9ae3a8
+    qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,
9ae3a8
+                        QCOW2_DISCARD_OTHER);
9ae3a8
     return ret;
9ae3a8
 }
9ae3a8
 
9ae3a8
@@ -548,7 +550,8 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
9ae3a8
 
9ae3a8
         /* Then decrease the refcount of the old table */
9ae3a8
         if (l2_offset) {
9ae3a8
-            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
9ae3a8
+            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
9ae3a8
+                                QCOW2_DISCARD_OTHER);
9ae3a8
         }
9ae3a8
     }
9ae3a8
 
9ae3a8
@@ -715,10 +718,14 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
9ae3a8
     /*
9ae3a8
      * If this was a COW, we need to decrease the refcount of the old cluster.
9ae3a8
      * Also flush bs->file to get the right order for L2 and refcount update.
9ae3a8
+     *
9ae3a8
+     * Don't discard clusters that reach a refcount of 0 (e.g. compressed
9ae3a8
+     * clusters), the next write will reuse them anyway.
9ae3a8
      */
9ae3a8
     if (j != 0) {
9ae3a8
         for (i = 0; i < j; i++) {
9ae3a8
-            qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1);
9ae3a8
+            qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1,
9ae3a8
+                                    QCOW2_DISCARD_NEVER);
9ae3a8
         }
9ae3a8
     }
9ae3a8
 
9ae3a8
@@ -1339,7 +1346,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
9ae3a8
         l2_table[l2_index + i] = cpu_to_be64(0);
9ae3a8
 
9ae3a8
         /* Then decrease the refcount */
9ae3a8
-        qcow2_free_any_clusters(bs, old_offset, 1);
9ae3a8
+        qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
9ae3a8
     }
9ae3a8
 
9ae3a8
     ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
9ae3a8
@@ -1415,7 +1422,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
9ae3a8
         qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
9ae3a8
         if (old_offset & QCOW_OFLAG_COMPRESSED) {
9ae3a8
             l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
9ae3a8
-            qcow2_free_any_clusters(bs, old_offset, 1);
9ae3a8
+            qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
9ae3a8
         } else {
9ae3a8
             l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
9ae3a8
         }
9ae3a8
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
9ae3a8
index b32738f..6d35e49 100644
9ae3a8
--- a/block/qcow2-refcount.c
9ae3a8
+++ b/block/qcow2-refcount.c
9ae3a8
@@ -29,7 +29,7 @@
9ae3a8
 static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
9ae3a8
 static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
9ae3a8
                             int64_t offset, int64_t length,
9ae3a8
-                            int addend);
9ae3a8
+                            int addend, enum qcow2_discard_type type);
9ae3a8
 
9ae3a8
 
9ae3a8
 /*********************************************************/
9ae3a8
@@ -235,7 +235,8 @@ static int alloc_refcount_block(BlockDriverState *bs,
9ae3a8
     } else {
9ae3a8
         /* Described somewhere else. This can recurse at most twice before we
9ae3a8
          * arrive at a block that describes itself. */
9ae3a8
-        ret = update_refcount(bs, new_block, s->cluster_size, 1);
9ae3a8
+        ret = update_refcount(bs, new_block, s->cluster_size, 1,
9ae3a8
+                              QCOW2_DISCARD_NEVER);
9ae3a8
         if (ret < 0) {
9ae3a8
             goto fail_block;
9ae3a8
         }
9ae3a8
@@ -399,7 +400,8 @@ static int alloc_refcount_block(BlockDriverState *bs,
9ae3a8
 
9ae3a8
     /* Free old table. Remember, we must not change free_cluster_index */
9ae3a8
     uint64_t old_free_cluster_index = s->free_cluster_index;
9ae3a8
-    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
9ae3a8
+    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
9ae3a8
+                        QCOW2_DISCARD_OTHER);
9ae3a8
     s->free_cluster_index = old_free_cluster_index;
9ae3a8
 
9ae3a8
     ret = load_refcount_block(bs, new_block, (void**) refcount_block);
9ae3a8
@@ -420,7 +422,7 @@ fail_block:
9ae3a8
 
9ae3a8
 /* XXX: cache several refcount block clusters ? */
9ae3a8
 static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
9ae3a8
-    int64_t offset, int64_t length, int addend)
9ae3a8
+    int64_t offset, int64_t length, int addend, enum qcow2_discard_type type)
9ae3a8
 {
9ae3a8
     BDRVQcowState *s = bs->opaque;
9ae3a8
     int64_t start, last, cluster_offset;
9ae3a8
@@ -506,7 +508,8 @@ fail:
9ae3a8
      */
9ae3a8
     if (ret < 0) {
9ae3a8
         int dummy;
9ae3a8
-        dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);
9ae3a8
+        dummy = update_refcount(bs, offset, cluster_offset - offset, -addend,
9ae3a8
+                                QCOW2_DISCARD_NEVER);
9ae3a8
         (void)dummy;
9ae3a8
     }
9ae3a8
 
9ae3a8
@@ -522,12 +525,14 @@ fail:
9ae3a8
  */
9ae3a8
 static int update_cluster_refcount(BlockDriverState *bs,
9ae3a8
                                    int64_t cluster_index,
9ae3a8
-                                   int addend)
9ae3a8
+                                   int addend,
9ae3a8
+                                   enum qcow2_discard_type type)
9ae3a8
 {
9ae3a8
     BDRVQcowState *s = bs->opaque;
9ae3a8
     int ret;
9ae3a8
 
9ae3a8
-    ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
9ae3a8
+    ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend,
9ae3a8
+                          type);
9ae3a8
     if (ret < 0) {
9ae3a8
         return ret;
9ae3a8
     }
9ae3a8
@@ -579,7 +584,7 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
9ae3a8
         return offset;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    ret = update_refcount(bs, offset, size, 1);
9ae3a8
+    ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
9ae3a8
     if (ret < 0) {
9ae3a8
         return ret;
9ae3a8
     }
9ae3a8
@@ -611,7 +616,8 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
9ae3a8
     old_free_cluster_index = s->free_cluster_index;
9ae3a8
     s->free_cluster_index = cluster_index + i;
9ae3a8
 
9ae3a8
-    ret = update_refcount(bs, offset, i << s->cluster_bits, 1);
9ae3a8
+    ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
9ae3a8
+                          QCOW2_DISCARD_NEVER);
9ae3a8
     if (ret < 0) {
9ae3a8
         return ret;
9ae3a8
     }
9ae3a8
@@ -649,7 +655,8 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
9ae3a8
         if (free_in_cluster == 0)
9ae3a8
             s->free_byte_offset = 0;
9ae3a8
         if ((offset & (s->cluster_size - 1)) != 0)
9ae3a8
-            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
9ae3a8
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
9ae3a8
+                                    QCOW2_DISCARD_NEVER);
9ae3a8
     } else {
9ae3a8
         offset = qcow2_alloc_clusters(bs, s->cluster_size);
9ae3a8
         if (offset < 0) {
9ae3a8
@@ -659,7 +666,8 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
9ae3a8
         if ((cluster_offset + s->cluster_size) == offset) {
9ae3a8
             /* we are lucky: contiguous data */
9ae3a8
             offset = s->free_byte_offset;
9ae3a8
-            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
9ae3a8
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
9ae3a8
+                                    QCOW2_DISCARD_NEVER);
9ae3a8
             s->free_byte_offset += size;
9ae3a8
         } else {
9ae3a8
             s->free_byte_offset = offset;
9ae3a8
@@ -676,12 +684,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
9ae3a8
 }
9ae3a8
 
9ae3a8
 void qcow2_free_clusters(BlockDriverState *bs,
9ae3a8
-                          int64_t offset, int64_t size)
9ae3a8
+                          int64_t offset, int64_t size,
9ae3a8
+                          enum qcow2_discard_type type)
9ae3a8
 {
9ae3a8
     int ret;
9ae3a8
 
9ae3a8
     BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_FREE);
9ae3a8
-    ret = update_refcount(bs, offset, size, -1);
9ae3a8
+    ret = update_refcount(bs, offset, size, -1, type);
9ae3a8
     if (ret < 0) {
9ae3a8
         fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
9ae3a8
         /* TODO Remember the clusters to free them later and avoid leaking */
9ae3a8
@@ -692,8 +701,8 @@ void qcow2_free_clusters(BlockDriverState *bs,
9ae3a8
  * Free a cluster using its L2 entry (handles clusters of all types, e.g.
9ae3a8
  * normal cluster, compressed cluster, etc.)
9ae3a8
  */
9ae3a8
-void qcow2_free_any_clusters(BlockDriverState *bs,
9ae3a8
-    uint64_t l2_entry, int nb_clusters)
9ae3a8
+void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
9ae3a8
+                             int nb_clusters, enum qcow2_discard_type type)
9ae3a8
 {
9ae3a8
     BDRVQcowState *s = bs->opaque;
9ae3a8
 
9ae3a8
@@ -705,12 +714,12 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
9ae3a8
                            s->csize_mask) + 1;
9ae3a8
             qcow2_free_clusters(bs,
9ae3a8
                 (l2_entry & s->cluster_offset_mask) & ~511,
9ae3a8
-                nb_csectors * 512);
9ae3a8
+                nb_csectors * 512, type);
9ae3a8
         }
9ae3a8
         break;
9ae3a8
     case QCOW2_CLUSTER_NORMAL:
9ae3a8
         qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
9ae3a8
-                            nb_clusters << s->cluster_bits);
9ae3a8
+                            nb_clusters << s->cluster_bits, type);
9ae3a8
         break;
9ae3a8
     case QCOW2_CLUSTER_UNALLOCATED:
9ae3a8
     case QCOW2_CLUSTER_ZERO:
9ae3a8
@@ -785,7 +794,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
                             int ret;
9ae3a8
                             ret = update_refcount(bs,
9ae3a8
                                 (offset & s->cluster_offset_mask) & ~511,
9ae3a8
-                                nb_csectors * 512, addend);
9ae3a8
+                                nb_csectors * 512, addend,
9ae3a8
+                                QCOW2_DISCARD_SNAPSHOT);
9ae3a8
                             if (ret < 0) {
9ae3a8
                                 goto fail;
9ae3a8
                             }
9ae3a8
@@ -795,7 +805,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
                     } else {
9ae3a8
                         uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
9ae3a8
                         if (addend != 0) {
9ae3a8
-                            refcount = update_cluster_refcount(bs, cluster_index, addend);
9ae3a8
+                            refcount = update_cluster_refcount(bs, cluster_index, addend,
9ae3a8
+                                                               QCOW2_DISCARD_SNAPSHOT);
9ae3a8
                         } else {
9ae3a8
                             refcount = get_refcount(bs, cluster_index);
9ae3a8
                         }
9ae3a8
@@ -827,7 +838,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
 
9ae3a8
 
9ae3a8
             if (addend != 0) {
9ae3a8
-                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
9ae3a8
+                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend,
9ae3a8
+                                                   QCOW2_DISCARD_SNAPSHOT);
9ae3a8
             } else {
9ae3a8
                 refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
9ae3a8
             }
9ae3a8
@@ -1253,7 +1265,8 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
9ae3a8
 
9ae3a8
             if (num_fixed) {
9ae3a8
                 ret = update_refcount(bs, i << s->cluster_bits, 1,
9ae3a8
-                                      refcount2 - refcount1);
9ae3a8
+                                      refcount2 - refcount1,
9ae3a8
+                                      QCOW2_DISCARD_ALWAYS);
9ae3a8
                 if (ret >= 0) {
9ae3a8
                     (*num_fixed)++;
9ae3a8
                     continue;
9ae3a8
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
9ae3a8
index 992a5c8..0caac90 100644
9ae3a8
--- a/block/qcow2-snapshot.c
9ae3a8
+++ b/block/qcow2-snapshot.c
9ae3a8
@@ -262,7 +262,8 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
9ae3a8
     }
9ae3a8
 
9ae3a8
     /* free the old snapshot table */
9ae3a8
-    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
9ae3a8
+    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size,
9ae3a8
+                        QCOW2_DISCARD_SNAPSHOT);
9ae3a8
     s->snapshots_offset = snapshots_offset;
9ae3a8
     s->snapshots_size = snapshots_size;
9ae3a8
     return 0;
9ae3a8
@@ -569,7 +570,8 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
9ae3a8
     if (ret < 0) {
9ae3a8
         return ret;
9ae3a8
     }
9ae3a8
-    qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
9ae3a8
+    qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t),
9ae3a8
+                        QCOW2_DISCARD_SNAPSHOT);
9ae3a8
 
9ae3a8
     /* must update the copied flag on the current cluster offsets */
9ae3a8
     ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
9ae3a8
diff --git a/block/qcow2.c b/block/qcow2.c
9ae3a8
index 0fa5cb2..e28ea47 100644
9ae3a8
--- a/block/qcow2.c
9ae3a8
+++ b/block/qcow2.c
9ae3a8
@@ -1196,7 +1196,8 @@ static int preallocate(BlockDriverState *bs)
9ae3a8
 
9ae3a8
         ret = qcow2_alloc_cluster_link_l2(bs, meta);
9ae3a8
         if (ret < 0) {
9ae3a8
-            qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters);
9ae3a8
+            qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters,
9ae3a8
+                                    QCOW2_DISCARD_NEVER);
9ae3a8
             return ret;
9ae3a8
         }
9ae3a8
 
9ae3a8
diff --git a/block/qcow2.h b/block/qcow2.h
9ae3a8
index 6959c6a..64a6479 100644
9ae3a8
--- a/block/qcow2.h
9ae3a8
+++ b/block/qcow2.h
9ae3a8
@@ -129,6 +129,15 @@ enum {
9ae3a8
     QCOW2_COMPAT_FEAT_MASK            = QCOW2_COMPAT_LAZY_REFCOUNTS,
9ae3a8
 };
9ae3a8
 
9ae3a8
+enum qcow2_discard_type {
9ae3a8
+    QCOW2_DISCARD_NEVER = 0,
9ae3a8
+    QCOW2_DISCARD_ALWAYS,
9ae3a8
+    QCOW2_DISCARD_REQUEST,
9ae3a8
+    QCOW2_DISCARD_SNAPSHOT,
9ae3a8
+    QCOW2_DISCARD_OTHER,
9ae3a8
+    QCOW2_DISCARD_MAX
9ae3a8
+};
9ae3a8
+
9ae3a8
 typedef struct Qcow2Feature {
9ae3a8
     uint8_t type;
9ae3a8
     uint8_t bit;
9ae3a8
@@ -349,9 +358,10 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
9ae3a8
     int nb_clusters);
9ae3a8
 int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
9ae3a8
 void qcow2_free_clusters(BlockDriverState *bs,
9ae3a8
-    int64_t offset, int64_t size);
9ae3a8
-void qcow2_free_any_clusters(BlockDriverState *bs,
9ae3a8
-    uint64_t cluster_offset, int nb_clusters);
9ae3a8
+                          int64_t offset, int64_t size,
9ae3a8
+                          enum qcow2_discard_type type);
9ae3a8
+void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
9ae3a8
+                             int nb_clusters, enum qcow2_discard_type type);
9ae3a8
 
9ae3a8
 int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
     int64_t l1_table_offset, int l1_size, int addend);
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8