Patchwork [RFC,V6,21/33] qcow2: Drop hash for a given cluster when dedup makes refcount > 2^16/2.

login
register
mail settings
Submitter Benoît Canet
Date Feb. 6, 2013, 12:31 p.m.
Message ID <1360153926-9492-22-git-send-email-benoit@irqsave.net>
Download mbox | patch
Permalink /patch/218615/
State New
Headers show

Comments

Benoît Canet - Feb. 6, 2013, 12:31 p.m.
A new physical cluster with the same hash value will be used for further
occurrence of this hash.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
---
 block/qcow2-dedup.c    |   32 ++++++++++++++++++++++++++++++++
 block/qcow2-refcount.c |    3 +++
 block/qcow2.h          |    4 ++++
 3 files changed, 39 insertions(+)
Stefan Hajnoczi - Feb. 7, 2013, 10:23 a.m.
On Wed, Feb 06, 2013 at 01:31:54PM +0100, Benoît Canet wrote:
> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
> index a932ff6..fa2559f 100644
> --- a/block/qcow2-refcount.c
> +++ b/block/qcow2-refcount.c
> @@ -489,6 +489,9 @@ int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
>              ret = -EINVAL;
>              goto fail;
>          }
> +        if (s->has_dedup && deduplication && refcount >= 0xFFFF/2) {
> +            qcow2_dedup_refcount_half_max_reached(bs, cluster_index);
> +        }

update_cluster_refcount() calls update_refcount() followed by
get_refcount().  It is not necessary to add the deduplication argument
to update_refcount and perform this check inside update_refcount().

Please either use update_cluster_refcount() or write a similar function,
then you'll get back the actual refcount value and can test it in dedup
code.

>          if (refcount == 0 && cluster_index < s->free_cluster_index) {
>              s->free_cluster_index = cluster_index;
>          }
> diff --git a/block/qcow2.h b/block/qcow2.h
> index dc378a7..f281832 100644
> --- a/block/qcow2.h
> +++ b/block/qcow2.h
> @@ -65,6 +65,8 @@
>  #define DEFAULT_DEDUP_CLUSTER_SIZE 4096
>  
>  #define HASH_LENGTH 32
> +/* indicate that this cluster refcount has reached its maximum value */
> +#define QCOW_FLAG_HALF_MAX_REFCOUNT (1LL << 61)

Missing from the spec.

Patch

diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c
index b1922ab..4819eb3 100644
--- a/block/qcow2-dedup.c
+++ b/block/qcow2-dedup.c
@@ -941,3 +941,35 @@  int qcow2_dedup_store_new_hashes(BlockDriverState *bs,
 
     return ret;
 }
+
+/* Force to use a new physical cluster and QCowHashNode when the refcount pass
+ * 2^16/2.
+ *
+ * @cluster_index: the index of the physical cluster
+ */
+void qcow2_dedup_refcount_half_max_reached(BlockDriverState *bs,
+                                           uint64_t cluster_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowHashNode *hash_node;
+    uint64_t physical_sect = cluster_index * s->cluster_sectors;
+
+    hash_node =  g_tree_lookup(s->dedup_tree_by_sect, &physical_sect);
+
+    if (!hash_node) {
+        return;
+    }
+
+    /* mark this hash so we won't load it anymore at startup after writing it */
+    hash_node->first_logical_sect |= QCOW_FLAG_HALF_MAX_REFCOUNT;
+
+    /* write to disk */
+    qcow2_dedup_read_write_hash(bs,
+                                &hash_node->hash,
+                                &hash_node->first_logical_sect,
+                                hash_node->physical_sect,
+                                true);
+
+    /* remove the QCowHashNode from ram so we won't use it anymore for dedup */
+    qcow2_remove_hash_node(bs, hash_node);
+}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index a932ff6..fa2559f 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -489,6 +489,9 @@  int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
             ret = -EINVAL;
             goto fail;
         }
+        if (s->has_dedup && deduplication && refcount >= 0xFFFF/2) {
+            qcow2_dedup_refcount_half_max_reached(bs, cluster_index);
+        }
         if (refcount == 0 && cluster_index < s->free_cluster_index) {
             s->free_cluster_index = cluster_index;
         }
diff --git a/block/qcow2.h b/block/qcow2.h
index dc378a7..f281832 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -65,6 +65,8 @@ 
 #define DEFAULT_DEDUP_CLUSTER_SIZE 4096
 
 #define HASH_LENGTH 32
+/* indicate that this cluster refcount has reached its maximum value */
+#define QCOW_FLAG_HALF_MAX_REFCOUNT (1LL << 61)
 /* indicate that the hash structure is empty and miss offset */
 #define QCOW_FLAG_EMPTY   (1LL << 62)
 /* indicate that the cluster for this hash has QCOW_OFLAG_COPIED on disk */
@@ -496,5 +498,7 @@  int qcow2_dedup_store_new_hashes(BlockDriverState *bs,
                                  int count,
                                  uint64_t logical_sect,
                                  uint64_t physical_sect);
+void qcow2_dedup_refcount_half_max_reached(BlockDriverState *bs,
+                                           uint64_t cluster_index);
 
 #endif