From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:36749) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UGVy2-0000Ea-2w for qemu-devel@nongnu.org; Fri, 15 Mar 2013 10:50:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UGVxu-0004pH-LG for qemu-devel@nongnu.org; Fri, 15 Mar 2013 10:50:46 -0400 Received: from nodalink.pck.nerim.net ([62.212.105.220]:59599 helo=paradis.irqsave.net) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UGVxu-0004p5-39 for qemu-devel@nongnu.org; Fri, 15 Mar 2013 10:50:38 -0400 From: =?UTF-8?q?Beno=C3=AEt=20Canet?= Date: Fri, 15 Mar 2013 15:49:25 +0100 Message-Id: <1363358986-8360-12-git-send-email-benoit@irqsave.net> In-Reply-To: <1363358986-8360-1-git-send-email-benoit@irqsave.net> References: <1363358986-8360-1-git-send-email-benoit@irqsave.net> Subject: [Qemu-devel] [RFC V7 11/32] qcow2: Add qcow2_dedup_grow_table and use it. List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kwolf@redhat.com, =?UTF-8?q?Beno=C3=AEt=20Canet?= , stefanha@redhat.com Signed-off-by: Benoit Canet --- block/qcow2-dedup.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++- include/block/block.h | 4 ++ 2 files changed, 103 insertions(+), 1 deletion(-) 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; -- 1.7.10.4