Patchwork [RFC,V6,33/33] qcow2: Add qcow2_dedup_init and qcow2_dedup_close.

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

Comments

Benoît Canet - Feb. 6, 2013, 12:32 p.m.
Signed-off-by: Benoit Canet <benoit@irqsave.net>
---
 block/qcow2-dedup.c |   97 +++++++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.h       |    2 ++
 2 files changed, 99 insertions(+)
Stefan Hajnoczi - Feb. 8, 2013, 11:12 a.m.
On Wed, Feb 06, 2013 at 01:32:06PM +0100, Benoît Canet wrote:
> +static int qcow2_dedup_alloc(BlockDriverState *bs)
> +{
> +    BDRVQcowState *s = bs->opaque;
> +    int ret;
> +
> +    ret = qcow2_do_table_init(bs,
> +                              &s->dedup_table,
> +                              s->dedup_table_offset,
> +                              s->dedup_table_size,
> +                              false);
> +
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    s->dedup_tree_by_hash = g_tree_new_full(qcow2_dedup_compare_by_hash, NULL,
> +                                            NULL,
> +                                            qcow2_dedup_destroy_qcow_hash_node);
> +    s->dedup_tree_by_sect = g_tree_new_full(qcow2_dedup_compare_by_offset,
> +                                              NULL, NULL, NULL);
> +
> +    s->dedup_cluster_cache = qcow2_cache_create(bs, DEDUP_CACHE_SIZE,
> +                                                s->hash_block_size);

I don't remember any patches that set a dependency on other caches.
This suggests that the write ordering for metadata updates hasn't been
considered yet.

The cache dependencies allow ordering to be expressed between caches.
This way, the refcounts will always be written before the L2 table
updates, for example.

> +
> +    return 0;
> +}
> +
> +static void qcow2_dedup_free(BlockDriverState *bs)
> +{
> +    BDRVQcowState *s = bs->opaque;
> +    g_free(s->dedup_table);
> +
> +    qcow2_cache_flush(bs, s->dedup_cluster_cache);
> +    qcow2_cache_destroy(bs, s->dedup_cluster_cache);
> +    g_tree_destroy(s->dedup_tree_by_sect);
> +    g_tree_destroy(s->dedup_tree_by_hash);
> +}
> +
> +int qcow2_dedup_init(BlockDriverState *bs)
> +{
> +    BDRVQcowState *s = bs->opaque;
> +    int ret = 0;
> +
> +    s->has_dedup = true;
> +
> +    ret = qcow2_dedup_alloc(bs);
> +
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    /* if we are read-only we don't load the deduplication table */
> +    if (bs->read_only) {
> +        return 0;

Might be worth mentioning that has_dedup remains set to true here so
that .bdrv_check() still looks into the dedup tables for read-only
images (qemu-img check is read-only by default).

Patch

diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c
index 9a44697..0679a68 100644
--- a/block/qcow2-dedup.c
+++ b/block/qcow2-dedup.c
@@ -1019,3 +1019,100 @@  bool qcow2_dedup_is_running(BlockDriverState *bs)
     BDRVQcowState *s = bs->opaque;
     return s->has_dedup && s->dedup_status == DEDUP_STATUS_STARTED;
 }
+
+static gint qcow2_dedup_compare_by_hash(gconstpointer a,
+                                        gconstpointer b,
+                                        gpointer data)
+{
+    QCowHash *hash_a = (QCowHash *) a;
+    QCowHash *hash_b = (QCowHash *) b;
+    return memcmp(hash_a->data, hash_b->data, HASH_LENGTH);
+}
+
+static void qcow2_dedup_destroy_qcow_hash_node(gpointer p)
+{
+    QCowHashNode *hash_node = (QCowHashNode *) p;
+    g_free(hash_node);
+}
+
+static gint qcow2_dedup_compare_by_offset(gconstpointer a,
+                                          gconstpointer b,
+                                          gpointer data)
+{
+    uint64_t offset_a = *((uint64_t *) a);
+    uint64_t offset_b = *((uint64_t *) b);
+
+    if (offset_a > offset_b) {
+        return 1;
+    }
+    if (offset_a < offset_b) {
+        return -1;
+    }
+    return 0;
+}
+
+static int qcow2_dedup_alloc(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    ret = qcow2_do_table_init(bs,
+                              &s->dedup_table,
+                              s->dedup_table_offset,
+                              s->dedup_table_size,
+                              false);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    s->dedup_tree_by_hash = g_tree_new_full(qcow2_dedup_compare_by_hash, NULL,
+                                            NULL,
+                                            qcow2_dedup_destroy_qcow_hash_node);
+    s->dedup_tree_by_sect = g_tree_new_full(qcow2_dedup_compare_by_offset,
+                                              NULL, NULL, NULL);
+
+    s->dedup_cluster_cache = qcow2_cache_create(bs, DEDUP_CACHE_SIZE,
+                                                s->hash_block_size);
+
+    return 0;
+}
+
+static void qcow2_dedup_free(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    g_free(s->dedup_table);
+
+    qcow2_cache_flush(bs, s->dedup_cluster_cache);
+    qcow2_cache_destroy(bs, s->dedup_cluster_cache);
+    g_tree_destroy(s->dedup_tree_by_sect);
+    g_tree_destroy(s->dedup_tree_by_hash);
+}
+
+int qcow2_dedup_init(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret = 0;
+
+    s->has_dedup = true;
+
+    ret = qcow2_dedup_alloc(bs);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* if we are read-only we don't load the deduplication table */
+    if (bs->read_only) {
+        return 0;
+    }
+
+    s->dedup_status = DEDUP_STATUS_STARTING;
+
+    return 0;
+}
+
+void qcow2_dedup_close(BlockDriverState *bs)
+{
+    qcow2_dedup_free(bs);
+}
diff --git a/block/qcow2.h b/block/qcow2.h
index 81dc0ea..18e2974 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -504,5 +504,7 @@  void qcow2_dedup_refcount_zero_reached(BlockDriverState *bs,
 void qcow2_dedup_refcount_half_max_reached(BlockDriverState *bs,
                                            uint64_t cluster_index);
 bool qcow2_dedup_is_running(BlockDriverState *bs);
+int qcow2_dedup_init(BlockDriverState *bs);
+void qcow2_dedup_close(BlockDriverState *bs);
 
 #endif