|
|
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);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.