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][1/2] qcow2: optimize refminus updates
Date: Tue, 13 Sep 2011 09:53:07 +0200	[thread overview]
Message-ID: <1315900388-6448-2-git-send-email-freddy77@gmail.com> (raw)
In-Reply-To: <1315900388-6448-1-git-send-email-freddy77@gmail.com>

Cache refcount decrement in an array to trade-off between
leaks and speed.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
---
 block/qcow2-refcount.c |  142 ++++++++++++++++++++++++++++++++++++++++++++++--
 block/qcow2.c          |    1 +
 block/qcow2.h          |   14 +++++
 3 files changed, 153 insertions(+), 4 deletions(-)

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 9605367..7d59b68 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -40,6 +40,13 @@ int qcow2_refcount_init(BlockDriverState *bs)
     BDRVQcowState *s = bs->opaque;
     int ret, refcount_table_size2, i;
 
+    s->refm_cache_index = 0;
+    s->refm_cache_len = 1024;
+    s->refm_cache = g_malloc(s->refm_cache_len * sizeof(uint64));
+    if (!s->refm_cache) {
+        goto fail;
+    }
+
     refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
     s->refcount_table = g_malloc(refcount_table_size2);
     if (s->refcount_table_size > 0) {
@@ -53,12 +60,14 @@ int qcow2_refcount_init(BlockDriverState *bs)
     }
     return 0;
  fail:
+    g_free(s->refm_cache);
     return -ENOMEM;
 }
 
 void qcow2_refcount_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
+    g_free(s->refm_cache);
     g_free(s->refcount_table);
 }
 
@@ -634,13 +643,21 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
 void qcow2_free_clusters(BlockDriverState *bs,
                           int64_t offset, int64_t size)
 {
+    BDRVQcowState *s = bs->opaque;
     int ret;
+    int64_t start, last;
 
     BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_FREE);
-    ret = update_refcount(bs, offset, size, -1);
-    if (ret < 0) {
-        fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
-        /* TODO Remember the clusters to free them later and avoid leaking */
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1) & ~(s->cluster_size - 1);
+    for (; start <= last; start += s->cluster_size) {
+        ret = qcow2_refm_add(bs, start);
+        if (ret < 0) {
+            fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
+            /* TODO Remember the clusters to free them later
+             * and avoid leaking */
+            break;
+        }
     }
 }
 
@@ -1165,3 +1182,120 @@ fail:
     return ret;
 }
 
+int qcow2_refm_add_any(BlockDriverState *bs, int64_t offset)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    offset &= ~QCOW_OFLAG_COPIED;
+    if (s->refm_cache_index + 2 > s->refm_cache_len) {
+        int ret = qcow2_refm_flush(bs);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if ((offset & QCOW_OFLAG_COMPRESSED)) {
+        int nb_csectors = ((offset >> s->csize_shift) & s->csize_mask) + 1;
+        int64_t last;
+
+        offset = (offset & s->cluster_offset_mask) & ~511;
+        last  = offset + nb_csectors * 512 - 1;
+        if (!in_same_refcount_block(s, offset, last)) {
+            s->refm_cache[s->refm_cache_index++] = last;
+        }
+    }
+    s->refm_cache[s->refm_cache_index++] = offset;
+    return 0;
+}
+
+static int uint64_cmp(const void *a, const void *b)
+{
+#define A (*((const uint64_t *)a))
+#define B (*((const uint64_t *)b))
+    if (A == B) {
+        return 0;
+    }
+    return A > B ? 1 : -1;
+#undef A
+#undef B
+}
+
+int qcow2_refm_flush(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint16_t *refcount_block = NULL;
+    int64_t old_table_index = -1;
+    int ret, i, saved_index = 0;
+    int len = s->refm_cache_index;
+
+    /* sort cache */
+    qsort(s->refm_cache, len, sizeof(uint64_t), uint64_cmp);
+
+    /* save */
+    for (i = 0; i < len; ++i) {
+        uint64_t cluster_offset = s->refm_cache[i];
+        int block_index, refcount;
+        int64_t cluster_index = cluster_offset >> s->cluster_bits;
+        int64_t table_index =
+            cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+
+        /* Load the refcount block and allocate it if needed */
+        if (table_index != old_table_index) {
+            if (refcount_block) {
+                ret = qcow2_cache_put(bs, s->refcount_block_cache,
+                    (void **) &refcount_block);
+                if (ret < 0) {
+                    goto fail;
+                }
+                saved_index = i;
+                refcount_block = NULL;
+            }
+
+            ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
+            if (ret < 0) {
+                goto fail;
+            }
+        }
+        old_table_index = table_index;
+
+        qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
+
+        /* we can update the count and save it */
+        block_index = cluster_index &
+            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+
+        refcount = be16_to_cpu(refcount_block[block_index]);
+        refcount--;
+        if (refcount < 0) {
+            ret = -EINVAL;
+            goto fail;
+        }
+        if (refcount == 0 && cluster_index < s->free_cluster_index) {
+            s->free_cluster_index = cluster_index;
+        }
+        refcount_block[block_index] = cpu_to_be16(refcount);
+    }
+
+    saved_index = len = 0;
+    s->refm_cache_index = 0;
+    ret = 0;
+fail:
+    /* Write last changed block to disk */
+    if (refcount_block) {
+        int wret;
+        wret = qcow2_cache_put(bs, s->refcount_block_cache,
+            (void **) &refcount_block);
+        if (wret < 0) {
+            return ret < 0 ? ret : wret;
+        }
+    }
+
+    if (saved_index < len) {
+        memmove(s->refm_cache, s->refm_cache + saved_index,
+            (len - saved_index) * sizeof(uint64_t));
+        s->refm_cache_index = len - saved_index;
+    }
+
+    return ret;
+}
+
diff --git a/block/qcow2.c b/block/qcow2.c
index 510ff68..89ae765 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_refm_flush(bs);
     qcow2_cache_flush(bs, s->refcount_block_cache);
 
     qcow2_cache_destroy(bs, s->l2_table_cache);
diff --git a/block/qcow2.h b/block/qcow2.h
index 531af39..49d3d55 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -103,6 +103,8 @@ typedef struct BDRVQcowState {
 
     Qcow2Cache* l2_table_cache;
     Qcow2Cache* refcount_block_cache;
+    int refm_cache_len, refm_cache_index;
+    uint64_t *refm_cache;
 
     uint8_t *cluster_cache;
     uint8_t *cluster_data;
@@ -181,6 +183,18 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
 int qcow2_refcount_init(BlockDriverState *bs);
 void qcow2_refcount_close(BlockDriverState *bs);
 
+int qcow2_refm_add_any(BlockDriverState *bs, int64_t offset);
+int qcow2_refm_flush(BlockDriverState *bs);
+static inline int qcow2_refm_add(BlockDriverState *bs, int64_t offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    if (s->refm_cache_index < s->refm_cache_len) {
+        s->refm_cache[s->refm_cache_index++] = offset;
+        return 0;
+    }
+    return qcow2_refm_add_any(bs, offset);
+}
+
 int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
 int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
 void qcow2_free_clusters(BlockDriverState *bs,
-- 
1.7.1

  reply	other threads:[~2011-09-13  7:52 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 ` Frediano Ziglio [this message]
2011-09-13  7:53 ` [Qemu-devel] [PATCH][RFC][2/2] qcow2: ref+ optimization Frediano Ziglio
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-2-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.