From: Zhu Yangyang <[email protected]>
Optimize IO performance in writethrough cache mode by immediately performing
write cache after updating the L2 entry and only flushing the portions that
have actually changed.
Signed-off-by: Zhu Yangyang <[email protected]>
---
block/qcow2-cache.c | 7 +++++++
block/qcow2-cluster.c | 15 +++++++++++++++
block/qcow2.h | 3 ++-
3 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index b5378d003d..3491cea7fb 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -463,6 +463,13 @@ void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void
*table)
c->entries[i].dirty = true;
}
+bool qcow2_cache_is_dirty(Qcow2Cache *c, void *table)
+{
+ int i = qcow2_cache_get_table_idx(c, table);
+ assert(c->entries[i].offset != 0);
+ return c->entries[i].dirty;
+}
+
void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset)
{
int i;
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index ce8c0076b3..95b0e44c6e 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1032,6 +1032,10 @@ int coroutine_fn
qcow2_alloc_cluster_link_l2(BlockDriverState *bs,
int i, j = 0, l2_index, ret;
uint64_t *old_cluster, *l2_slice;
uint64_t cluster_offset = m->alloc_offset;
+ bool part_flush = false;
+ /* I haven't figured out yet how to perceive this IO
+ * as a writethrough cache mode. */
+ bool writethrough = true;
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
assert(m->nb_clusters > 0);
@@ -1061,6 +1065,13 @@ int coroutine_fn
qcow2_alloc_cluster_link_l2(BlockDriverState *bs,
if (ret < 0) {
goto err;
}
+
+ /* If the cache is clean before qcow2_cache_entry_mark_dirty(),
+ * we can flush only the modified L2 entries..
+ */
+ if (writethrough && !qcow2_cache_is_dirty(s->l2_table_cache, l2_slice)) {
+ part_flush = true;
+ }
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
@@ -1102,6 +1113,10 @@ int coroutine_fn
qcow2_alloc_cluster_link_l2(BlockDriverState *bs,
}
+ if (part_flush) {
+ qcow2_write_l2_entry(bs, s->l2_table_cache, l2_slice, l2_index,
+ m->nb_clusters);
+ }
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
/*
diff --git a/block/qcow2.h b/block/qcow2.h
index b0ba2e1996..8fb59c4e87 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -1000,9 +1000,10 @@ qcow2_cache_create(BlockDriverState *bs, int num_tables,
unsigned table_size);
int qcow2_cache_destroy(Qcow2Cache *c);
+bool qcow2_cache_is_dirty(Qcow2Cache *c, void *table);
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
int qcow2_write_l2_entry(BlockDriverState *bs, Qcow2Cache *c, void *l2_tabel,
- int l2_index, int nb_clusters)
+ int l2_index, int nb_clusters);
int GRAPH_RDLOCK qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
int GRAPH_RDLOCK qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
int GRAPH_RDLOCK qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache
*c,