From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, armbru@redhat.com,
qemu-devel@nongnu.org, mreitz@redhat.com, den@openvz.org
Subject: [PATCH 3/7] block/qcow2: use compressed write cache
Date: Fri, 29 Jan 2021 19:50:26 +0300 [thread overview]
Message-ID: <20210129165030.640169-4-vsementsov@virtuozzo.com> (raw)
In-Reply-To: <20210129165030.640169-1-vsementsov@virtuozzo.com>
Introduce a new option: compressed-cache-size, with default to 64
clusters (to be not less than 64 default max-workers for backup job).
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
qapi/block-core.json | 8 +++-
block/qcow2.h | 4 ++
block/qcow2-refcount.c | 13 +++++++
block/qcow2.c | 87 ++++++++++++++++++++++++++++++++++++++++--
4 files changed, 108 insertions(+), 4 deletions(-)
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 9f555d5c1d..e0be6657f3 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3202,6 +3202,11 @@
# an image, the data file name is loaded from the image
# file. (since 4.0)
#
+# @compressed-cache-size: The maximum size of compressed write cache in
+# bytes. If positive must be not less than
+# cluster size. 0 disables the feature. Default
+# is 64 * cluster_size. (since 6.0)
+#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsQcow2',
@@ -3217,7 +3222,8 @@
'*refcount-cache-size': 'int',
'*cache-clean-interval': 'int',
'*encrypt': 'BlockdevQcow2Encryption',
- '*data-file': 'BlockdevRef' } }
+ '*data-file': 'BlockdevRef',
+ '*compressed-cache-size': 'int' } }
##
# @SshHostKeyCheckMode:
diff --git a/block/qcow2.h b/block/qcow2.h
index fbdedf89fa..b86aa06006 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -150,6 +150,7 @@
#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
#define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
#define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"
+#define QCOW2_OPT_COMPRESSED_CACHE_SIZE "compressed-cache-size"
typedef struct QCowHeader {
uint32_t magic;
@@ -422,6 +423,9 @@ typedef struct BDRVQcow2State {
* is to convert the image with the desired compression type set.
*/
Qcow2CompressionType compression_type;
+
+ uint64_t compressed_cache_size;
+ Qcow2CompressedWriteCache *compressed_cache;
} BDRVQcow2State;
typedef struct Qcow2COWRegion {
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 8e649b008e..5720591460 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -899,6 +899,11 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
qcow2_cache_discard(s->l2_table_cache, table);
}
+ if (s->compressed_cache) {
+ qcow2_compressed_cache_co_discard(s->compressed_cache,
+ cluster_offset);
+ }
+
if (s->discard_passthrough[type]) {
update_refcount_discard(bs, cluster_offset, s->cluster_size);
}
@@ -1110,6 +1115,14 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
}
if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) {
+ if (offset && s->compressed_cache) {
+ /*
+ * Previous cluster is unfinished, but we'll not write more
+ * data to it. We should inform compressed cache.
+ */
+ qcow2_compressed_cache_co_set_cluster_end(
+ s->compressed_cache, offset);
+ }
offset = new_cluster;
free_in_cluster = s->cluster_size;
} else {
diff --git a/block/qcow2.c b/block/qcow2.c
index 5d94f45be9..3997d8c143 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -808,6 +808,13 @@ static QemuOptsList qcow2_runtime_opts = {
.type = QEMU_OPT_NUMBER,
.help = "Clean unused cache entries after this time (in seconds)",
},
+ {
+ .name = QCOW2_OPT_COMPRESSED_CACHE_SIZE,
+ .type = QEMU_OPT_NUMBER,
+ .help = "The maximum size of compressed write cache in bytes. If "
+ "positive must be not less than cluster size. 0 disables "
+ "the feature. Default is 64 * cluster_size",
+ },
BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.",
"ID of secret providing qcow2 AES key or LUKS passphrase"),
{ /* end of list */ }
@@ -969,6 +976,38 @@ typedef struct Qcow2ReopenState {
QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
} Qcow2ReopenState;
+static int qcow2_update_compressed_cache_option(BlockDriverState *bs,
+ QemuOpts *opts, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t new_size;
+ int ret;
+
+ new_size = qemu_opt_get_size(opts, QCOW2_OPT_COMPRESSED_CACHE_SIZE,
+ 64 * s->cluster_size);
+ if (new_size > 0 && new_size < s->cluster_size) {
+ error_setg(errp, "compressed cache size is too small");
+ return -EINVAL;
+ }
+
+ if (s->compressed_cache && !new_size) {
+ ret = qcow2_compressed_cache_stop_flush(bs, s->compressed_cache);
+ if (ret < 0) {
+ error_report("Failed to flush the compressed write cache: %s",
+ strerror(-ret));
+ return ret;
+ }
+ qcow2_compressed_cache_free(s->compressed_cache);
+ s->compressed_cache = NULL;
+ } else if (s->compressed_cache) {
+ qcow2_compressed_cache_set_size(s->compressed_cache, new_size);
+ }
+
+ s->compressed_cache_size = new_size;
+
+ return 0;
+}
+
static int qcow2_update_options_prepare(BlockDriverState *bs,
Qcow2ReopenState *r,
QDict *options, int flags,
@@ -994,6 +1033,11 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
goto fail;
}
+ ret = qcow2_update_compressed_cache_option(bs, opts, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
/* get L2 table/refcount block cache size from command line options */
read_cache_sizes(bs, opts, &l2_cache_size, &l2_cache_entry_size,
&refcount_cache_size, &local_err);
@@ -2660,6 +2704,17 @@ static int qcow2_inactivate(BlockDriverState *bs)
bdrv_get_device_or_node_name(bs));
}
+ if (s->compressed_cache) {
+ ret = qcow2_compressed_cache_stop_flush(bs, s->compressed_cache);
+ if (ret < 0) {
+ result = ret;
+ error_report("Failed to flush the compressed write cache: %s",
+ strerror(-ret));
+ }
+ qcow2_compressed_cache_free(s->compressed_cache);
+ s->compressed_cache = NULL;
+ }
+
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret) {
result = ret;
@@ -2692,6 +2747,8 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_inactivate(bs);
}
+ assert(!s->compressed_cache);
+
cache_clean_timer_del(bs);
qcow2_cache_destroy(s->l2_table_cache);
qcow2_cache_destroy(s->refcount_block_cache);
@@ -4539,8 +4596,14 @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
goto fail;
}
- BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
- ret = bdrv_co_pwrite(s->data_file, cluster_offset, out_len, out_buf, 0);
+ if (s->compressed_cache) {
+ ret = qcow2_compressed_cache_co_write(s->compressed_cache,
+ cluster_offset, out_len, out_buf);
+ out_buf = NULL;
+ } else {
+ BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
+ ret = bdrv_co_pwrite(s->data_file, cluster_offset, out_len, out_buf, 0);
+ }
if (ret < 0) {
goto fail;
}
@@ -4601,6 +4664,12 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
return -EINVAL;
}
+ if (!s->compressed_cache && s->compressed_cache_size) {
+ s->compressed_cache =
+ qcow2_compressed_cache_new(s->data_file, s->cluster_size,
+ s->compressed_cache_size);
+ }
+
while (bytes && aio_task_pool_status(aio) == 0) {
uint64_t chunk_size = MIN(bytes, s->cluster_size);
@@ -4656,7 +4725,12 @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
out_buf = qemu_blockalign(bs, s->cluster_size);
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
- ret = bdrv_co_pread(bs->file, coffset, csize, buf, 0);
+ if (s->compressed_cache) {
+ ret = qcow2_compressed_cache_co_read(s->compressed_cache,
+ coffset, csize, buf);
+ } else {
+ ret = bdrv_co_pread(bs->file, coffset, csize, buf, 0);
+ }
if (ret < 0) {
goto fail;
}
@@ -4875,6 +4949,13 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
BDRVQcow2State *s = bs->opaque;
int ret;
+ if (s->compressed_cache) {
+ ret = qcow2_compressed_cache_flush(bs, s->compressed_cache);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
qemu_co_mutex_lock(&s->lock);
ret = qcow2_write_caches(bs);
qemu_co_mutex_unlock(&s->lock);
--
2.29.2
next prev parent reply other threads:[~2021-01-29 17:16 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-29 16:50 [PATCH 0/7] qcow2: compressed write cache Vladimir Sementsov-Ogievskiy
2021-01-29 16:50 ` [PATCH 1/7] qemu/queue: add some useful QLIST_ and QTAILQ_ macros Vladimir Sementsov-Ogievskiy
2021-02-01 8:29 ` Markus Armbruster
2021-02-01 8:34 ` Vladimir Sementsov-Ogievskiy
2021-02-10 17:07 ` Max Reitz
2021-01-29 16:50 ` [PATCH 2/7] block/qcow2: introduce cache for compressed writes Vladimir Sementsov-Ogievskiy
2021-02-10 17:07 ` Max Reitz
2021-02-11 12:49 ` Vladimir Sementsov-Ogievskiy
2021-02-18 15:04 ` Max Reitz
2021-01-29 16:50 ` Vladimir Sementsov-Ogievskiy [this message]
2021-02-10 17:11 ` [PATCH 3/7] block/qcow2: use compressed write cache Max Reitz
2021-02-11 12:53 ` Vladimir Sementsov-Ogievskiy
2021-02-18 16:02 ` Max Reitz
2021-01-29 16:50 ` [PATCH 4/7] simplebench: bench_one(): add slow_limit argument Vladimir Sementsov-Ogievskiy
2021-01-29 16:50 ` [PATCH 5/7] simplebench: bench_one(): support count=1 Vladimir Sementsov-Ogievskiy
2021-01-29 16:50 ` [PATCH 6/7] simplebench/bench-backup: add --compressed option Vladimir Sementsov-Ogievskiy
2021-01-29 16:50 ` [PATCH 7/7] simplebench/bench-backup: add target-cache argument Vladimir Sementsov-Ogievskiy
2021-01-29 17:30 ` [PATCH 0/7] qcow2: compressed write cache no-reply
2021-02-01 8:24 ` Vladimir Sementsov-Ogievskiy
2021-02-09 13:25 ` Max Reitz
2021-02-09 14:10 ` Vladimir Sementsov-Ogievskiy
2021-02-09 14:47 ` Max Reitz
2021-02-09 16:39 ` Vladimir Sementsov-Ogievskiy
2021-02-09 18:36 ` Vladimir Sementsov-Ogievskiy
2021-02-09 18:41 ` Denis V. Lunev
2021-02-09 18:51 ` Vladimir Sementsov-Ogievskiy
2021-02-10 10:00 ` Max Reitz
2021-02-10 10:10 ` Vladimir Sementsov-Ogievskiy
2021-02-09 16:52 ` Denis V. Lunev
2021-02-10 10:00 ` Max Reitz
2021-02-10 12:35 ` Kevin Wolf
2021-02-10 14:35 ` Vladimir Sementsov-Ogievskiy
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=20210129165030.640169-4-vsementsov@virtuozzo.com \
--to=vsementsov@virtuozzo.com \
--cc=armbru@redhat.com \
--cc=den@openvz.org \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).