* [PATCH v8 01/11] parallels: Out of image offset in BAT leads to image inflation
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 02/11] parallels: Fix high_off calculation in parallels_co_check() Alexander Ivanov
` (9 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
data_end field in BDRVParallelsState is set to the biggest offset present
in BAT. If this offset is outside of the image, any further write
will create the cluster at this offset and/or the image will be truncated
to this offset on close. This is definitely not correct.
Raise an error in parallels_open() if data_end points outside the image
and it is not a check (let the check to repaire the image).
Set data_end to the end of the cluster with the last correct offset.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/block/parallels.c b/block/parallels.c
index bbea2f2221..4af68adc61 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -732,6 +732,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
BDRVParallelsState *s = bs->opaque;
ParallelsHeader ph;
int ret, size, i;
+ int64_t file_size;
QemuOpts *opts = NULL;
Error *local_err = NULL;
char *buf;
@@ -741,6 +742,12 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
+ file_size = bdrv_getlength(bs->file->bs);
+ if (file_size < 0) {
+ return -EINVAL;
+ }
+ file_size >>= BDRV_SECTOR_BITS;
+
ret = bdrv_pread(bs->file, 0, sizeof(ph), &ph, 0);
if (ret < 0) {
goto fail;
@@ -805,6 +812,16 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
for (i = 0; i < s->bat_size; i++) {
int64_t off = bat2sect(s, i);
+ if (off >= file_size) {
+ if (flags & BDRV_O_CHECK) {
+ continue;
+ }
+ error_setg(errp, "parallels: Offset %" PRIi64 " in BAT[%d] entry "
+ "is larger than file size (%" PRIi64 ")",
+ off, i, file_size);
+ ret = -EINVAL;
+ goto fail;
+ }
if (off >= s->data_end) {
s->data_end = off + s->tracks;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 02/11] parallels: Fix high_off calculation in parallels_co_check()
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 01/11] parallels: Out of image offset in BAT leads to image inflation Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 03/11] parallels: Fix data_end after out-of-image check Alexander Ivanov
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
Don't let high_off be more than the file size
even if we don't fix the image.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 4af68adc61..436b36bbd9 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -460,12 +460,12 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
res->corruptions++;
if (fix & BDRV_FIX_ERRORS) {
- prev_off = 0;
s->bat_bitmap[i] = 0;
res->corruptions_fixed++;
flush_bat = true;
- continue;
}
+ prev_off = 0;
+ continue;
}
res->bfi.allocated_clusters++;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 03/11] parallels: Fix data_end after out-of-image check
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 01/11] parallels: Out of image offset in BAT leads to image inflation Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 02/11] parallels: Fix high_off calculation in parallels_co_check() Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 04/11] parallels: create parallels_set_bat_entry_helper() to assign BAT value Alexander Ivanov
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
Set data_end to the end of the last cluster inside the image.
In such a way we can be sure that corrupted offsets in the BAT
can't affect on the image size.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block/parallels.c b/block/parallels.c
index 436b36bbd9..9fe0f33ba9 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -514,6 +514,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
}
}
+ s->data_end = res->image_end_offset >> BDRV_SECTOR_BITS;
+
out:
qemu_co_mutex_unlock(&s->lock);
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 04/11] parallels: create parallels_set_bat_entry_helper() to assign BAT value
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (2 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 03/11] parallels: Fix data_end after out-of-image check Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 05/11] parallels: Use generic infrastructure for BAT writing in parallels_co_check() Alexander Ivanov
` (6 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
This helper will be reused in next patches during parallels_co_check
rework to simplify its code.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
block/parallels.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 9fe0f33ba9..2144ecff7d 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -165,6 +165,13 @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
return start_off;
}
+static void parallels_set_bat_entry(BDRVParallelsState *s,
+ uint32_t index, uint32_t offset)
+{
+ s->bat_bitmap[index] = cpu_to_le32(offset);
+ bitmap_set(s->bat_dirty_bmap, bat_entry_off(index) / s->bat_dirty_block, 1);
+}
+
static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors, int *pnum)
@@ -251,10 +258,8 @@ static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs,
}
for (i = 0; i < to_allocate; i++) {
- s->bat_bitmap[idx + i] = cpu_to_le32(s->data_end / s->off_multiplier);
+ parallels_set_bat_entry(s, idx + i, s->data_end / s->off_multiplier);
s->data_end += s->tracks;
- bitmap_set(s->bat_dirty_bmap,
- bat_entry_off(idx + i) / s->bat_dirty_block, 1);
}
return bat2sect(s, idx) + sector_num % s->tracks;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 05/11] parallels: Use generic infrastructure for BAT writing in parallels_co_check()
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (3 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 04/11] parallels: create parallels_set_bat_entry_helper() to assign BAT value Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 06/11] parallels: Move check of unclean image to a separate function Alexander Ivanov
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
BAT is written in the context of conventional operations over
the image inside bdrv_co_flush() when it calls
parallels_co_flush_to_os() callback. Thus we should not
modify BAT array directly, but call parallels_set_bat_entry()
helper and bdrv_co_flush() further on. After that there is no
need to manually write BAT and track its modification.
This makes code more generic and allows to split
parallels_set_bat_entry() for independent pieces.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 2144ecff7d..3ca4ec469b 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -425,9 +425,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
{
BDRVParallelsState *s = bs->opaque;
int64_t size, prev_off, high_off;
- int ret;
+ int ret = 0;
uint32_t i;
- bool flush_bat = false;
size = bdrv_getlength(bs->file->bs);
if (size < 0) {
@@ -465,9 +464,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
res->corruptions++;
if (fix & BDRV_FIX_ERRORS) {
- s->bat_bitmap[i] = 0;
+ parallels_set_bat_entry(s, i, 0);
res->corruptions_fixed++;
- flush_bat = true;
}
prev_off = 0;
continue;
@@ -484,15 +482,6 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
prev_off = off;
}
- ret = 0;
- if (flush_bat) {
- ret = bdrv_co_pwrite_sync(bs->file, 0, s->header_size, s->header, 0);
- if (ret < 0) {
- res->check_errors++;
- goto out;
- }
- }
-
res->image_end_offset = high_off + s->cluster_size;
if (size > res->image_end_offset) {
int64_t count;
@@ -523,6 +512,14 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
out:
qemu_co_mutex_unlock(&s->lock);
+
+ if (ret == 0) {
+ ret = bdrv_co_flush(bs);
+ if (ret < 0) {
+ res->check_errors++;
+ }
+ }
+
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 06/11] parallels: Move check of unclean image to a separate function
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (4 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 05/11] parallels: Use generic infrastructure for BAT writing in parallels_co_check() Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 07/11] parallels: Move check of cluster outside " Alexander Ivanov
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
We will add more and more checks so we need a better code structure
in parallels_co_check. Let each check performs in a separate loop
in a separate helper.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
block/parallels.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 3ca4ec469b..d48b447cca 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -418,6 +418,25 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
return ret;
}
+static void parallels_check_unclean(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
+{
+ BDRVParallelsState *s = bs->opaque;
+
+ if (!s->header_unclean) {
+ return;
+ }
+
+ fprintf(stderr, "%s image was not closed correctly\n",
+ fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
+ res->corruptions++;
+ if (fix & BDRV_FIX_ERRORS) {
+ /* parallels_close will do the job right */
+ res->corruptions_fixed++;
+ s->header_unclean = false;
+ }
+}
static int coroutine_fn parallels_co_check(BlockDriverState *bs,
BdrvCheckResult *res,
@@ -435,16 +454,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
}
qemu_co_mutex_lock(&s->lock);
- if (s->header_unclean) {
- fprintf(stderr, "%s image was not closed correctly\n",
- fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
- res->corruptions++;
- if (fix & BDRV_FIX_ERRORS) {
- /* parallels_close will do the job right */
- res->corruptions_fixed++;
- s->header_unclean = false;
- }
- }
+
+ parallels_check_unclean(bs, res, fix);
res->bfi.total_clusters = s->bat_size;
res->bfi.compressed_clusters = 0; /* compression is not supported */
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 07/11] parallels: Move check of cluster outside image to a separate function
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (5 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 06/11] parallels: Move check of unclean image to a separate function Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-18 14:45 ` Hanna Czenczek
2023-01-15 15:58 ` [PATCH v8 08/11] parallels: Move check of leaks " Alexander Ivanov
` (3 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
We will add more and more checks so we need a better code structure
in parallels_co_check. Let each check performs in a separate loop
in a separate helper.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 59 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 43 insertions(+), 16 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index d48b447cca..3d06623355 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -438,13 +438,50 @@ static void parallels_check_unclean(BlockDriverState *bs,
}
}
+static int parallels_check_outside_image(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
+{
+ BDRVParallelsState *s = bs->opaque;
+ uint32_t i;
+ int64_t off, high_off, size;
+
+ size = bdrv_getlength(bs->file->bs);
+ if (size < 0) {
+ res->check_errors++;
+ return size;
+ }
+
+ high_off = 0;
+ for (i = 0; i < s->bat_size; i++) {
+ off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+ if (off > size) {
+ fprintf(stderr, "%s cluster %u is outside image\n",
+ fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
+ res->corruptions++;
+ if (fix & BDRV_FIX_ERRORS) {
+ parallels_set_bat_entry(s, i, 0);
+ res->corruptions_fixed++;
+ }
+ continue;
+ }
+ if (high_off < off) {
+ high_off = off;
+ }
+ }
+
+ s->data_end = (high_off + s->cluster_size) >> BDRV_SECTOR_BITS;
+
+ return 0;
+}
+
static int coroutine_fn parallels_co_check(BlockDriverState *bs,
BdrvCheckResult *res,
BdrvCheckMode fix)
{
BDRVParallelsState *s = bs->opaque;
int64_t size, prev_off, high_off;
- int ret = 0;
+ int ret;
uint32_t i;
size = bdrv_getlength(bs->file->bs);
@@ -457,6 +494,11 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
parallels_check_unclean(bs, res, fix);
+ ret = parallels_check_outside_image(bs, res, fix);
+ if (ret < 0) {
+ goto out;
+ }
+
res->bfi.total_clusters = s->bat_size;
res->bfi.compressed_clusters = 0; /* compression is not supported */
@@ -469,19 +511,6 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
continue;
}
- /* cluster outside the image */
- if (off > size) {
- fprintf(stderr, "%s cluster %u is outside image\n",
- fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
- res->corruptions++;
- if (fix & BDRV_FIX_ERRORS) {
- parallels_set_bat_entry(s, i, 0);
- res->corruptions_fixed++;
- }
- prev_off = 0;
- continue;
- }
-
res->bfi.allocated_clusters++;
if (off > high_off) {
high_off = off;
@@ -519,8 +548,6 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
}
}
- s->data_end = res->image_end_offset >> BDRV_SECTOR_BITS;
-
out:
qemu_co_mutex_unlock(&s->lock);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v8 07/11] parallels: Move check of cluster outside image to a separate function
2023-01-15 15:58 ` [PATCH v8 07/11] parallels: Move check of cluster outside " Alexander Ivanov
@ 2023-01-18 14:45 ` Hanna Czenczek
2023-01-20 10:30 ` Alexander Ivanov
0 siblings, 1 reply; 17+ messages in thread
From: Hanna Czenczek @ 2023-01-18 14:45 UTC (permalink / raw)
To: Alexander Ivanov, qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf
On 15.01.23 16:58, Alexander Ivanov wrote:
> We will add more and more checks so we need a better code structure
> in parallels_co_check. Let each check performs in a separate loop
> in a separate helper.
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> Reviewed-by: Denis V. Lunev <den@openvz.org>
> ---
> block/parallels.c | 59 ++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 43 insertions(+), 16 deletions(-)
>
> diff --git a/block/parallels.c b/block/parallels.c
> index d48b447cca..3d06623355 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
[...]
> @@ -469,19 +511,6 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
> continue;
> }
>
> - /* cluster outside the image */
> - if (off > size) {
> - fprintf(stderr, "%s cluster %u is outside image\n",
> - fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
> - res->corruptions++;
> - if (fix & BDRV_FIX_ERRORS) {
> - parallels_set_bat_entry(s, i, 0);
> - res->corruptions_fixed++;
> - }
> - prev_off = 0;
> - continue;
> - }
> -
> res->bfi.allocated_clusters++;
> if (off > high_off) {
> high_off = off;
parallels_co_check() keeps the `high_off` variable, and now it is also
bumped for clusters that are outside the image. This seems to go
against patch 2’s intentions.
Consider an image whose file length is larger than all of its clusters
need (i.e. there’s leaked space), except for one cluster, which is
beyond the EOF. This one cluster is considered an error (because it’s
outside the image). Before this patch, we would have truncated the
image’s file length to match all the other non-error clusters (and drop
the leaked space). With this patch, the error cluster, if it wasn’t
fixed by parallels_check_outside_image(), the image’s file length is no
longer truncated. Basically, this seems to restore the behavior from
before patch 2.
Was this intentional?
Hanna
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v8 07/11] parallels: Move check of cluster outside image to a separate function
2023-01-18 14:45 ` Hanna Czenczek
@ 2023-01-20 10:30 ` Alexander Ivanov
0 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-20 10:30 UTC (permalink / raw)
To: Hanna Czenczek, qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf
On 18.01.2023 15:45, Hanna Czenczek wrote:
> On 15.01.23 16:58, Alexander Ivanov wrote:
>> We will add more and more checks so we need a better code structure
>> in parallels_co_check. Let each check performs in a separate loop
>> in a separate helper.
>>
>> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
>> Reviewed-by: Denis V. Lunev <den@openvz.org>
>> ---
>> block/parallels.c | 59 ++++++++++++++++++++++++++++++++++-------------
>> 1 file changed, 43 insertions(+), 16 deletions(-)
>>
>> diff --git a/block/parallels.c b/block/parallels.c
>> index d48b447cca..3d06623355 100644
>> --- a/block/parallels.c
>> +++ b/block/parallels.c
>
> [...]
>
>> @@ -469,19 +511,6 @@ static int coroutine_fn
>> parallels_co_check(BlockDriverState *bs,
>> continue;
>> }
>> - /* cluster outside the image */
>> - if (off > size) {
>> - fprintf(stderr, "%s cluster %u is outside image\n",
>> - fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
>> - res->corruptions++;
>> - if (fix & BDRV_FIX_ERRORS) {
>> - parallels_set_bat_entry(s, i, 0);
>> - res->corruptions_fixed++;
>> - }
>> - prev_off = 0;
>> - continue;
>> - }
>> -
>> res->bfi.allocated_clusters++;
>> if (off > high_off) {
>> high_off = off;
>
> parallels_co_check() keeps the `high_off` variable, and now it is also
> bumped for clusters that are outside the image. This seems to go
> against patch 2’s intentions.
>
> Consider an image whose file length is larger than all of its clusters
> need (i.e. there’s leaked space), except for one cluster, which is
> beyond the EOF. This one cluster is considered an error (because it’s
> outside the image). Before this patch, we would have truncated the
> image’s file length to match all the other non-error clusters (and
> drop the leaked space). With this patch, the error cluster, if it
> wasn’t fixed by parallels_check_outside_image(), the image’s file
> length is no longer truncated. Basically, this seems to restore the
> behavior from before patch 2.
>
> Was this intentional?
>
> Hanna
>
Good point!
I have missed the case with !BDRV_FIX_ERRORS.
Thank you!
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v8 08/11] parallels: Move check of leaks to a separate function
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (6 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 07/11] parallels: Move check of cluster outside " Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-18 14:48 ` Hanna Czenczek
2023-01-15 15:58 ` [PATCH v8 09/11] parallels: Move statistic collection " Alexander Ivanov
` (2 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
We will add more and more checks so we need a better code structure
in parallels_co_check. Let each check performs in a separate loop
in a separate helper.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 84 +++++++++++++++++++++++++++++------------------
1 file changed, 52 insertions(+), 32 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 3d06623355..5db099b1dd 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -475,14 +475,14 @@ static int parallels_check_outside_image(BlockDriverState *bs,
return 0;
}
-static int coroutine_fn parallels_co_check(BlockDriverState *bs,
- BdrvCheckResult *res,
- BdrvCheckMode fix)
+static int parallels_check_leak(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
{
BDRVParallelsState *s = bs->opaque;
- int64_t size, prev_off, high_off;
- int ret;
+ int64_t size, off, high_off, count;
uint32_t i;
+ int ret;
size = bdrv_getlength(bs->file->bs);
if (size < 0) {
@@ -490,41 +490,16 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
return size;
}
- qemu_co_mutex_lock(&s->lock);
-
- parallels_check_unclean(bs, res, fix);
-
- ret = parallels_check_outside_image(bs, res, fix);
- if (ret < 0) {
- goto out;
- }
-
- res->bfi.total_clusters = s->bat_size;
- res->bfi.compressed_clusters = 0; /* compression is not supported */
-
high_off = 0;
- prev_off = 0;
for (i = 0; i < s->bat_size; i++) {
- int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
- if (off == 0) {
- prev_off = 0;
- continue;
- }
-
- res->bfi.allocated_clusters++;
+ off = bat2sect(s, i) << BDRV_SECTOR_BITS;
if (off > high_off) {
high_off = off;
}
-
- if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
- res->bfi.fragmented_clusters++;
- }
- prev_off = off;
}
res->image_end_offset = high_off + s->cluster_size;
if (size > res->image_end_offset) {
- int64_t count;
count = DIV_ROUND_UP(size - res->image_end_offset, s->cluster_size);
fprintf(stderr, "%s space leaked at the end of the image %" PRId64 "\n",
fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR",
@@ -542,12 +517,57 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
if (ret < 0) {
error_report_err(local_err);
res->check_errors++;
- goto out;
+ return ret;
}
res->leaks_fixed += count;
}
}
+ return 0;
+}
+
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
+{
+ BDRVParallelsState *s = bs->opaque;
+ int64_t prev_off;
+ int ret;
+ uint32_t i;
+
+ qemu_co_mutex_lock(&s->lock);
+
+ parallels_check_unclean(bs, res, fix);
+
+ ret = parallels_check_outside_image(bs, res, fix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = parallels_check_leak(bs, res, fix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ res->bfi.total_clusters = s->bat_size;
+ res->bfi.compressed_clusters = 0; /* compression is not supported */
+
+ prev_off = 0;
+ for (i = 0; i < s->bat_size; i++) {
+ int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+ if (off == 0) {
+ prev_off = 0;
+ continue;
+ }
+
+ res->bfi.allocated_clusters++;
+
+ if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
+ res->bfi.fragmented_clusters++;
+ }
+ prev_off = off;
+ }
+
out:
qemu_co_mutex_unlock(&s->lock);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v8 08/11] parallels: Move check of leaks to a separate function
2023-01-15 15:58 ` [PATCH v8 08/11] parallels: Move check of leaks " Alexander Ivanov
@ 2023-01-18 14:48 ` Hanna Czenczek
0 siblings, 0 replies; 17+ messages in thread
From: Hanna Czenczek @ 2023-01-18 14:48 UTC (permalink / raw)
To: Alexander Ivanov, qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf
On 15.01.23 16:58, Alexander Ivanov wrote:
> We will add more and more checks so we need a better code structure
> in parallels_co_check. Let each check performs in a separate loop
> in a separate helper.
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> Reviewed-by: Denis V. Lunev <den@openvz.org>
> ---
> block/parallels.c | 84 +++++++++++++++++++++++++++++------------------
> 1 file changed, 52 insertions(+), 32 deletions(-)
>
> diff --git a/block/parallels.c b/block/parallels.c
> index 3d06623355..5db099b1dd 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -475,14 +475,14 @@ static int parallels_check_outside_image(BlockDriverState *bs,
> return 0;
> }
>
> -static int coroutine_fn parallels_co_check(BlockDriverState *bs,
> - BdrvCheckResult *res,
> - BdrvCheckMode fix)
> +static int parallels_check_leak(BlockDriverState *bs,
> + BdrvCheckResult *res,
> + BdrvCheckMode fix)
> {
> BDRVParallelsState *s = bs->opaque;
> - int64_t size, prev_off, high_off;
> - int ret;
> + int64_t size, off, high_off, count;
> uint32_t i;
> + int ret;
>
> size = bdrv_getlength(bs->file->bs);
> if (size < 0) {
> @@ -490,41 +490,16 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
> return size;
> }
>
> - qemu_co_mutex_lock(&s->lock);
> -
> - parallels_check_unclean(bs, res, fix);
> -
> - ret = parallels_check_outside_image(bs, res, fix);
> - if (ret < 0) {
> - goto out;
> - }
> -
> - res->bfi.total_clusters = s->bat_size;
> - res->bfi.compressed_clusters = 0; /* compression is not supported */
> -
> high_off = 0;
> - prev_off = 0;
> for (i = 0; i < s->bat_size; i++) {
> - int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
> - if (off == 0) {
> - prev_off = 0;
> - continue;
> - }
> -
> - res->bfi.allocated_clusters++;
> + off = bat2sect(s, i) << BDRV_SECTOR_BITS;
> if (off > high_off) {
> high_off = off;
> }
> -
> - if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
> - res->bfi.fragmented_clusters++;
> - }
> - prev_off = off;
> }
>
> res->image_end_offset = high_off + s->cluster_size;
Continuing the question from patch 7, why do we have separate ways to
calculate s->data_end and res->image_end_offset now? Would it be
possible to just set `res->image_end = s->data_end` and thus drop the
`for` loop from this function?
Hanna
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v8 09/11] parallels: Move statistic collection to a separate function
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (7 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 08/11] parallels: Move check of leaks " Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 10/11] parallels: Replace qemu_co_mutex_lock by WITH_QEMU_LOCK_GUARD Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 11/11] parallels: Incorrect condition in out-of-image check Alexander Ivanov
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
We will add more and more checks so we need a better code structure
in parallels_co_check. Let each check performs in a separate loop
in a separate helper.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
block/parallels.c | 53 +++++++++++++++++++++++++++--------------------
1 file changed, 31 insertions(+), 22 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 5db099b1dd..6e7f140e06 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -526,47 +526,56 @@ static int parallels_check_leak(BlockDriverState *bs,
return 0;
}
-static int coroutine_fn parallels_co_check(BlockDriverState *bs,
- BdrvCheckResult *res,
- BdrvCheckMode fix)
+static void parallels_collect_statistics(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
{
BDRVParallelsState *s = bs->opaque;
- int64_t prev_off;
- int ret;
+ int64_t off, prev_off;
uint32_t i;
- qemu_co_mutex_lock(&s->lock);
-
- parallels_check_unclean(bs, res, fix);
-
- ret = parallels_check_outside_image(bs, res, fix);
- if (ret < 0) {
- goto out;
- }
-
- ret = parallels_check_leak(bs, res, fix);
- if (ret < 0) {
- goto out;
- }
-
res->bfi.total_clusters = s->bat_size;
res->bfi.compressed_clusters = 0; /* compression is not supported */
prev_off = 0;
for (i = 0; i < s->bat_size; i++) {
- int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+ off = bat2sect(s, i) << BDRV_SECTOR_BITS;
if (off == 0) {
prev_off = 0;
continue;
}
- res->bfi.allocated_clusters++;
-
if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
res->bfi.fragmented_clusters++;
}
+
prev_off = off;
+ res->bfi.allocated_clusters++;
}
+}
+
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
+{
+ BDRVParallelsState *s = bs->opaque;
+ int ret;
+
+ qemu_co_mutex_lock(&s->lock);
+
+ parallels_check_unclean(bs, res, fix);
+
+ ret = parallels_check_outside_image(bs, res, fix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = parallels_check_leak(bs, res, fix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ parallels_collect_statistics(bs, res, fix);
out:
qemu_co_mutex_unlock(&s->lock);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 10/11] parallels: Replace qemu_co_mutex_lock by WITH_QEMU_LOCK_GUARD
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (8 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 09/11] parallels: Move statistic collection " Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-15 15:58 ` [PATCH v8 11/11] parallels: Incorrect condition in out-of-image check Alexander Ivanov
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
Replace the way we use mutex in parallels_co_check() for simplier
and less error prone code.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 33 ++++++++++++++-------------------
1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 6e7f140e06..621dbf623a 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -561,30 +561,25 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
BDRVParallelsState *s = bs->opaque;
int ret;
- qemu_co_mutex_lock(&s->lock);
+ WITH_QEMU_LOCK_GUARD(&s->lock) {
+ parallels_check_unclean(bs, res, fix);
- parallels_check_unclean(bs, res, fix);
+ ret = parallels_check_outside_image(bs, res, fix);
+ if (ret < 0) {
+ return ret;
+ }
- ret = parallels_check_outside_image(bs, res, fix);
- if (ret < 0) {
- goto out;
- }
+ ret = parallels_check_leak(bs, res, fix);
+ if (ret < 0) {
+ return ret;
+ }
- ret = parallels_check_leak(bs, res, fix);
- if (ret < 0) {
- goto out;
+ parallels_collect_statistics(bs, res, fix);
}
- parallels_collect_statistics(bs, res, fix);
-
-out:
- qemu_co_mutex_unlock(&s->lock);
-
- if (ret == 0) {
- ret = bdrv_co_flush(bs);
- if (ret < 0) {
- res->check_errors++;
- }
+ ret = bdrv_co_flush(bs);
+ if (ret < 0) {
+ res->check_errors++;
}
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v8 11/11] parallels: Incorrect condition in out-of-image check
2023-01-15 15:58 [PATCH v8 00/11] parallels: Refactor the code of images checks and fix a bug Alexander Ivanov
` (9 preceding siblings ...)
2023-01-15 15:58 ` [PATCH v8 10/11] parallels: Replace qemu_co_mutex_lock by WITH_QEMU_LOCK_GUARD Alexander Ivanov
@ 2023-01-15 15:58 ` Alexander Ivanov
2023-01-18 14:46 ` Hanna Czenczek
10 siblings, 1 reply; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-15 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf, hreitz
All the offsets in the BAT must be lower than the file size.
Fix the check condition for correct check.
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
---
block/parallels.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/parallels.c b/block/parallels.c
index 621dbf623a..eda3fb558d 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -455,7 +455,7 @@ static int parallels_check_outside_image(BlockDriverState *bs,
high_off = 0;
for (i = 0; i < s->bat_size; i++) {
off = bat2sect(s, i) << BDRV_SECTOR_BITS;
- if (off > size) {
+ if (off >= size) {
fprintf(stderr, "%s cluster %u is outside image\n",
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
res->corruptions++;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v8 11/11] parallels: Incorrect condition in out-of-image check
2023-01-15 15:58 ` [PATCH v8 11/11] parallels: Incorrect condition in out-of-image check Alexander Ivanov
@ 2023-01-18 14:46 ` Hanna Czenczek
2023-01-20 10:37 ` Alexander Ivanov
0 siblings, 1 reply; 17+ messages in thread
From: Hanna Czenczek @ 2023-01-18 14:46 UTC (permalink / raw)
To: Alexander Ivanov, qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf
On 15.01.23 16:58, Alexander Ivanov wrote:
> All the offsets in the BAT must be lower than the file size.
> Fix the check condition for correct check.
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> Reviewed-by: Denis V. Lunev <den@openvz.org>
> ---
> block/parallels.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/block/parallels.c b/block/parallels.c
> index 621dbf623a..eda3fb558d 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -455,7 +455,7 @@ static int parallels_check_outside_image(BlockDriverState *bs,
> high_off = 0;
> for (i = 0; i < s->bat_size; i++) {
> off = bat2sect(s, i) << BDRV_SECTOR_BITS;
> - if (off > size) {
> + if (off >= size) {
Should this not be the even stricter `off + s->cluster_size > size`
instead, or is it possible to have partial clusters at the image end?
Hanna
> fprintf(stderr, "%s cluster %u is outside image\n",
> fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
> res->corruptions++;
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v8 11/11] parallels: Incorrect condition in out-of-image check
2023-01-18 14:46 ` Hanna Czenczek
@ 2023-01-20 10:37 ` Alexander Ivanov
0 siblings, 0 replies; 17+ messages in thread
From: Alexander Ivanov @ 2023-01-20 10:37 UTC (permalink / raw)
To: Hanna Czenczek, qemu-devel; +Cc: qemu-block, den, stefanha, vsementsov, kwolf
On 18.01.2023 15:46, Hanna Czenczek wrote:
> On 15.01.23 16:58, Alexander Ivanov wrote:
>> All the offsets in the BAT must be lower than the file size.
>> Fix the check condition for correct check.
>>
>> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
>> Reviewed-by: Denis V. Lunev <den@openvz.org>
>> ---
>> block/parallels.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/block/parallels.c b/block/parallels.c
>> index 621dbf623a..eda3fb558d 100644
>> --- a/block/parallels.c
>> +++ b/block/parallels.c
>> @@ -455,7 +455,7 @@ static int
>> parallels_check_outside_image(BlockDriverState *bs,
>> high_off = 0;
>> for (i = 0; i < s->bat_size; i++) {
>> off = bat2sect(s, i) << BDRV_SECTOR_BITS;
>> - if (off > size) {
>> + if (off >= size) {
>
> Should this not be the even stricter `off + s->cluster_size > size`
> instead, or is it possible to have partial clusters at the image end?
>
> Hanna
'off' is aligned* on the cluster size, so these conditions are
equivalent, but I agree, your condition is more idiomatic.
* It works for the new image format. In the old one there could be
entries in the BAT, pointing to unaligned clusters. There will be a
separate check for unaligned clusters.
>
>> fprintf(stderr, "%s cluster %u is outside image\n",
>> fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
>> res->corruptions++;
>
^ permalink raw reply [flat|nested] 17+ messages in thread