[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH][RFC][2/2] qcow2: ref+ optimization
From: |
Frediano Ziglio |
Subject: |
[Qemu-devel] [PATCH][RFC][2/2] qcow2: ref+ optimization |
Date: |
Tue, 13 Sep 2011 09:53:08 +0200 |
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 <address@hidden>
---
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
- [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Frediano Ziglio, 2011/09/13
- [Qemu-devel] [PATCH][RFC][1/2] qcow2: optimize refminus updates, Frediano Ziglio, 2011/09/13
- [Qemu-devel] [PATCH][RFC][2/2] qcow2: ref+ optimization,
Frediano Ziglio <=
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Kevin Wolf, 2011/09/13
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Frediano Ziglio, 2011/09/13
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Kevin Wolf, 2011/09/14
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Frediano Ziglio, 2011/09/14
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Kevin Wolf, 2011/09/14
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Frediano Ziglio, 2011/09/14
- Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Frediano Ziglio, 2011/09/15
Re: [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization, Frediano Ziglio, 2011/09/13