qemu/block/blkverify.c
<<
>>
Prefs
   1/*
   2 * Block protocol for block driver correctness testing
   3 *
   4 * Copyright (C) 2010 IBM, Corp.
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9
  10#include <stdarg.h>
  11#include "qemu_socket.h" /* for EINPROGRESS on Windows */
  12#include "block_int.h"
  13
  14typedef struct {
  15    BlockDriverState *test_file;
  16} BDRVBlkverifyState;
  17
  18typedef struct BlkverifyAIOCB BlkverifyAIOCB;
  19struct BlkverifyAIOCB {
  20    BlockDriverAIOCB common;
  21    QEMUBH *bh;
  22
  23    /* Request metadata */
  24    bool is_write;
  25    int64_t sector_num;
  26    int nb_sectors;
  27
  28    int ret;                    /* first completed request's result */
  29    unsigned int done;          /* completion counter */
  30    bool *finished;             /* completion signal for cancel */
  31
  32    QEMUIOVector *qiov;         /* user I/O vector */
  33    QEMUIOVector raw_qiov;      /* cloned I/O vector for raw file */
  34    void *buf;                  /* buffer for raw file I/O */
  35
  36    void (*verify)(BlkverifyAIOCB *acb);
  37};
  38
  39static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
  40{
  41    BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb;
  42    bool finished = false;
  43
  44    /* Wait until request completes, invokes its callback, and frees itself */
  45    acb->finished = &finished;
  46    while (!finished) {
  47        qemu_aio_wait();
  48    }
  49}
  50
  51static const AIOCBInfo blkverify_aiocb_info = {
  52    .aiocb_size         = sizeof(BlkverifyAIOCB),
  53    .cancel             = blkverify_aio_cancel,
  54};
  55
  56static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
  57                                             const char *fmt, ...)
  58{
  59    va_list ap;
  60
  61    va_start(ap, fmt);
  62    fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ",
  63            acb->is_write ? "write" : "read", acb->sector_num,
  64            acb->nb_sectors);
  65    vfprintf(stderr, fmt, ap);
  66    fprintf(stderr, "\n");
  67    va_end(ap);
  68    exit(1);
  69}
  70
  71/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
  72static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
  73{
  74    BDRVBlkverifyState *s = bs->opaque;
  75    int ret;
  76    char *raw, *c;
  77
  78    /* Parse the blkverify: prefix */
  79    if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
  80        return -EINVAL;
  81    }
  82    filename += strlen("blkverify:");
  83
  84    /* Parse the raw image filename */
  85    c = strchr(filename, ':');
  86    if (c == NULL) {
  87        return -EINVAL;
  88    }
  89
  90    raw = g_strdup(filename);
  91    raw[c - filename] = '\0';
  92    ret = bdrv_file_open(&bs->file, raw, flags);
  93    g_free(raw);
  94    if (ret < 0) {
  95        return ret;
  96    }
  97    filename = c + 1;
  98
  99    /* Open the test file */
 100    s->test_file = bdrv_new("");
 101    ret = bdrv_open(s->test_file, filename, flags, NULL);
 102    if (ret < 0) {
 103        bdrv_delete(s->test_file);
 104        s->test_file = NULL;
 105        return ret;
 106    }
 107
 108    return 0;
 109}
 110
 111static void blkverify_close(BlockDriverState *bs)
 112{
 113    BDRVBlkverifyState *s = bs->opaque;
 114
 115    bdrv_delete(s->test_file);
 116    s->test_file = NULL;
 117}
 118
 119static int64_t blkverify_getlength(BlockDriverState *bs)
 120{
 121    BDRVBlkverifyState *s = bs->opaque;
 122
 123    return bdrv_getlength(s->test_file);
 124}
 125
 126/**
 127 * Check that I/O vector contents are identical
 128 *
 129 * @a:          I/O vector
 130 * @b:          I/O vector
 131 * @ret:        Offset to first mismatching byte or -1 if match
 132 */
 133static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
 134{
 135    int i;
 136    ssize_t offset = 0;
 137
 138    assert(a->niov == b->niov);
 139    for (i = 0; i < a->niov; i++) {
 140        size_t len = 0;
 141        uint8_t *p = (uint8_t *)a->iov[i].iov_base;
 142        uint8_t *q = (uint8_t *)b->iov[i].iov_base;
 143
 144        assert(a->iov[i].iov_len == b->iov[i].iov_len);
 145        while (len < a->iov[i].iov_len && *p++ == *q++) {
 146            len++;
 147        }
 148
 149        offset += len;
 150
 151        if (len != a->iov[i].iov_len) {
 152            return offset;
 153        }
 154    }
 155    return -1;
 156}
 157
 158typedef struct {
 159    int src_index;
 160    struct iovec *src_iov;
 161    void *dest_base;
 162} IOVectorSortElem;
 163
 164static int sortelem_cmp_src_base(const void *a, const void *b)
 165{
 166    const IOVectorSortElem *elem_a = a;
 167    const IOVectorSortElem *elem_b = b;
 168
 169    /* Don't overflow */
 170    if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
 171        return -1;
 172    } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
 173        return 1;
 174    } else {
 175        return 0;
 176    }
 177}
 178
 179static int sortelem_cmp_src_index(const void *a, const void *b)
 180{
 181    const IOVectorSortElem *elem_a = a;
 182    const IOVectorSortElem *elem_b = b;
 183
 184    return elem_a->src_index - elem_b->src_index;
 185}
 186
 187/**
 188 * Copy contents of I/O vector
 189 *
 190 * The relative relationships of overlapping iovecs are preserved.  This is
 191 * necessary to ensure identical semantics in the cloned I/O vector.
 192 */
 193static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
 194                                  void *buf)
 195{
 196    IOVectorSortElem sortelems[src->niov];
 197    void *last_end;
 198    int i;
 199
 200    /* Sort by source iovecs by base address */
 201    for (i = 0; i < src->niov; i++) {
 202        sortelems[i].src_index = i;
 203        sortelems[i].src_iov = &src->iov[i];
 204    }
 205    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
 206
 207    /* Allocate buffer space taking into account overlapping iovecs */
 208    last_end = NULL;
 209    for (i = 0; i < src->niov; i++) {
 210        struct iovec *cur = sortelems[i].src_iov;
 211        ptrdiff_t rewind = 0;
 212
 213        /* Detect overlap */
 214        if (last_end && last_end > cur->iov_base) {
 215            rewind = last_end - cur->iov_base;
 216        }
 217
 218        sortelems[i].dest_base = buf - rewind;
 219        buf += cur->iov_len - MIN(rewind, cur->iov_len);
 220        last_end = MAX(cur->iov_base + cur->iov_len, last_end);
 221    }
 222
 223    /* Sort by source iovec index and build destination iovec */
 224    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
 225    for (i = 0; i < src->niov; i++) {
 226        qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
 227    }
 228}
 229
 230static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
 231                                         int64_t sector_num, QEMUIOVector *qiov,
 232                                         int nb_sectors,
 233                                         BlockDriverCompletionFunc *cb,
 234                                         void *opaque)
 235{
 236    BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
 237
 238    acb->bh = NULL;
 239    acb->is_write = is_write;
 240    acb->sector_num = sector_num;
 241    acb->nb_sectors = nb_sectors;
 242    acb->ret = -EINPROGRESS;
 243    acb->done = 0;
 244    acb->qiov = qiov;
 245    acb->buf = NULL;
 246    acb->verify = NULL;
 247    acb->finished = NULL;
 248    return acb;
 249}
 250
 251static void blkverify_aio_bh(void *opaque)
 252{
 253    BlkverifyAIOCB *acb = opaque;
 254
 255    qemu_bh_delete(acb->bh);
 256    if (acb->buf) {
 257        qemu_iovec_destroy(&acb->raw_qiov);
 258        qemu_vfree(acb->buf);
 259    }
 260    acb->common.cb(acb->common.opaque, acb->ret);
 261    if (acb->finished) {
 262        *acb->finished = true;
 263    }
 264    qemu_aio_release(acb);
 265}
 266
 267static void blkverify_aio_cb(void *opaque, int ret)
 268{
 269    BlkverifyAIOCB *acb = opaque;
 270
 271    switch (++acb->done) {
 272    case 1:
 273        acb->ret = ret;
 274        break;
 275
 276    case 2:
 277        if (acb->ret != ret) {
 278            blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
 279        }
 280
 281        if (acb->verify) {
 282            acb->verify(acb);
 283        }
 284
 285        acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
 286        qemu_bh_schedule(acb->bh);
 287        break;
 288    }
 289}
 290
 291static void blkverify_verify_readv(BlkverifyAIOCB *acb)
 292{
 293    ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
 294    if (offset != -1) {
 295        blkverify_err(acb, "contents mismatch in sector %" PRId64,
 296                      acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
 297    }
 298}
 299
 300static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
 301        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 302        BlockDriverCompletionFunc *cb, void *opaque)
 303{
 304    BDRVBlkverifyState *s = bs->opaque;
 305    BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
 306                                            nb_sectors, cb, opaque);
 307
 308    acb->verify = blkverify_verify_readv;
 309    acb->buf = qemu_blockalign(bs->file, qiov->size);
 310    qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
 311    blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
 312
 313    bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
 314                   blkverify_aio_cb, acb);
 315    bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
 316                   blkverify_aio_cb, acb);
 317    return &acb->common;
 318}
 319
 320static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
 321        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 322        BlockDriverCompletionFunc *cb, void *opaque)
 323{
 324    BDRVBlkverifyState *s = bs->opaque;
 325    BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
 326                                            nb_sectors, cb, opaque);
 327
 328    bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
 329                    blkverify_aio_cb, acb);
 330    bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
 331                    blkverify_aio_cb, acb);
 332    return &acb->common;
 333}
 334
 335static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
 336                                             BlockDriverCompletionFunc *cb,
 337                                             void *opaque)
 338{
 339    BDRVBlkverifyState *s = bs->opaque;
 340
 341    /* Only flush test file, the raw file is not important */
 342    return bdrv_aio_flush(s->test_file, cb, opaque);
 343}
 344
 345static BlockDriver bdrv_blkverify = {
 346    .format_name        = "blkverify",
 347    .protocol_name      = "blkverify",
 348
 349    .instance_size      = sizeof(BDRVBlkverifyState),
 350
 351    .bdrv_getlength     = blkverify_getlength,
 352
 353    .bdrv_file_open     = blkverify_open,
 354    .bdrv_close         = blkverify_close,
 355
 356    .bdrv_aio_readv     = blkverify_aio_readv,
 357    .bdrv_aio_writev    = blkverify_aio_writev,
 358    .bdrv_aio_flush     = blkverify_aio_flush,
 359};
 360
 361static void bdrv_blkverify_init(void)
 362{
 363    bdrv_register(&bdrv_blkverify);
 364}
 365
 366block_init(bdrv_blkverify_init);
 367