All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Denis V. Lunev" <den@virtuozzo.com>
To: alexander.ivanov@virtuozzo.com, qemu-devel@nongnu.org
Subject: Re: [PATCH 1/3] parallels: Add checking and repairing duplicate offsets in BAT
Date: Thu, 4 Aug 2022 17:18:11 +0200	[thread overview]
Message-ID: <55f445a4-42dc-22ba-6b81-f368ed484ff9@virtuozzo.com> (raw)
In-Reply-To: <20220804145200.564072-2-alexander.ivanov@virtuozzo.com>

On 04.08.2022 16:51, alexander.ivanov@virtuozzo.com wrote:
> From: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
>
> There could be corruptions in the image file:
> two quest memory areas refer to the same host cluster.
>
> If a duplicate offset is found fix it by copying the content
> of the referred cluster to a new allocated cluster and
> replace one of the two referring entries by the new cluster offset.
>
> Signed-off-by: Natalia Kuzmina <natalia.kuzmina@openvz.org>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> ---
>   block/parallels.c | 93 +++++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 90 insertions(+), 3 deletions(-)
>
> diff --git a/block/parallels.c b/block/parallels.c
> index a229c06f25..6a82942f38 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -64,6 +64,11 @@ static QEnumLookup prealloc_mode_lookup = {
>   #define PARALLELS_OPT_PREALLOC_MODE     "prealloc-mode"
>   #define PARALLELS_OPT_PREALLOC_SIZE     "prealloc-size"
>   
> +#define REVERSED_BAT_UNTOUCHED  0xFFFFFFFF
> +
> +#define HOST_CLUSTER_INDEX(s, off) \
> +    ((off - ((s->header->data_off) << BDRV_SECTOR_BITS)) / (s->cluster_size))
> +
>   static QemuOptsList parallels_runtime_opts = {
>       .name = "parallels",
>       .head = QTAILQ_HEAD_INITIALIZER(parallels_runtime_opts.head),
> @@ -419,9 +424,11 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
>                                              BdrvCheckMode fix)
>   {
>       BDRVParallelsState *s = bs->opaque;
> -    int64_t size, prev_off, high_off;
> -    int ret;
> -    uint32_t i;
> +    QEMUIOVector qiov;
> +    int64_t size, prev_off, high_off, sector_num;
> +    int ret, n;
> +    uint32_t i, idx_host, *reversed_bat;
> +    int64_t *cluster_buf;
>       bool flush_bat = false;
>   
>       size = bdrv_getlength(bs->file->bs);
> @@ -443,8 +450,31 @@ 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 */
>   
> +    cluster_buf = g_malloc(s->cluster_size);
> +    qemu_iovec_init(&qiov, 0);
> +    qemu_iovec_add(&qiov, cluster_buf, s->cluster_size);
> +
> +    /*
> +     * Make a reversed BAT. The table has the same size as BAT.
I would better use different wording. We need to define why the table is 
used
and what is idea behind it.

"Each cluster in the host file could represent only one cluster from the 
guest point of view.
  Reversed BAT provides mapping of that type."


> +     * Initially the table is filled with REVERSED_BAT_UNTOUCHED values.
> +     * A position in the table is defined by a host index
> +     * (a number of a cluster in the data area):
> +     *     index = (cluster_offset - data_area_offset) / cluster_size
> +     * In the main loop fill the table with guest indexes
^^ indices
> +     * (a number of entry in BAT).
> +     * Before this, check if the relevant entry in the reversed table
> +     * is REVERSED_BAT_UNTOUCHED. If that's not true, a guest index was
> +     * written to the reversed table on a previous step.
> +     * It means there is a duplicate offset.
> +     */
> +    reversed_bat = g_malloc(s->bat_size * sizeof(uint32_t));
> +    for (i = 0; i < s->bat_size; i++) {
> +        reversed_bat[i] = REVERSED_BAT_UNTOUCHED;
> +    }
> +
>       high_off = 0;
>       prev_off = 0;
>       for (i = 0; i < s->bat_size; i++) {
> @@ -468,6 +498,59 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
>               }
>           }
>   
> +        /* Checking bat entry uniqueness. */
> +        idx_host = HOST_CLUSTER_INDEX(s, off);
> +        if (reversed_bat[idx_host] != REVERSED_BAT_UNTOUCHED) {
> +            /* duplicated offset in BAT */
> +            fprintf(stderr,
> +                    "%s BAT offset in entry %u duplicates offset in entry %u\n",
> +                    fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
> +                    i, reversed_bat[idx_host]);
> +            res->corruptions++;
> +
> +            if (fix & BDRV_FIX_ERRORS) {
> +                /* copy data to a new cluster */
> +                sector_num = bat2sect(s, reversed_bat[idx_host]);
> +
> +                ret = bdrv_pread(bs->file, sector_num << BDRV_SECTOR_BITS,
> +                                 s->cluster_size, cluster_buf, 0);
> +                if (ret < 0) {
> +                    res->check_errors++;
> +                    goto out;
> +                }
> +
I'd add a comment here, this is a bit tricky thing, we have discussed this
verbally a lot.

> +                s->bat_bitmap[i] = 0;
> +
> +                sector_num = (i * s->cluster_size) >> BDRV_SECTOR_BITS;
> +                off = allocate_clusters(bs, sector_num, s->tracks, &n);
Should we do sanity check one more time? Fatal if that I believe.

> +                if (off < 0) {
> +                    res->check_errors++;
> +                    goto out;
> +                }
> +                off <<= BDRV_SECTOR_BITS;
> +
> +                /* off is new and we should repair idx_host accordingly. */
> +                idx_host = HOST_CLUSTER_INDEX(s, off);
> +
> +                ret = bdrv_co_pwritev(bs->file, off, s->cluster_size, &qiov, 0);
> +                if (ret < 0) {
> +                    res->check_errors++;
> +                    goto out;
> +                }
> +
> +                size = bdrv_getlength(bs->file->bs);
> +                if (size < 0) {
> +                    res->check_errors++;
> +                    ret = size;
> +                    goto out;
> +                }
> +
> +                res->corruptions_fixed++;
> +                flush_bat = true;
> +            }
> +        }
> +        reversed_bat[idx_host] = i;
> +
>           res->bfi.allocated_clusters++;
>           if (off > high_off) {
>               high_off = off;
> @@ -477,6 +560,7 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
>               res->bfi.fragmented_clusters++;
>           }
>           prev_off = off;
> +
please no unrelated changes

>       }
>   
>       ret = 0;
> @@ -515,6 +599,9 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
>       }
>   
>   out:
> +    qemu_iovec_destroy(&qiov);
> +    g_free(cluster_buf);
> +    g_free(reversed_bat);
>       qemu_co_mutex_unlock(&s->lock);
>       return ret;
>   }



  reply	other threads:[~2022-08-04 15:21 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-04 14:51 [PATCH 0/3] Check and repair duplicated clusters in parallels images alexander.ivanov
2022-08-04 14:51 ` [PATCH 1/3] parallels: Add checking and repairing duplicate offsets in BAT alexander.ivanov
2022-08-04 15:18   ` Denis V. Lunev [this message]
2022-08-04 14:51 ` [PATCH 2/3] parallels: Let duplicates repairing pass without unwanted messages alexander.ivanov
2022-08-04 15:22   ` Denis V. Lunev
2022-08-04 14:52 ` [PATCH 3/3] iotests, parallels: Add a test for duplicated clusters alexander.ivanov
2022-08-04 15:28   ` Denis V. Lunev
2022-08-04 15:01 ` [PATCH 0/3] Check and repair duplicated clusters in parallels images Denis V. Lunev
2022-08-04 15:31   ` Denis V. Lunev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55f445a4-42dc-22ba-6b81-f368ed484ff9@virtuozzo.com \
    --to=den@virtuozzo.com \
    --cc=alexander.ivanov@virtuozzo.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.