qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: Denis Plotnikov <dplotnikov@virtuozzo.com>, qemu-devel@nongnu.org
Cc: kwolf@redhat.com, berto@igalia.com, qemu-block@nongnu.org,
	armbru@redhat.com, mreitz@redhat.com, den@openvz.org
Subject: Re: [PATCH v13 3/4] qcow2: add zstd cluster compression
Date: Tue, 31 Mar 2020 17:49:21 +0300	[thread overview]
Message-ID: <c2bab0c3-a39e-7c4c-49cc-065f366906fc@virtuozzo.com> (raw)
In-Reply-To: <20200331131743.17448-4-dplotnikov@virtuozzo.com>

31.03.2020 16:17, Denis Plotnikov wrote:
> zstd significantly reduces cluster compression time.
> It provides better compression performance maintaining
> the same level of the compression ratio in comparison with
> zlib, which, at the moment, is the only compression
> method available.
> 
> The performance test results:
> Test compresses and decompresses qemu qcow2 image with just
> installed rhel-7.6 guest.
> Image cluster size: 64K. Image on disk size: 2.2G
> 
> The test was conducted with brd disk to reduce the influence
> of disk subsystem to the test results.
> The results is given in seconds.
> 
> compress cmd:
>    time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd]
>                    src.img [zlib|zstd]_compressed.img
> decompress cmd
>    time ./qemu-img convert -O qcow2
>                    [zlib|zstd]_compressed.img uncompressed.img
> 
>             compression               decompression
>           zlib       zstd           zlib         zstd
> ------------------------------------------------------------
> real     65.5       16.3 (-75 %)    1.9          1.6 (-16 %)
> user     65.0       15.8            5.3          2.5
> sys       3.3        0.2            2.0          2.0
> 
> Both ZLIB and ZSTD gave the same compression ratio: 1.57
> compressed image size in both cases: 1.4G
> 
> Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
> QAPI part:
> Acked-by: Markus Armbruster <armbru@redhat.com>
> ---

Hi!

I have three suggestions:

1. return type of qcow2 compression functions is ssize_t, and return type of zstd is size_t. I think better is not to mix them.
2. safe check for ENOMEM in compression part - avoid overflow ( maximum of paranoia :)
3. slightly more tolerate sanity check in decompression part: allow zstd to make progress only on one of the buffers

Here is it, and if you like it, take it together with my
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
index 0b04f30bd8..208218c8f3 100644
--- a/block/qcow2-threads.c
+++ b/block/qcow2-threads.c
@@ -188,7 +188,7 @@ static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size,
  static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size,
                                     const void *src, size_t src_size)
  {
-    size_t ret;
+    ssize_t ret;
      ZSTD_outBuffer output = { dest, dest_size, 0 };
      ZSTD_inBuffer input = { src, src_size, 0 };
      ZSTD_CCtx *cctx;
@@ -214,13 +214,14 @@ static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size,
           * We want to use zstd streamed interface on decompression,
           * as we won't know the exact size of the compressed data.
           */
-        ret = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
-        if (ZSTD_isError(ret)) {
+        size_t zstd_ret = ZSTD_compressStream2(cctx, &output, &input,
+                                               ZSTD_e_end);
+        if (ZSTD_isError(zstd_ret)) {
              ret = -EIO;
              goto out;
          }
          /* Dest buffer isn't big enough to store compressed content */
-        if (output.pos + ret > output.size) {
+        if (zstd_ret > output.size - output.pos) {
              ret = -ENOMEM;
              goto out;
          }
@@ -248,7 +249,8 @@ out:
  static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
                                       const void *src, size_t src_size)
  {
-    size_t ret = 0;
+    ssize_t ret = 0;
+    size_t zstd_ret = 0;
      ZSTD_outBuffer output = { dest, dest_size, 0 };
      ZSTD_inBuffer input = { src, src_size, 0 };
      ZSTD_DCtx *dctx = ZSTD_createDCtx();
@@ -269,8 +271,9 @@ static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
       * ZSTD_decompressStream reads another ONE full frame.
       */
      while (output.pos < output.size) {
-        size_t last_input_pos = input.pos;
-        ret = ZSTD_decompressStream(dctx, &output, &input);
+        size_t last_progress = input.pos + output.pos;
+
+        zstd_ret = ZSTD_decompressStream(dctx, &output, &input);
          /*
           * zstd manual doesn't explicitly states what happens,
           * if the read the frame partially. But, based on the
@@ -278,7 +281,7 @@ static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
           * and have read all the frames from the input,
           * we end up with error here.
           */
-        if (ZSTD_isError(ret)) {
+        if (ZSTD_isError(zstd_ret)) {
              ret = -EIO;
              break;
          }
@@ -286,7 +289,7 @@ static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
          /*
           * Sanity check that each time we do some progress
           */
-        if (last_input_pos >= input.pos) {
+        if (last_progress >= input.pos + output.pos) {
              ret = -EIO;
              break;
          }
@@ -297,7 +300,7 @@ static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
       * if not, we somehow managed to get uncompressed cluster
       * greater then the cluster size.
       */
-    if (ret > 0) {
+    if (zstd_ret > 0) {
          ret = -EIO;
      }



-- 
Best regards,
Vladimir


  reply	other threads:[~2020-03-31 14:51 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-31 13:17 [PATCH v13 0/4] qcow2: Implement zstd cluster compression method Denis Plotnikov
2020-03-31 13:17 ` [PATCH v13 1/4] qcow2: introduce compression type feature Denis Plotnikov
2020-03-31 13:17 ` [PATCH v13 2/4] qcow2: rework the cluster compression routine Denis Plotnikov
2020-03-31 13:17 ` [PATCH v13 3/4] qcow2: add zstd cluster compression Denis Plotnikov
2020-03-31 14:49   ` Vladimir Sementsov-Ogievskiy [this message]
2020-03-31 15:16     ` Denis Plotnikov
2020-03-31 13:17 ` [PATCH v13 4/4] iotests: 287: add qcow2 compression type test Denis Plotnikov

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=c2bab0c3-a39e-7c4c-49cc-065f366906fc@virtuozzo.com \
    --to=vsementsov@virtuozzo.com \
    --cc=armbru@redhat.com \
    --cc=berto@igalia.com \
    --cc=den@openvz.org \
    --cc=dplotnikov@virtuozzo.com \
    --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).