Annotation of qemu/block/blkverify.c, revision 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.