Am 04.09.2010 17:34, schrieb Stefan Hajnoczi:
> The blkverify block driver makes investigating image format data
> corruption much easier.  A raw image initialized with the same contents
> as the test image (e.g. qcow2 file) must be provided.  The raw image
> mirrors read/write operations and is used to verify that data read from
> the test image is correct.
> 
> Signed-off-by: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com>
> ---
> This is embarassing, I sent out the v2 patch instead of the v3 patch the first
> time!
> 
> v3:
>  * Fix compile error in blkverify_aio_cancel()
> 
> v2:
>  * Implement aio_cancel() by waiting for pending requests
>  * Fix conflict in Makefile.objs
> 
>  Makefile.objs      |    2 +-
>  block/blkverify.c  |  324 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  docs/blkverify.txt |   69 +++++++++++
>  3 files changed, 394 insertions(+), 1 deletions(-)
>  create mode 100644 block/blkverify.c
>  create mode 100644 docs/blkverify.txt
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index 4a1eaa1..b640ec8 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -14,7 +14,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
>  
>  block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o 
> vpc.o vvfat.o
>  block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
> -block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o
> +block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
>  block-nested-$(CONFIG_WIN32) += raw-win32.o
>  block-nested-$(CONFIG_POSIX) += raw-posix.o
>  block-nested-$(CONFIG_CURL) += curl.o
> diff --git a/block/blkverify.c b/block/blkverify.c
> new file mode 100644
> index 0000000..97717a6
> --- /dev/null
> +++ b/block/blkverify.c
> @@ -0,0 +1,324 @@
> +/*
> + * Block protocol for block driver correctness testing
> + *
> + * Copyright (C) 2010 IBM, Corp.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include <stdarg.h>
> +#include "block_int.h"
> +
> +typedef struct {
> +    BlockDriverState *test_file;
> +} BDRVBlkverifyState;
> +
> +typedef struct BlkverifyAIOCB BlkverifyAIOCB;
> +struct BlkverifyAIOCB {
> +    BlockDriverAIOCB common;
> +    QEMUBH *bh;
> +
> +    /* Request metadata */
> +    bool is_write;
> +    int64_t sector_num;
> +    int nb_sectors;
> +
> +    int ret;                    /* first completed request's result */
> +    unsigned int done;          /* completion counter */
> +
> +    QEMUIOVector *qiov;         /* user I/O vector */
> +    QEMUIOVector raw_qiov;      /* cloned I/O vector for raw file */
> +    void *buf;                  /* buffer for raw file I/O */
> +
> +    void (*verify)(BlkverifyAIOCB *acb);
> +};
> +
> +static void blkverify_aio_cancel_cb(void *opaque, int ret)
> +{
> +    *(bool *)opaque = true;
> +}
> +
> +static void blkverify_aio_cancel(BlockDriverAIOCB *acb)
> +{
> +    bool done = false;
> +
> +    /* Allow the request to complete so the raw file and test file stay in
> +     * sync.  Hijack the callback (since the request is cancelled anyway) to
> +     * wait for completion.
> +     */

The approach of completing the request sounds okay, but I think you need
to call the original callback if you let it complete.

> +    acb->cb = blkverify_aio_cancel_cb;
> +    acb->opaque = &done;
> +    while (!done) {
> +        qemu_aio_wait();
> +    }

qemu_aio_release(acb)?

> +}
> +
> +static AIOPool blkverify_aio_pool = {
> +    .aiocb_size         = sizeof(BlkverifyAIOCB),
> +    .cancel             = blkverify_aio_cancel,
> +};
> +
> +static void blkverify_err(BlkverifyAIOCB *acb, const char *fmt, ...)
> +{
> +    va_list ap;
> +
> +    va_start(ap, fmt);
> +    fprintf(stderr, "blkverify: %s sector_num=%ld nb_sectors=%d ",
> +            acb->is_write ? "write" : "read", acb->sector_num,
> +            acb->nb_sectors);
> +    vfprintf(stderr, fmt, ap);
> +    fprintf(stderr, "\n");
> +    va_end(ap);
> +    exit(1);
> +}
> +
> +/* Valid blkverify filenames look like 
> blkverify:path/to/raw_image:path/to/image */
> +static int blkverify_open(BlockDriverState *bs, const char *filename, int 
> flags)
> +{
> +    BDRVBlkverifyState *s = bs->opaque;
> +    int ret;
> +    char *raw, *c;
> +
> +    /* Parse the blkverify: prefix */
> +    if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
> +        return -EINVAL;
> +    }
> +    filename += strlen("blkverify:");
> +
> +    /* Parse the raw image filename */
> +    c = strchr(filename, ':');
> +    if (c == NULL) {
> +        return -EINVAL;
> +    }
> +
> +    raw = strdup(filename);
> +    raw[c - filename] = '\0';
> +    ret = bdrv_file_open(&bs->file, raw, flags);
> +    free(raw);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +    filename = c + 1;
> +
> +    /* Open the test file */
> +    s->test_file = bdrv_new("");
> +    ret = bdrv_open(s->test_file, filename, flags, NULL);
> +    if (ret < 0) {
> +        return ret;

This leaks bs->file.

Kevin

Reply via email to