From: Frediano Ziglio <freddy77@gmail.com>
To: kwolf@redhat.com
Cc: qemu-devel@nongnu.org, Frediano Ziglio <freddy77@gmail.com>
Subject: [Qemu-devel] [PATCH][RFC][2/2] qcow2: ref+ optimization
Date: Tue, 13 Sep 2011 09:53:08 +0200 [thread overview]
Message-ID: <1315900388-6448-3-git-send-email-freddy77@gmail.com> (raw)
In-Reply-To: <1315900388-6448-1-git-send-email-freddy77@gmail.com>
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 <freddy77@gmail.com>
---
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
next prev parent reply other threads:[~2011-09-13 7:53 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-13 7:53 [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization Frediano Ziglio
2011-09-13 7:53 ` [Qemu-devel] [PATCH][RFC][1/2] qcow2: optimize refminus updates Frediano Ziglio
2011-09-13 7:53 ` Frediano Ziglio [this message]
2011-09-13 10:37 ` [Qemu-devel] [PATCH][RFC][0/2] REF+/REF- optimization Kevin Wolf
2011-09-13 13:36 ` Frediano Ziglio
2011-09-14 9:10 ` Kevin Wolf
2011-09-14 9:52 ` Frediano Ziglio
2011-09-14 10:21 ` Kevin Wolf
2011-09-14 11:49 ` Frediano Ziglio
2011-09-15 7:24 ` Frediano Ziglio
2011-09-13 14:55 ` Frediano Ziglio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1315900388-6448-3-git-send-email-freddy77@gmail.com \
--to=freddy77@gmail.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).