On 05/05/2018 03:49 AM, Ivan Ren wrote:
> qemu-img info with a block device which has a qcow2 format always
> return 0 for disk size, and this can not reflect the qcow2 size
> and the used space of the block device. This patch return the
> allocated size of qcow2 as the disk size.
> 

This has hit over a month old; I only skimmed the comments on V1 from
Max and Eric. Is this something we still want?

--js

> Signed-off-by: Ivan Ren <ivan...@tencent.com>
> ---
>  block/qcow2.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
> 
> This version differs from the previous:
> (1).Accumulate all non-0 refcount cluster as the allocated size instead the
> highest offset.
> (2).Simplify the implementation by just check the refcount info.
> 
> diff --git a/block/qcow2.c b/block/qcow2.c
> index ef68772..e64469a 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -4493,6 +4493,59 @@ static QemuOptsList qcow2_create_opts = {
>      }
>  };
>  
> +/* Get allocated space of qcow2, aligned to cluster_size */
> +static int64_t qcow2_get_allocated_size(BlockDriverState *bs)
> +{
> +    int64_t allocated_cluster_count = 0;
> +    uint64_t refcount;
> +    int64_t i, j, begin_index, end_index;
> +
> +    BDRVQcow2State *s = bs->opaque;
> +
> +    /* Traverse refcount table */
> +    for (i = 0; i < s->refcount_table_size; i++) {
> +        if (s->refcount_table[i] & REFT_OFFSET_MASK) {
> +            begin_index = i * s->refcount_block_size;
> +            end_index = begin_index + s->refcount_block_size;
> +            for (j = begin_index; j < end_index; j++) {
> +                if (qcow2_get_refcount(bs, j, &refcount) < 0) {
> +                    continue;
> +                }
> +                if (refcount > 0) {
> +                    allocated_cluster_count++;
> +                }
> +            }
> +        }
> +
> +    }
> +
> +    return allocated_cluster_count * s->cluster_size;
> +}
> +
> +static int64_t qcow2_get_allocated_file_size(BlockDriverState *bs)
> +{
> +    int64_t ret = 0;
> +
> +    /* Get through bs->file first */
> +    if (bs->file) {
> +        ret = bdrv_get_allocated_file_size(bs->file->bs);
> +    }
> +
> +    /*
> +     * If ret < 0, some error may happen to the underlying media, return the
> +     * error directly.
> +     * If ret == 0, means length get from bs->file is 0, which is impossible
> +     * for a normal file because of the qcow2 header. In this case, the
> +     * underlying media may be a block device or anything else that can't
> +     * return a suitable size. So we get the allocated size of qcow2 instead.
> +     */
> +    if (!ret) {
> +        ret = qcow2_get_allocated_size(bs);
> +    }
> +
> +    return ret;
> +}
> +
>  BlockDriver bdrv_qcow2 = {
>      .format_name        = "qcow2",
>      .instance_size      = sizeof(BDRVQcow2State),
> @@ -4516,6 +4569,7 @@ BlockDriver bdrv_qcow2 = {
>      .bdrv_co_pwrite_zeroes  = qcow2_co_pwrite_zeroes,
>      .bdrv_co_pdiscard       = qcow2_co_pdiscard,
>      .bdrv_truncate          = qcow2_truncate,
> +    .bdrv_get_allocated_file_size = qcow2_get_allocated_file_size,
>      .bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed,
>      .bdrv_make_empty        = qcow2_make_empty,
>  
> 

Reply via email to