[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/3] qemu-img check: fixing duplicated clusters for parallels for
From: |
Natalia Kuzmina |
Subject: |
[PATCH 1/3] qemu-img check: fixing duplicated clusters for parallels format |
Date: |
Mon, 18 Apr 2022 14:04:28 +0300 |
Let qemu-img check fix corruption in the image file: two
guest memory areas refer to the same host memory area
(duplicated offsets in BAT).
Signed-off-by: Natalia Kuzmina <natalia.kuzmina@openvz.org>
---
block/parallels.c | 66 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/block/parallels.c b/block/parallels.c
index 6ebad2a2bb..6a73933d45 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -418,9 +418,11 @@ static int coroutine_fn
parallels_co_check(BlockDriverState *bs,
BdrvCheckMode fix)
{
BDRVParallelsState *s = bs->opaque;
- int64_t size, prev_off, high_off;
+ int64_t size, prev_off, high_off, idx_host, sector_num;
int ret;
uint32_t i;
+ int64_t *buf;
+ int *reversed_bat;
bool flush_bat = false;
size = bdrv_getlength(bs->file->bs);
@@ -442,8 +444,14 @@ static int coroutine_fn
parallels_co_check(BlockDriverState *bs,
}
res->bfi.total_clusters = s->bat_size;
+ res->bfi.allocated_clusters = 0;
res->bfi.compressed_clusters = 0; /* compression is not supported */
+ reversed_bat = g_malloc(s->bat_size * sizeof(int));
+ for (i = 0; i < s->bat_size; i++) {
+ reversed_bat[i] = -1;
+ }
+
high_off = 0;
prev_off = 0;
for (i = 0; i < s->bat_size; i++) {
@@ -453,6 +461,59 @@ static int coroutine_fn
parallels_co_check(BlockDriverState *bs,
continue;
}
+ /* checking bat entry uniqueness */
+ idx_host = (off - ((s->header->data_off) << BDRV_SECTOR_BITS))
+ / (s->cluster_size);
+ if (reversed_bat[idx_host] != -1) { /* duplicated cluster */
+ fprintf(stderr, "%s cluster %u is duplicated (with cluster %u)\n",
+ fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
+ i, reversed_bat[idx_host]);
+ res->corruptions++;
+ res->bfi.allocated_clusters--; /* not to count this cluster twice
*/
+ if (fix & BDRV_FIX_ERRORS) {
+ /* copy data to new cluster */
+ sector_num = bat2sect(s, reversed_bat[idx_host]);
+ buf = g_malloc(s->cluster_size);
+ ret = bdrv_pread(bs->file, sector_num << BDRV_SECTOR_BITS,
+ buf, s->cluster_size);
+ if (ret < 0) {
+ res->check_errors++;
+ g_free(buf);
+ goto out;
+ }
+
+ ret = bdrv_pwrite(bs->file, s->data_end << BDRV_SECTOR_BITS,
+ buf, s->cluster_size);
+ if (ret < 0) {
+ res->check_errors++;
+ g_free(buf);
+ goto out;
+ }
+
+ s->bat_bitmap[i] = cpu_to_le32(s->data_end /
s->off_multiplier);
+ s->data_end += s->tracks;
+ bitmap_set(s->bat_dirty_bmap,
+ bat_entry_off(i) / s->bat_dirty_block, 1);
+ g_free(buf);
+
+ res->corruptions_fixed++;
+ flush_bat = true;
+
+ /* these values are invalid after repairing */
+ off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+ idx_host = (off - ((s->header->data_off) << BDRV_SECTOR_BITS))
+ / (s->cluster_size);
+ size = bdrv_getlength(bs->file->bs);
+ if (size < 0) {
+ res->check_errors++;
+ ret = size;
+ goto out;
+ }
+ }
+ }
+
+ reversed_bat[idx_host] = i;
+
/* cluster outside the image */
if (off > size) {
fprintf(stderr, "%s cluster %u is outside image\n",
@@ -472,7 +533,7 @@ static int coroutine_fn parallels_co_check(BlockDriverState
*bs,
high_off = off;
}
- if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
+ if (prev_off != 0 && (off - prev_off) % s->cluster_size != 0) {
res->bfi.fragmented_clusters++;
}
prev_off = off;
@@ -514,6 +575,7 @@ static int coroutine_fn parallels_co_check(BlockDriverState
*bs,
}
out:
+ g_free(reversed_bat);
qemu_co_mutex_unlock(&s->lock);
return ret;
}
--
2.25.1