All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>, qemu-block@nongnu.org
Cc: jsnow@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com
Subject: Re: [Qemu-devel] [PATCH 1/5] qcow2: Work with bytes in qcow2_get_cluster_offset()
Date: Fri, 3 Jun 2016 11:44:39 -0600	[thread overview]
Message-ID: <5751C207.6000709@redhat.com> (raw)
In-Reply-To: <1464974478-23598-2-git-send-email-kwolf@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 4334 bytes --]

On 06/03/2016 11:21 AM, Kevin Wolf wrote:
> This patch changes the units that qcow2_get_cluster_offset() uses
> internally, without touching the interface just yet. This will be done
> in another patch.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2-cluster.c | 43 ++++++++++++++++++++++---------------------
>  1 file changed, 22 insertions(+), 21 deletions(-)
> 
> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
> index d901d89..b2405b1 100644
> --- a/block/qcow2-cluster.c
> +++ b/block/qcow2-cluster.c
> @@ -482,29 +482,27 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
>      unsigned int l2_index;
>      uint64_t l1_index, l2_offset, *l2_table;
>      int l1_bits, c;
> -    unsigned int index_in_cluster, nb_clusters;
> -    uint64_t nb_available, nb_needed;
> +    unsigned int offset_in_cluster, nb_clusters;
> +    uint64_t bytes_available, bytes_needed;
>      int ret;
> +    unsigned int bytes;
>  
> -    index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
> -    nb_needed = *num + index_in_cluster;
> +    bytes = *num * BDRV_SECTOR_SIZE;

bytes can overflow if num > BDRV_REQUEST_MAX_SECTORS.  Is that ever a
problem? Would an assert() help, or else clamping it (since it is really
just a hint of how far we are allowed to look for similar clusters, but
we can always quit looking early):

bytes = MIN(*num * BDRV_SECTOR_SIZE, UINT32_MAX);

Then again, the interface is about to change, so this may just be a
transient problem.

>  
> -    l1_bits = s->l2_bits + s->cluster_bits;
> -
> -    /* compute how many bytes there are between the offset and
> -     * the end of the l1 entry
> -     */
> +    offset_in_cluster = offset_into_cluster(s, offset);
> +    bytes_needed = bytes + offset_in_cluster;

Hmm, my idea for clamped bytes above may need tweaking (that is,
UINT32_MAX is inappropriate as the clamp value, if you are going to
round it up here).  Or, since bytes_needed is 64-bits, make either bytes
or offset_in_cluster also be 64 bits, or start with '0ULL +', to avoid
overflow.

>  
> -    nb_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1));
> -
> -    /* compute the number of available sectors */
> +    l1_bits = s->l2_bits + s->cluster_bits;
>  
> -    nb_available = (nb_available >> 9) + index_in_cluster;
> +    /* compute how many bytes there are between the start of the cluster
> +     * containing offset and the end of the l1 entry */
> +    bytes_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1))
> +                    + offset_in_cluster;
>  
> -    if (nb_needed > nb_available) {
> -        nb_needed = nb_available;
> +    if (bytes_needed > bytes_available) {
> +        bytes_needed = bytes_available;
>      }
> -    assert(nb_needed <= INT_MAX);
> +    assert(bytes_needed <= INT_MAX);

Is this assertion too late given the spots I pointed out above as
possible overflow points?

>  
>      *cluster_offset = 0;
>  
> @@ -542,7 +540,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
>      *cluster_offset = be64_to_cpu(l2_table[l2_index]);
>  
>      /* nb_needed <= INT_MAX, thus nb_clusters <= INT_MAX, too */
> -    nb_clusters = size_to_clusters(s, nb_needed << 9);
> +    nb_clusters = size_to_clusters(s, bytes_needed);
>  
>      ret = qcow2_get_cluster_type(*cluster_offset);
>      switch (ret) {
> @@ -589,13 +587,16 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
>  
>      qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
>  
> -    nb_available = (c * s->cluster_sectors);
> +    bytes_available = (c * s->cluster_size);
>  
>  out:
> -    if (nb_available > nb_needed)
> -        nb_available = nb_needed;
> +    if (bytes_available > bytes_needed) {
> +        bytes_available = bytes_needed;
> +    }
>  
> -    *num = nb_available - index_in_cluster;
> +    bytes = bytes_available - offset_in_cluster;
> +    assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
> +    *num = bytes >> BDRV_SECTOR_BITS;
>  
>      return ret;

Looks like it is headed in the right direction, though.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

  reply	other threads:[~2016-06-03 17:44 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-03 17:21 [Qemu-devel] [PATCH 0/5] qcow2: Implement .bdrv_co_preadv/pwritev Kevin Wolf
2016-06-03 17:21 ` [Qemu-devel] [PATCH 1/5] qcow2: Work with bytes in qcow2_get_cluster_offset() Kevin Wolf
2016-06-03 17:44   ` Eric Blake [this message]
2016-06-03 17:21 ` [Qemu-devel] [PATCH 2/5] qcow2: Implement .bdrv_co_preadv() Kevin Wolf
2016-06-03 19:18   ` Eric Blake
2016-06-03 17:21 ` [Qemu-devel] [PATCH 3/5] qcow2: Make copy_sectors() byte based Kevin Wolf
2016-06-03 19:34   ` Eric Blake
2016-06-03 17:21 ` [Qemu-devel] [PATCH 4/5] qcow2: Use bytes instead of sectors for QCowL2Meta Kevin Wolf
2016-06-03 19:44   ` Eric Blake
2016-06-03 17:21 ` [Qemu-devel] [PATCH 5/5] qcow2: Implement .bdrv_co_pwritev Kevin Wolf
2016-06-03 20:13   ` Eric Blake
2016-06-06 14:50     ` Kevin Wolf
2016-06-03 22:59   ` Eric Blake

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=5751C207.6000709@redhat.com \
    --to=eblake@redhat.com \
    --cc=jsnow@redhat.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 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.