All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.