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, -- 2.33.0
