Patchwork [RFC,V7,11/32] qcow2: Add qcow2_dedup_grow_table and use it.

login
register
mail settings
Submitter Benoît Canet
Date March 15, 2013, 2:49 p.m.
Message ID <1363358986-8360-12-git-send-email-benoit@irqsave.net>
Download mbox | patch
Permalink /patch/228021/
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-dedup.c   |  100 ++++++++++++++++++++++++++++++++++++++++++++++++-
 include/block/block.h |    4 ++
 2 files changed, 103 insertions(+), 1 deletion(-)

Patch

diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c
index 089b999..819c37e 100644
--- a/block/qcow2-dedup.c
+++ b/block/qcow2-dedup.c
@@ -40,6 +40,100 @@  static int qcow2_dedup_read_write_hash(BlockDriverState *bs,
                                        bool write);
 
 /*
+ * Grow the deduplication table
+ *
+ * @min_size:   minimal size
+ * @exact_size: if true force to grow to the exact size
+ * @ret:        0 on success, -errno  on error
+ */
+static int qcow2_grow_dedup_table(BlockDriverState *bs, size_t min_size,
+                                  bool exact_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    size_t table_size, table_size2;
+    int ret, i;
+    uint64_t *new_dedup_table;
+    int64_t table_offset;
+
+    if (min_size <= s->dedup_table_size) {
+        return 0;
+    }
+
+    if (exact_size) {
+        table_size = min_size;
+    } else {
+        /* Bump size up to reduce the number of times we have to grow */
+        table_size = s->dedup_table_size;
+        if (table_size == 0) {
+            table_size = 1;
+        }
+        while (min_size > table_size) {
+            table_size = (table_size * 3 + 1) / 2;
+        }
+    }
+
+#ifdef DEBUG_ALLOC2
+    fprintf(stderr, "grow dedup_table from %d to %d\n", s->dedup_table_size,
+            table_size);
+#endif
+
+    table_size2 = sizeof(uint64_t) * table_size;
+    new_dedup_table = g_malloc0(align_offset(table_size2, 512));
+    memcpy(new_dedup_table, s->dedup_table,
+           s->dedup_table_size * sizeof(uint64_t));
+
+    /* write new table (align to cluster) */
+    BLKDBG_EVENT(bs->file, BLKDBG_DEDUP_GROW_ALLOC_TABLE);
+    table_offset = qcow2_alloc_clusters(bs, table_size2);
+    if (table_offset < 0) {
+        g_free(new_dedup_table);
+        return table_offset;
+    }
+
+    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_DEDUP_GROW_WRITE_TABLE);
+    for (i = 0; i < s->dedup_table_size; i++) {
+        new_dedup_table[i] = cpu_to_be64(new_dedup_table[i]);
+    }
+
+    ret = bdrv_pwrite_sync(bs->file, table_offset,
+                           new_dedup_table, table_size2);
+
+    if (ret < 0) {
+        goto fail;
+    }
+
+    for (i = 0; i < s->dedup_table_size; i++) {
+        new_dedup_table[i] = be64_to_cpu(new_dedup_table[i]);
+    }
+
+    g_free(s->dedup_table);
+    qcow2_free_clusters(bs, s->dedup_table_offset,
+                        s->dedup_table_size * sizeof(uint64_t));
+
+    /* set new table */
+    s->dedup_table = new_dedup_table;
+    BLKDBG_EVENT(bs->file, BLKDBG_DEDUP_GROW_ACTIVATE_TABLE);
+    s->dedup_table_offset = table_offset;
+    s->dedup_table_size = table_size;
+    ret = qcow2_update_header(bs);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+fail:
+    g_free(new_dedup_table);
+    qcow2_free_clusters(bs, table_offset, table_size2);
+    return ret;
+}
+
+/*
  * Prepare a buffer containing everything required to compute cluster
  * sized deduplication hashes.
  * If sector_num or nb_sectors are not cluster-aligned, missing data
@@ -715,7 +809,11 @@  static int qcow2_dedup_read_write_hash(BlockDriverState *bs,
     index_in_dedup_table = cluster_number / nb_hash_in_block;
 
     if (s->dedup_table_size <= index_in_dedup_table) {
-        return -ENOSPC;
+        ret = qcow2_grow_dedup_table(bs, index_in_dedup_table + 1, false);
+    }
+
+    if (ret < 0) {
+        return ret;
     }
 
     /* if we must read and there is nothing to read return a null hash */
diff --git a/include/block/block.h b/include/block/block.h
index 0f750d7..f109452 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -445,6 +445,10 @@  typedef enum {
     BLKDBG_CLUSTER_ALLOC_BYTES,
     BLKDBG_CLUSTER_FREE,
 
+    BLKDBG_DEDUP_GROW_ALLOC_TABLE,
+    BLKDBG_DEDUP_GROW_WRITE_TABLE,
+    BLKDBG_DEDUP_GROW_ACTIVATE_TABLE,
+
     BLKDBG_EVENT_MAX,
 } BlkDebugEvent;