diff options
author | Max Reitz <mreitz@redhat.com> | 2019-06-12 18:14:13 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2020-09-07 12:31:31 +0200 |
commit | 081e465026769a24b86ba2e6a77709cfea33f16a (patch) | |
tree | 7fcf59220af674ee450618289de6cb8e609061d9 | |
parent | f706a92f249b573c624fa5a8067fa1c6636a6ae0 (diff) | |
download | qemu-081e465026769a24b86ba2e6a77709cfea33f16a.zip qemu-081e465026769a24b86ba2e6a77709cfea33f16a.tar.gz qemu-081e465026769a24b86ba2e6a77709cfea33f16a.tar.bz2 |
block: Improve get_allocated_file_size's default
There are two practical problems with bdrv_get_allocated_file_size()'s
default right now:
(1) For drivers with children, we should generally sum all their sizes
instead of just passing the request through to bs->file. The latter
is good for filters, but not so much for format drivers.
(2) Filters need not have bs->file, so we should actually go to the
filtered child instead of hard-coding bs->file.
Fix this by splitting the default implementation into three branches:
(1) For filter drivers: Return the size of the filtered child
(2) For protocol drivers: Return -ENOTSUP, because the default
implementation cannot make a guess
(3) For other drivers: Sum all data-bearing children's sizes
Signed-off-by: Max Reitz <mreitz@redhat.com>
-rw-r--r-- | block.c | 42 |
1 files changed, 39 insertions, 3 deletions
@@ -5006,6 +5006,31 @@ exit: } /** + * Implementation of BlockDriver.bdrv_get_allocated_file_size() that + * sums the size of all data-bearing children. (This excludes backing + * children.) + */ +static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) +{ + BdrvChild *child; + int64_t child_size, sum = 0; + + QLIST_FOREACH(child, &bs->children, next) { + if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | + BDRV_CHILD_FILTERED)) + { + child_size = bdrv_get_allocated_file_size(child->bs); + if (child_size < 0) { + return child_size; + } + sum += child_size; + } + } + + return sum; +} + +/** * Length of a allocated file in bytes. Sparse files are counted by actual * allocated space. Return < 0 if error or unknown. */ @@ -5018,10 +5043,21 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) if (drv->bdrv_get_allocated_file_size) { return drv->bdrv_get_allocated_file_size(bs); } - if (bs->file) { - return bdrv_get_allocated_file_size(bs->file->bs); + + if (drv->bdrv_file_open) { + /* + * Protocol drivers default to -ENOTSUP (most of their data is + * not stored in any of their children (if they even have any), + * so there is no generic way to figure it out). + */ + return -ENOTSUP; + } else if (drv->is_filter) { + /* Filter drivers default to the size of their filtered child */ + return bdrv_get_allocated_file_size(bdrv_filter_bs(bs)); + } else { + /* Other drivers default to summing their children's sizes */ + return bdrv_sum_allocated_file_size(bs); } - return -ENOTSUP; } /* |