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

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: 
                     90:     raw = strdup(filename);
                     91:     raw[c - filename] = '\0';
                     92:     ret = bdrv_file_open(&bs->file, raw, flags);
                     93:     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: 
                    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 int blkverify_flush(BlockDriverState *bs)
                    120: {
                    121:     BDRVBlkverifyState *s = bs->opaque;
                    122: 
                    123:     /* Only flush test file, the raw file is not important */
                    124:     return bdrv_flush(s->test_file);
                    125: }
                    126: 
                    127: static int64_t blkverify_getlength(BlockDriverState *bs)
                    128: {
                    129:     BDRVBlkverifyState *s = bs->opaque;
                    130: 
                    131:     return bdrv_getlength(s->test_file);
                    132: }
                    133: 
                    134: /**
                    135:  * Check that I/O vector contents are identical
                    136:  *
                    137:  * @a:          I/O vector
                    138:  * @b:          I/O vector
                    139:  * @ret:        Offset to first mismatching byte or -1 if match
                    140:  */
                    141: static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
                    142: {
                    143:     int i;
                    144:     ssize_t offset = 0;
                    145: 
                    146:     assert(a->niov == b->niov);
                    147:     for (i = 0; i < a->niov; i++) {
                    148:         size_t len = 0;
                    149:         uint8_t *p = (uint8_t *)a->iov[i].iov_base;
                    150:         uint8_t *q = (uint8_t *)b->iov[i].iov_base;
                    151: 
                    152:         assert(a->iov[i].iov_len == b->iov[i].iov_len);
                    153:         while (len < a->iov[i].iov_len && *p++ == *q++) {
                    154:             len++;
                    155:         }
                    156: 
                    157:         offset += len;
                    158: 
                    159:         if (len != a->iov[i].iov_len) {
                    160:             return offset;
                    161:         }
                    162:     }
                    163:     return -1;
                    164: }
                    165: 
                    166: typedef struct {
                    167:     int src_index;
                    168:     struct iovec *src_iov;
                    169:     void *dest_base;
                    170: } IOVectorSortElem;
                    171: 
                    172: static int sortelem_cmp_src_base(const void *a, const void *b)
                    173: {
                    174:     const IOVectorSortElem *elem_a = a;
                    175:     const IOVectorSortElem *elem_b = b;
                    176: 
                    177:     /* Don't overflow */
                    178:     if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
                    179:         return -1;
                    180:     } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
                    181:         return 1;
                    182:     } else {
                    183:         return 0;
                    184:     }
                    185: }
                    186: 
                    187: static int sortelem_cmp_src_index(const void *a, const void *b)
                    188: {
                    189:     const IOVectorSortElem *elem_a = a;
                    190:     const IOVectorSortElem *elem_b = b;
                    191: 
                    192:     return elem_a->src_index - elem_b->src_index;
                    193: }
                    194: 
                    195: /**
                    196:  * Copy contents of I/O vector
                    197:  *
                    198:  * The relative relationships of overlapping iovecs are preserved.  This is
                    199:  * necessary to ensure identical semantics in the cloned I/O vector.
                    200:  */
                    201: static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
                    202:                                   void *buf)
                    203: {
                    204:     IOVectorSortElem sortelems[src->niov];
                    205:     void *last_end;
                    206:     int i;
                    207: 
                    208:     /* Sort by source iovecs by base address */
                    209:     for (i = 0; i < src->niov; i++) {
                    210:         sortelems[i].src_index = i;
                    211:         sortelems[i].src_iov = &src->iov[i];
                    212:     }
                    213:     qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
                    214: 
                    215:     /* Allocate buffer space taking into account overlapping iovecs */
                    216:     last_end = NULL;
                    217:     for (i = 0; i < src->niov; i++) {
                    218:         struct iovec *cur = sortelems[i].src_iov;
                    219:         ptrdiff_t rewind = 0;
                    220: 
                    221:         /* Detect overlap */
                    222:         if (last_end && last_end > cur->iov_base) {
                    223:             rewind = last_end - cur->iov_base;
                    224:         }
                    225: 
                    226:         sortelems[i].dest_base = buf - rewind;
                    227:         buf += cur->iov_len - MIN(rewind, cur->iov_len);
                    228:         last_end = MAX(cur->iov_base + cur->iov_len, last_end);
                    229:     }
                    230: 
                    231:     /* Sort by source iovec index and build destination iovec */
                    232:     qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
                    233:     for (i = 0; i < src->niov; i++) {
                    234:         qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
                    235:     }
                    236: }
                    237: 
                    238: static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
                    239:                                          int64_t sector_num, QEMUIOVector *qiov,
                    240:                                          int nb_sectors,
                    241:                                          BlockDriverCompletionFunc *cb,
                    242:                                          void *opaque)
                    243: {
                    244:     BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
                    245: 
                    246:     acb->bh = NULL;
                    247:     acb->is_write = is_write;
                    248:     acb->sector_num = sector_num;
                    249:     acb->nb_sectors = nb_sectors;
                    250:     acb->ret = -EINPROGRESS;
                    251:     acb->done = 0;
                    252:     acb->qiov = qiov;
                    253:     acb->buf = NULL;
                    254:     acb->verify = NULL;
                    255:     acb->finished = NULL;
                    256:     return acb;
                    257: }
                    258: 
                    259: static void blkverify_aio_bh(void *opaque)
                    260: {
                    261:     BlkverifyAIOCB *acb = opaque;
                    262: 
                    263:     qemu_bh_delete(acb->bh);
                    264:     if (acb->buf) {
                    265:         qemu_iovec_destroy(&acb->raw_qiov);
                    266:         qemu_vfree(acb->buf);
                    267:     }
                    268:     acb->common.cb(acb->common.opaque, acb->ret);
                    269:     if (acb->finished) {
                    270:         *acb->finished = true;
                    271:     }
                    272:     qemu_aio_release(acb);
                    273: }
                    274: 
                    275: static void blkverify_aio_cb(void *opaque, int ret)
                    276: {
                    277:     BlkverifyAIOCB *acb = opaque;
                    278: 
                    279:     switch (++acb->done) {
                    280:     case 1:
                    281:         acb->ret = ret;
                    282:         break;
                    283: 
                    284:     case 2:
                    285:         if (acb->ret != ret) {
                    286:             blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
                    287:         }
                    288: 
                    289:         if (acb->verify) {
                    290:             acb->verify(acb);
                    291:         }
                    292: 
                    293:         acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
                    294:         qemu_bh_schedule(acb->bh);
                    295:         break;
                    296:     }
                    297: }
                    298: 
                    299: static void blkverify_verify_readv(BlkverifyAIOCB *acb)
                    300: {
                    301:     ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
                    302:     if (offset != -1) {
                    303:         blkverify_err(acb, "contents mismatch in sector %" PRId64,
                    304:                       acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
                    305:     }
                    306: }
                    307: 
                    308: static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
                    309:         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
                    310:         BlockDriverCompletionFunc *cb, void *opaque)
                    311: {
                    312:     BDRVBlkverifyState *s = bs->opaque;
                    313:     BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
                    314:                                             nb_sectors, cb, opaque);
                    315: 
                    316:     acb->verify = blkverify_verify_readv;
                    317:     acb->buf = qemu_blockalign(bs->file, qiov->size);
                    318:     qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
                    319:     blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
                    320: 
                    321:     if (!bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
                    322:                         blkverify_aio_cb, acb)) {
                    323:         blkverify_aio_cb(acb, -EIO);
                    324:     }
                    325:     if (!bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
                    326:                         blkverify_aio_cb, acb)) {
                    327:         blkverify_aio_cb(acb, -EIO);
                    328:     }
                    329:     return &acb->common;
                    330: }
                    331: 
                    332: static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
                    333:         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
                    334:         BlockDriverCompletionFunc *cb, void *opaque)
                    335: {
                    336:     BDRVBlkverifyState *s = bs->opaque;
                    337:     BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
                    338:                                             nb_sectors, cb, opaque);
                    339: 
                    340:     if (!bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
                    341:                          blkverify_aio_cb, acb)) {
                    342:         blkverify_aio_cb(acb, -EIO);
                    343:     }
                    344:     if (!bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
                    345:                          blkverify_aio_cb, acb)) {
                    346:         blkverify_aio_cb(acb, -EIO);
                    347:     }
                    348:     return &acb->common;
                    349: }
                    350: 
                    351: static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
                    352:                                              BlockDriverCompletionFunc *cb,
                    353:                                              void *opaque)
                    354: {
                    355:     BDRVBlkverifyState *s = bs->opaque;
                    356: 
                    357:     /* Only flush test file, the raw file is not important */
                    358:     return bdrv_aio_flush(s->test_file, cb, opaque);
                    359: }
                    360: 
                    361: static BlockDriver bdrv_blkverify = {
                    362:     .format_name        = "blkverify",
                    363:     .protocol_name      = "blkverify",
                    364: 
                    365:     .instance_size      = sizeof(BDRVBlkverifyState),
                    366: 
                    367:     .bdrv_getlength     = blkverify_getlength,
                    368: 
                    369:     .bdrv_file_open     = blkverify_open,
                    370:     .bdrv_close         = blkverify_close,
                    371:     .bdrv_flush         = blkverify_flush,
                    372: 
                    373:     .bdrv_aio_readv     = blkverify_aio_readv,
                    374:     .bdrv_aio_writev    = blkverify_aio_writev,
                    375:     .bdrv_aio_flush     = blkverify_aio_flush,
                    376: };
                    377: 
                    378: static void bdrv_blkverify_init(void)
                    379: {
                    380:     bdrv_register(&bdrv_blkverify);
                    381: }
                    382: 
                    383: 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.