Annotation of qemu/block/blkverify.c, revision 1.1.1.3

1.1       root        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: 
                     14: typedef struct {
                     15:     BlockDriverState *test_file;
                     16: } BDRVBlkverifyState;
                     17: 
                     18: typedef struct BlkverifyAIOCB BlkverifyAIOCB;
                     19: struct 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: 
                     39: static 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: 
                     51: static AIOPool blkverify_aio_pool = {
                     52:     .aiocb_size         = sizeof(BlkverifyAIOCB),
                     53:     .cancel             = blkverify_aio_cancel,
                     54: };
                     55: 
                     56: static 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 */
                     72: static 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: 
1.1.1.3 ! root       90:     raw = g_strdup(filename);
1.1       root       91:     raw[c - filename] = '\0';
                     92:     ret = bdrv_file_open(&bs->file, raw, flags);
1.1.1.3 ! root       93:     g_free(raw);
1.1       root       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: 
                    111: static 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: 
                    119: static 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:  */
                    133: static 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: 
                    158: typedef struct {
                    159:     int src_index;
                    160:     struct iovec *src_iov;
                    161:     void *dest_base;
                    162: } IOVectorSortElem;
                    163: 
                    164: static 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: 
                    179: static 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:  */
                    193: static 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: 
                    230: static 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_aio_pool, 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: 
                    251: static 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: 
                    267: static 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: 
                    291: static 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: 
                    300: static 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: 
1.1.1.3 ! root      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);
1.1       root      317:     return &acb->common;
                    318: }
                    319: 
                    320: static 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: 
1.1.1.3 ! root      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);
1.1       root      332:     return &acb->common;
                    333: }
                    334: 
                    335: static 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: 
                    345: static 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: 
                    361: static void bdrv_blkverify_init(void)
                    362: {
                    363:     bdrv_register(&bdrv_blkverify);
                    364: }
                    365: 
                    366: block_init(bdrv_blkverify_init);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.