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

Submitted by Benoît Canet on Feb. 6, 2013, 12:32 p.m.

Details

Message ID 1360153926-9492-34-git-send-email-benoit@irqsave.net
State New
Headers show

Commit Message

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(+)

Comments

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 hide | download patch | download mbox

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