qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-block] [PATCH] qcow2: do lazy allocation of the L2 cache


From: Alberto Garcia
Subject: [Qemu-block] [PATCH] qcow2: do lazy allocation of the L2 cache
Date: Tue, 21 Apr 2015 18:20:39 +0300

Large disk images need large L2 caches in order to maximize their
I/O performance. However setting a correct size for the cache is not
necessarily easy since apart from the image size, it also depends
on other factors like its usage patterns or whether it's part of a
backing chain.

In order to be able to set a very large cache size to cover the
worst-case scenarios and yet prevent an unnecessary waste of memory,
this patch modifies the qcow2 cache algorithm so the memory for each
entry is allocated only when it's actually needed.

This also improves the scenarios with smaller images: the current
default L2 cache size can map a whole 8GB disk, so those smaller than
that are allocating cache memory that can never be used.

Signed-off-by: Alberto Garcia <address@hidden>
---
 block/qcow2-cache.c | 35 ++++++++++++++---------------------
 block/qcow2.c       |  4 ++--
 block/qcow2.h       |  2 +-
 3 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index b115549..33f2561 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -42,37 +42,19 @@ struct Qcow2Cache {
     bool                    depends_on_flush;
 };
 
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
+Qcow2Cache *qcow2_cache_create(int num_tables)
 {
-    BDRVQcowState *s = bs->opaque;
     Qcow2Cache *c;
-    int i;
 
     c = g_new0(Qcow2Cache, 1);
     c->size = num_tables;
     c->entries = g_try_new0(Qcow2CachedTable, num_tables);
     if (!c->entries) {
-        goto fail;
-    }
-
-    for (i = 0; i < c->size; i++) {
-        c->entries[i].table = qemu_try_blockalign(bs->file, s->cluster_size);
-        if (c->entries[i].table == NULL) {
-            goto fail;
-        }
+        g_free(c);
+        c = NULL;
     }
 
     return c;
-
-fail:
-    if (c->entries) {
-        for (i = 0; i < c->size; i++) {
-            qemu_vfree(c->entries[i].table);
-        }
-    }
-    g_free(c->entries);
-    g_free(c);
-    return NULL;
 }
 
 int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
@@ -151,6 +133,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, 
Qcow2Cache *c, int i)
         BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
     }
 
+    assert(c->entries[i].table != NULL);
     ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
         s->cluster_size);
     if (ret < 0) {
@@ -227,6 +210,8 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
 
     for (i = 0; i < c->size; i++) {
         assert(c->entries[i].ref == 0);
+        qemu_vfree(c->entries[i].table);
+        c->entries[i].table = NULL;
         c->entries[i].offset = 0;
         c->entries[i].cache_hits = 0;
     }
@@ -296,6 +281,13 @@ static int qcow2_cache_do_get(BlockDriverState *bs, 
Qcow2Cache *c,
         return ret;
     }
 
+    if (!c->entries[i].table) {
+        c->entries[i].table = qemu_try_blockalign(bs->file, s->cluster_size);
+        if (!c->entries[i].table) {
+            return -ENOMEM;
+        }
+    }
+
     trace_qcow2_cache_get_read(qemu_coroutine_self(),
                                c == s->l2_table_cache, i);
     c->entries[i].offset = 0;
@@ -343,6 +335,7 @@ int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, 
void **table)
 {
     int i;
 
+    assert(*table != NULL);
     for (i = 0; i < c->size; i++) {
         if (c->entries[i].table == *table) {
             goto found;
diff --git a/block/qcow2.c b/block/qcow2.c
index 316a8db..c3fd072 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -831,8 +831,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, 
int flags,
     }
 
     /* alloc L2 table/refcount block cache */
-    s->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
-    s->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
+    s->l2_table_cache = qcow2_cache_create(l2_cache_size);
+    s->refcount_block_cache = qcow2_cache_create(refcount_cache_size);
     if (s->l2_table_cache == NULL || s->refcount_block_cache == NULL) {
         error_setg(errp, "Could not allocate metadata caches");
         ret = -ENOMEM;
diff --git a/block/qcow2.h b/block/qcow2.h
index 422b825..62e38f7 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -571,7 +571,7 @@ void qcow2_free_snapshots(BlockDriverState *bs);
 int qcow2_read_snapshots(BlockDriverState *bs);
 
 /* qcow2-cache.c functions */
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
+Qcow2Cache *qcow2_cache_create(int num_tables);
 int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
 
 void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
-- 
2.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]