Signed-off-by: Benoit Canet <ben...@irqsave.net>
---
 block/qcow2-dedup.c    |   45 +++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2-refcount.c |    3 +++
 block/qcow2.h          |    2 ++
 3 files changed, 50 insertions(+)

diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c
index da4ad5c..599cb2e 100644
--- a/block/qcow2-dedup.c
+++ b/block/qcow2-dedup.c
@@ -656,3 +656,48 @@ int qcow2_dedup_store_new_hashes(BlockDriverState *bs,
 
     return ret;
 }
+
+/* Clean the last reference to a given cluster when its refcount is zero
+ *
+ * @cluster_index: the index of the physical cluster
+ */
+void qcow2_dedup_destroy_hash(BlockDriverState *bs,
+                              uint64_t cluster_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t offset = cluster_index * s->cluster_size;
+    QCowHashInfo hash_info;
+    uint8_t *buf;
+    int ret = 0;
+
+    /* allocate buffer */
+    buf = qemu_blockalign(bs, s->cluster_size);
+
+    /* read cluster from disk */
+    ret = bdrv_pread(bs->file, offset, buf, s->cluster_size);
+
+    /* error */
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    /* clear hash info */
+    memset(&hash_info, 0, sizeof(QCowHashInfo));
+
+    /* compute hash for the cluster */
+    ret = qcow2_compute_cluster_hash(bs,
+                                     &hash_info.hash,
+                                     buf);
+
+
+    /* error */
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    /* delete hash from key value store. It will not be deduplicated anymore */
+    qcow2_store_delete(bs, &s->key_value_store, &hash_info);
+
+free_exit:
+   qemu_vfree(buf);
+}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 3bd8f37..2734cd9 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -482,6 +482,9 @@ static int QEMU_WARN_UNUSED_RESULT 
update_refcount(BlockDriverState *bs,
             ret = -EINVAL;
             goto fail;
         }
+        if (s->has_dedup && refcount == 0) {
+            qcow2_dedup_destroy_hash(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 720131d..6f85e03 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -748,5 +748,7 @@ int qcow2_dedup_store_new_hashes(BlockDriverState *bs,
                                  int count,
                                  uint64_t logical_sect,
                                  uint64_t physical_sect);
+void qcow2_dedup_destroy_hash(BlockDriverState *bs,
+                              uint64_t cluster_index);
 
 #endif
-- 
1.7.10.4


Reply via email to