Patchwork [RFC,V7,13/32] qcow2: make the deduplication forget a cluster hash when a cluster is to dedupe

login
register
mail settings
Submitter Benoît Canet
Date March 15, 2013, 2:49 p.m.
Message ID <1363358986-8360-14-git-send-email-benoit@irqsave.net>
Download mbox | patch
Permalink /patch/228024/
State New
Headers show

Comments

Benoît Canet - March 15, 2013, 2:49 p.m.
Signed-off-by: Benoit Canet <benoit@irqsave.net>
---
 block/qcow2-cluster.c |   11 +++++++++--
 block/qcow2-dedup.c   |   40 ++++++++++++++++++++++++++++++++++++++++
 block/qcow2.h         |    2 ++
 3 files changed, 51 insertions(+), 2 deletions(-)

Patch

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 0d11ef0..3cbb64f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -683,6 +683,7 @@  int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
     qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
 
     for (i = 0; i < m->nb_clusters; i++) {
+        uint64_t offset = cluster_offset + (i << s->cluster_bits);
         /* if two concurrent writes happen to the same unallocated cluster
 	 * each write allocates separate cluster and writes data concurrently.
 	 * The first one to complete updates l2 table with pointer to its
@@ -692,8 +693,14 @@  int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
         if(l2_table[l2_index + i] != 0)
             old_cluster[j++] = l2_table[l2_index + i];
 
-        l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
-                    (i << s->cluster_bits)) | m->l2_entry_flags);
+        l2_table[l2_index + i] = cpu_to_be64(offset | m->l2_entry_flags);
+
+        /* make the deduplication forget the cluster to avoid making
+         * the dedup pointing to a cluster that has changed on it's back.
+         */
+        if (m->to_deduplicate) {
+            qcow2_dedup_forget_cluster_by_sector(bs, offset >> 9);
+        }
      }
 
 
diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c
index c106bd5..2aca01a 100644
--- a/block/qcow2-dedup.c
+++ b/block/qcow2-dedup.c
@@ -869,6 +869,46 @@  static inline bool is_hash_node_empty(QCowHashNode *hash_node)
     return hash_node->physical_sect & QCOW_DEDUP_FLAG_EMPTY;
 }
 
+/* This function removes a hash_node from the trees given a physical sector
+ *
+ * @physical_sect: The physical sector of the cluster corresponding to the hash
+ */
+static void qcow2_remove_hash_node_by_sector(BlockDriverState *bs,
+                                             uint64_t physical_sect)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowHash hash;
+    int ret = 0;
+    uint8_t *data = qemu_blockalign(bs, s->cluster_sectors * BDRV_SECTOR_SIZE);
+
+
+    /* read the cluster data */
+    ret = bdrv_pread(bs->file, physical_sect << 9, data,  s->cluster_size);
+
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    ret = qcow2_compute_cluster_hash(bs,
+                                     &hash,
+                                     data);
+
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    g_tree_remove(s->dedup_tree_by_hash, &hash);
+
+free_exit:
+    qemu_vfree(data);
+}
+
+void qcow2_dedup_forget_cluster_by_sector(BlockDriverState *bs,
+                                          uint64_t physical_sect)
+{
+    qcow2_remove_hash_node_by_sector(bs, physical_sect);
+}
+
 /* This function store a hash information to disk and RAM
  *
  * @hash:           the QCowHash to process
diff --git a/block/qcow2.h b/block/qcow2.h
index 9f24b4c..2eab1a4 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -467,6 +467,8 @@  int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
 
 /* qcow2-dedup.c functions */
 bool qcow2_must_deduplicate(BlockDriverState *bs);
+void qcow2_dedup_forget_cluster_by_sector(BlockDriverState *bs,
+                                          uint64_t physical_sect);
 int qcow2_dedup_read_missing_and_concatenate(BlockDriverState *bs,
                                              QEMUIOVector *qiov,
                                              uint64_t sector,