From patchwork Fri Mar 15 14:49:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Beno=C3=AEt_Canet?= X-Patchwork-Id: 228021 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 4056D2C00B2 for ; Sat, 16 Mar 2013 01:54:45 +1100 (EST) Received: from localhost ([::1]:53093 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UGW1r-0005dJ-6g for incoming@patchwork.ozlabs.org; Fri, 15 Mar 2013 10:54:43 -0400 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 Received: by paradis.irqsave.net (Postfix, from userid 1002) id 39AEE874353; Fri, 15 Mar 2013 15:50:37 +0100 (CET) Received: from localhost.localdomain (unknown [192.168.77.1]) by paradis.irqsave.net (Postfix) with ESMTP id 81ED1874357; Fri, 15 Mar 2013 15:48:47 +0100 (CET) From: =?UTF-8?q?Beno=C3=AEt=20Canet?= To: qemu-devel@nongnu.org Date: Fri, 15 Mar 2013 15:49:25 +0100 Message-Id: <1363358986-8360-12-git-send-email-benoit@irqsave.net> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1363358986-8360-1-git-send-email-benoit@irqsave.net> References: <1363358986-8360-1-git-send-email-benoit@irqsave.net> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 62.212.105.220 Cc: kwolf@redhat.com, =?UTF-8?q?Beno=C3=AEt=20Canet?= , stefanha@redhat.com Subject: [Qemu-devel] [RFC V7 11/32] qcow2: Add qcow2_dedup_grow_table and use it. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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;