Since we have a used bitmap, current leak check is useless. Add parallels_check_unused_clusters() helper that checks if there are unused clusters at the end of image and truncates them (if needed). Use it for leak check and at image inactivation.
In leak check we need to recreate used bitmap because it will be used during work. At image inactivation we can skip it. Signed-off-by: Alexander Ivanov <alexander.iva...@virtuozzo.com> --- block/parallels.c | 106 +++++++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index 5155b8ac48..fd80179642 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -773,57 +773,89 @@ parallels_check_outside_image(BlockDriverState *bs, BdrvCheckResult *res, return 0; } +static int64_t GRAPH_RDLOCK +parallels_check_unused_clusters(BlockDriverState *bs, bool truncate) +{ + BDRVParallelsState *s = bs->opaque; + int64_t leak, file_size, end_off = 0; + int ret; + + file_size = bdrv_getlength(bs->file->bs); + if (file_size < 0) { + return file_size; + } + + if (s->used_bmap_size > 0) { + end_off = find_last_bit(s->used_bmap, s->used_bmap_size); + if (end_off == s->used_bmap_size) { + end_off = 0; + } else { + end_off = (end_off + 1) * s->cluster_size; + } + } + + end_off += s->data_start * BDRV_SECTOR_SIZE; + leak = file_size - end_off; + if (leak < 0) { + return -EINVAL; + } + if (!truncate || leak == 0) { + return leak; + } + + ret = bdrv_truncate(bs->file, end_off, true, PREALLOC_MODE_OFF, 0, NULL); + if (ret) { + return ret; + } + + s->data_end = end_off / BDRV_SECTOR_SIZE; + + return leak; +} + static int coroutine_fn GRAPH_RDLOCK parallels_check_leak(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix, bool explicit) { BDRVParallelsState *s = bs->opaque; - int64_t size, count; + int64_t leak, count, size; int ret; + leak = parallels_check_unused_clusters(bs, fix & BDRV_FIX_LEAKS); + if (leak < 0) { + res->check_errors++; + return leak; + } + if (leak == 0) { + return 0; + } + + parallels_free_used_bitmap(bs); + ret = parallels_fill_used_bitmap(bs); + if (ret < 0) { + res->check_errors++; + return ret; + } + size = bdrv_co_getlength(bs->file->bs); if (size < 0) { res->check_errors++; return size; } - if (size <= res->image_end_offset) { + res->image_end_offset = size; + + if (!explicit) { return 0; } - count = DIV_ROUND_UP(size - res->image_end_offset, s->cluster_size); - if (explicit) { - fprintf(stderr, - "%s space leaked at the end of the image %" PRId64 "\n", - fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR", - size - res->image_end_offset); - res->leaks += count; - } + count = DIV_ROUND_UP(leak, s->cluster_size); + fprintf(stderr, + "%s space leaked at the end of the image %" PRId64 "\n", + fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR", leak); + res->leaks += count; + if (fix & BDRV_FIX_LEAKS) { - Error *local_err = NULL; - - /* - * In order to really repair the image, we must shrink it. - * That means we have to pass exact=true. - */ - ret = bdrv_co_truncate(bs->file, res->image_end_offset, true, - PREALLOC_MODE_OFF, 0, &local_err); - if (ret < 0) { - error_report_err(local_err); - res->check_errors++; - return ret; - } - s->data_end = res->image_end_offset >> BDRV_SECTOR_BITS; - - parallels_free_used_bitmap(bs); - ret = parallels_fill_used_bitmap(bs); - if (ret == -ENOMEM) { - res->check_errors++; - return ret; - } - - if (explicit) { - res->leaks_fixed += count; - } + res->leaks_fixed += count; } return 0; @@ -1475,9 +1507,7 @@ static int GRAPH_RDLOCK parallels_inactivate(BlockDriverState *bs) s->header->inuse = 0; parallels_update_header(bs); - /* errors are ignored, so we might as well pass exact=true */ - ret = bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, - true, PREALLOC_MODE_OFF, 0, NULL); + ret = parallels_check_unused_clusters(bs, true); if (ret < 0) { error_report("Failed to truncate image: %s", strerror(-ret)); } -- 2.40.1