From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:32815) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R3Nnp-0003Xb-K8 for qemu-devel@nongnu.org; Tue, 13 Sep 2011 03:53:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1R3Nnl-0006jm-A6 for qemu-devel@nongnu.org; Tue, 13 Sep 2011 03:53:09 -0400 Received: from mail-bw0-f45.google.com ([209.85.214.45]:34439) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R3Nnk-0006i1-Uu for qemu-devel@nongnu.org; Tue, 13 Sep 2011 03:53:05 -0400 Received: by mail-bw0-f45.google.com with SMTP id zv15so263370bkb.4 for ; Tue, 13 Sep 2011 00:53:04 -0700 (PDT) From: Frediano Ziglio Date: Tue, 13 Sep 2011 09:53:08 +0200 Message-Id: <1315900388-6448-3-git-send-email-freddy77@gmail.com> In-Reply-To: <1315900388-6448-1-git-send-email-freddy77@gmail.com> References: <1315900388-6448-1-git-send-email-freddy77@gmail.com> Subject: [Qemu-devel] [PATCH][RFC][2/2] qcow2: ref+ optimization List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: kwolf@redhat.com Cc: qemu-devel@nongnu.org, Frediano Ziglio preallocate multiple refcount increment in order to collapse allocation writes. This cause leaks in case of Qemu crash but no corruptions. Signed-off-by: Frediano Ziglio --- block/qcow2-refcount.c | 128 ++++++++++++++++++++++++++++++++++++++++++++--- block/qcow2.c | 1 + block/qcow2.h | 2 + 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 7d59b68..3792cda 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -30,6 +30,7 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size); static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, int64_t offset, int64_t length, int addend); +static void qcow2_refp_enable(BlockDriverState *bs); /*********************************************************/ @@ -117,6 +118,12 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index) ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); refcount = be16_to_cpu(refcount_block[block_index]); + /* ignore preallocation */ + if (cluster_index >= s->refp_prealloc_begin + && cluster_index < s->refp_prealloc_end) { + --refcount; + } + ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) &refcount_block); if (ret < 0) { @@ -207,6 +214,10 @@ static int alloc_refcount_block(BlockDriverState *bs, * refcount block into the cache */ + uint64_t old_free_cluster_index = s->free_cluster_index; + qcow2_refp_flush(bs); + s->free_cluster_index = old_free_cluster_index; + *refcount_block = NULL; /* We write to the refcount table, so we might depend on L2 tables */ @@ -215,6 +226,7 @@ static int alloc_refcount_block(BlockDriverState *bs, /* Allocate the refcount block itself and mark it as used */ int64_t new_block = alloc_clusters_noref(bs, s->cluster_size); if (new_block < 0) { + qcow2_refp_enable(bs); return new_block; } @@ -279,6 +291,7 @@ static int alloc_refcount_block(BlockDriverState *bs, } s->refcount_table[refcount_table_index] = new_block; + qcow2_refp_enable(bs); return 0; } @@ -400,10 +413,11 @@ static int alloc_refcount_block(BlockDriverState *bs, s->refcount_table_offset = table_offset; /* Free old table. Remember, we must not change free_cluster_index */ - uint64_t old_free_cluster_index = s->free_cluster_index; + old_free_cluster_index = s->free_cluster_index; qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); s->free_cluster_index = old_free_cluster_index; + qcow2_refp_enable(bs); ret = load_refcount_block(bs, new_block, (void**) refcount_block); if (ret < 0) { return ret; @@ -417,6 +431,7 @@ fail_block: if (*refcount_block != NULL) { qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block); } + qcow2_refp_enable(bs); return ret; } @@ -529,9 +544,23 @@ static int update_cluster_refcount(BlockDriverState *bs, BDRVQcowState *s = bs->opaque; int ret; - ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend); - if (ret < 0) { - return ret; + /* handle preallocation */ + if (cluster_index >= s->refp_prealloc_begin + && cluster_index < s->refp_prealloc_end) { + + /* free previous (should never happen) */ + int64_t index = s->refp_prealloc_begin; + for (; index < cluster_index; ++index) { + qcow2_refm_add(bs, index << s->cluster_bits); + } + addend--; + s->refp_prealloc_begin = cluster_index + 1; + } + if (addend) { + ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend); + if (ret < 0) { + return ret; + } } bdrv_flush(bs->file); @@ -572,20 +601,94 @@ retry: return (s->free_cluster_index - nb_clusters) << s->cluster_bits; } +static void qcow2_refp_enable(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + + if (s->refp_prealloc_end < 0) { + /* enable again ? */ + if (++s->refp_prealloc_end == 0) { + s->refp_prealloc_end = + s->refp_prealloc_begin; + } + } +} + +int qcow2_refp_flush(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + int64_t index, end = s->refp_prealloc_end; + + if (end < 0) { + s->refp_prealloc_end = end - 1; + return 0; + } + + index = s->refp_prealloc_begin; + /* this disable next allocations */ + s->refp_prealloc_end = -1; + for (; index < end; ++index) { + qcow2_refm_add(bs, index << s->cluster_bits); + } + qcow2_refm_flush(bs); + return 0; +} + int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size) { - int64_t offset; - int ret; + BDRVQcowState *s = bs->opaque; + int64_t offset, cluster_index; + int ret, nb_clusters; + uint32_t n_prealloc = 0; BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC); + nb_clusters = size_to_clusters(s, size); offset = alloc_clusters_noref(bs, size); if (offset < 0) { return offset; } - ret = update_refcount(bs, offset, size, 1); - if (ret < 0) { - return ret; + /* preallocation */ + cluster_index = offset >> s->cluster_bits; + if (cluster_index >= s->refp_prealloc_begin && + cluster_index < s->refp_prealloc_end) { + + /* free previous (should never happen) */ + int64_t index = s->refp_prealloc_begin; + for (; index < cluster_index; ++index) { + qcow2_refm_add(bs, index << s->cluster_bits); + } + while (cluster_index < s->refp_prealloc_end + && nb_clusters > 0) { + --nb_clusters; + ++cluster_index; + } + s->refp_prealloc_begin = cluster_index; + } + + /* try to allocate new space for preallocation */ + if (s->refp_prealloc_begin == s->refp_prealloc_end) { + s->refp_prealloc_begin = + s->refp_prealloc_end = cluster_index + nb_clusters; + while (nb_clusters < 1024 + && get_refcount(bs, s->refp_prealloc_begin + n_prealloc) == 0) { + ++nb_clusters; + ++n_prealloc; + s->refp_prealloc_end = -1; + } + } + + if (nb_clusters) { + ret = update_refcount(bs, cluster_index << s->cluster_bits, + nb_clusters << s->cluster_bits, 1); + if (ret < 0) { + return ret; + } + if (n_prealloc) { + assert(s->refp_prealloc_end == -1); + s->refp_prealloc_end = + s->refp_prealloc_begin + n_prealloc; + } } return offset; @@ -739,6 +842,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, l1_allocated = 0; } + /* disable preallocation */ + qcow2_refp_flush(bs); + for(i = 0; i < l1_size; i++) { l2_offset = l1_table[i]; if (l2_offset) { @@ -761,6 +867,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, s->csize_mask) + 1; if (addend != 0) { int ret; + /* XXX preallocation ??? */ ret = update_refcount(bs, (offset & s->cluster_offset_mask) & ~511, nb_csectors * 512, addend); @@ -836,6 +943,9 @@ fail: qcow2_cache_set_writethrough(bs, s->refcount_block_cache, old_refcount_writethrough); + /* enable preallocation again */ + qcow2_refp_enable(bs); + if (l1_modified) { for(i = 0; i < l1_size; i++) cpu_to_be64s(&l1_table[i]); diff --git a/block/qcow2.c b/block/qcow2.c index 89ae765..51014e1 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -622,6 +622,7 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->l1_table); qcow2_cache_flush(bs, s->l2_table_cache); + qcow2_refp_flush(bs); qcow2_refm_flush(bs); qcow2_cache_flush(bs, s->refcount_block_cache); diff --git a/block/qcow2.h b/block/qcow2.h index 49d3d55..98b1ab5 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -105,6 +105,7 @@ typedef struct BDRVQcowState { Qcow2Cache* refcount_block_cache; int refm_cache_len, refm_cache_index; uint64_t *refm_cache; + int64_t refp_prealloc_begin, refp_prealloc_end; uint8_t *cluster_cache; uint8_t *cluster_data; @@ -185,6 +186,7 @@ void qcow2_refcount_close(BlockDriverState *bs); int qcow2_refm_add_any(BlockDriverState *bs, int64_t offset); int qcow2_refm_flush(BlockDriverState *bs); +int qcow2_refp_flush(BlockDriverState *bs); static inline int qcow2_refm_add(BlockDriverState *bs, int64_t offset) { BDRVQcowState *s = bs->opaque; -- 1.7.1