From: Laszlo Ersek <lersek@redhat.com>
To: Max Reitz <mreitz@redhat.com>, qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
"Benoît Canet" <benoit@irqsave.net>,
"Stefan Hajnoczi" <stefanha@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v2 2/2] qcow2: Fix fail path in realloc_refcount_block()
Date: Mon, 17 Mar 2014 23:18:49 +0100 [thread overview]
Message-ID: <532774C9.9020702@redhat.com> (raw)
In-Reply-To: <1395093892-29271-3-git-send-email-mreitz@redhat.com>
On 03/17/14 23:04, Max Reitz wrote:
> If qcow2_alloc_clusters() fails, new_offset and ret will both be
> negative after the fail label, thus passing the first if condition and
> subsequently resulting in a call of qcow2_free_clusters() with an
> invalid (negative) offset parameter. Fix this by introducing a new label
> "fail_free_cluster" which is only invoked if new_offset is indeed
> pointing to a newly allocated cluster that should be cleaned up by
> freeing it.
>
> While we're at it, clean up the whole fail path. qcow2_cache_put()
> should (and actually can) never fail, hence the return value can safely
> be ignored (aside from asserting that it indeed did not fail).
>
> Furthermore, there is no reason to give QCOW2_DISCARD_ALWAYS to
> qcow2_free_clusters(), a mere QCOW2_DISCARD_OTHER will suffice.
>
> Ultimately, rename the "fail" label to "done", as it is invoked both on
> failure and success.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> Suggested-by: Laszlo Ersek <lersek@redhat.com>
> ---
> block/qcow2-refcount.c | 34 ++++++++++++++++++----------------
> 1 file changed, 18 insertions(+), 16 deletions(-)
>
> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
> index 3f2ed08..4a2df5f 100644
> --- a/block/qcow2-refcount.c
> +++ b/block/qcow2-refcount.c
> @@ -1399,14 +1399,14 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
> fprintf(stderr, "Could not allocate new cluster: %s\n",
> strerror(-new_offset));
> ret = new_offset;
> - goto fail;
> + goto done;
> }
>
> /* fetch current refcount block content */
> ret = qcow2_cache_get(bs, s->refcount_block_cache, offset, &refcount_block);
> if (ret < 0) {
> fprintf(stderr, "Could not fetch refcount block: %s\n", strerror(-ret));
> - goto fail;
> + goto fail_free_cluster;
> }
>
> /* new block has not yet been entered into refcount table, therefore it is
> @@ -1417,8 +1417,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
> "check failed: %s\n", strerror(-ret));
> /* the image will be marked corrupt, so don't even attempt on freeing
> * the cluster */
> - new_offset = 0;
> - goto fail;
> + goto done;
> }
>
> /* write to new block */
> @@ -1426,7 +1425,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
> s->cluster_sectors);
> if (ret < 0) {
> fprintf(stderr, "Could not write refcount block: %s\n", strerror(-ret));
> - goto fail;
> + goto fail_free_cluster;
> }
>
> /* update refcount table */
> @@ -1436,24 +1435,27 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
> if (ret < 0) {
> fprintf(stderr, "Could not update refcount table: %s\n",
> strerror(-ret));
> - goto fail;
> + goto fail_free_cluster;
> }
>
> -fail:
> - if (new_offset && (ret < 0)) {
> - qcow2_free_clusters(bs, new_offset, s->cluster_size,
> - QCOW2_DISCARD_ALWAYS);
> - }
> + goto done;
> +
> +fail_free_cluster:
> + qcow2_free_clusters(bs, new_offset, s->cluster_size, QCOW2_DISCARD_OTHER);
> +
> +done:
> if (refcount_block) {
> - if (ret < 0) {
> - qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
> - } else {
> - ret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
> - }
> + /* This should never fail, as it would only do so if the given refcount
> + * block cannot be found in the cache. As this is impossible as long as
> + * there are no bugs, assert the success. */
> + int tmp = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
> + assert(tmp == 0);
> }
> +
> if (ret < 0) {
> return ret;
> }
> +
> return new_offset;
> }
>
>
I liked the other version better. Especially crossing the trajectories
of the gotos (where "new_offset" used to be zeroed) makes me want to
avert my eyes. However, I've obsessed enough; the code seems correct.
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Thanks!
Laszlo
next prev parent reply other threads:[~2014-03-17 22:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-17 22:04 [Qemu-devel] [PATCH v2 0/2] qcow2: Fix return path of realloc_refcount_block() Max Reitz
2014-03-17 22:04 ` [Qemu-devel] [PATCH v2 1/2] qcow2: Correct comment for realloc_refcount_block() Max Reitz
2014-03-17 22:19 ` Laszlo Ersek
2014-03-17 22:04 ` [Qemu-devel] [PATCH v2 2/2] qcow2: Fix fail path in realloc_refcount_block() Max Reitz
2014-03-17 22:18 ` Laszlo Ersek [this message]
2014-03-18 9:32 ` Kevin Wolf
2014-03-18 9:33 ` [Qemu-devel] [PATCH v2 0/2] qcow2: Fix return path of realloc_refcount_block() Kevin Wolf
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=532774C9.9020702@redhat.com \
--to=lersek@redhat.com \
--cc=benoit@irqsave.net \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.