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/sockets.h" /* for EINPROGRESS on Windows */ 12 #include "block/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 const AIOCBInfo blkverify_aiocb_info = { 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 void blkverify_parse_filename(const char *filename, QDict *options, 73 Error **errp) 74 { 75 const char *c; 76 QString *raw_path; 77 78 79 /* Parse the blkverify: prefix */ 80 if (!strstart(filename, "blkverify:", &filename)) { 81 error_setg(errp, "File name string must start with 'blkverify:'"); 82 return; 83 } 84 85 /* Parse the raw image filename */ 86 c = strchr(filename, ':'); 87 if (c == NULL) { 88 error_setg(errp, "blkverify requires raw copy and original image path"); 89 return; 90 } 91 92 /* TODO Implement option pass-through and set raw.filename here */ 93 raw_path = qstring_from_substr(filename, 0, c - filename - 1); 94 qdict_put(options, "x-raw", raw_path); 95 96 /* TODO Allow multi-level nesting and set file.filename here */ 97 filename = c + 1; 98 qdict_put(options, "x-image", qstring_from_str(filename)); 99 } 100 101 static QemuOptsList runtime_opts = { 102 .name = "blkverify", 103 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 104 .desc = { 105 { 106 .name = "x-raw", 107 .type = QEMU_OPT_STRING, 108 .help = "[internal use only, will be removed]", 109 }, 110 { 111 .name = "x-image", 112 .type = QEMU_OPT_STRING, 113 .help = "[internal use only, will be removed]", 114 }, 115 { /* end of list */ } 116 }, 117 }; 118 119 static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, 120 Error **errp) 121 { 122 BDRVBlkverifyState *s = bs->opaque; 123 QemuOpts *opts; 124 Error *local_err = NULL; 125 const char *filename, *raw; 126 int ret; 127 128 opts = qemu_opts_create_nofail(&runtime_opts); 129 qemu_opts_absorb_qdict(opts, options, &local_err); 130 if (error_is_set(&local_err)) { 131 error_propagate(errp, local_err); 132 ret = -EINVAL; 133 goto fail; 134 } 135 136 /* Parse the raw image filename */ 137 raw = qemu_opt_get(opts, "x-raw"); 138 if (raw == NULL) { 139 error_setg(errp, "Could not retrieve raw image filename"); 140 ret = -EINVAL; 141 goto fail; 142 } 143 144 ret = bdrv_file_open(&bs->file, raw, NULL, flags, &local_err); 145 if (ret < 0) { 146 error_propagate(errp, local_err); 147 goto fail; 148 } 149 150 /* Open the test file */ 151 filename = qemu_opt_get(opts, "x-image"); 152 if (filename == NULL) { 153 error_setg(errp, "Could not retrieve test image filename"); 154 ret = -EINVAL; 155 goto fail; 156 } 157 158 s->test_file = bdrv_new(""); 159 ret = bdrv_open(s->test_file, filename, NULL, flags, NULL, &local_err); 160 if (ret < 0) { 161 error_propagate(errp, local_err); 162 bdrv_unref(s->test_file); 163 s->test_file = NULL; 164 goto fail; 165 } 166 167 ret = 0; 168 fail: 169 return ret; 170 } 171 172 static void blkverify_close(BlockDriverState *bs) 173 { 174 BDRVBlkverifyState *s = bs->opaque; 175 176 bdrv_unref(s->test_file); 177 s->test_file = NULL; 178 } 179 180 static int64_t blkverify_getlength(BlockDriverState *bs) 181 { 182 BDRVBlkverifyState *s = bs->opaque; 183 184 return bdrv_getlength(s->test_file); 185 } 186 187 /** 188 * Check that I/O vector contents are identical 189 * 190 * @a: I/O vector 191 * @b: I/O vector 192 * @ret: Offset to first mismatching byte or -1 if match 193 */ 194 static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b) 195 { 196 int i; 197 ssize_t offset = 0; 198 199 assert(a->niov == b->niov); 200 for (i = 0; i < a->niov; i++) { 201 size_t len = 0; 202 uint8_t *p = (uint8_t *)a->iov[i].iov_base; 203 uint8_t *q = (uint8_t *)b->iov[i].iov_base; 204 205 assert(a->iov[i].iov_len == b->iov[i].iov_len); 206 while (len < a->iov[i].iov_len && *p++ == *q++) { 207 len++; 208 } 209 210 offset += len; 211 212 if (len != a->iov[i].iov_len) { 213 return offset; 214 } 215 } 216 return -1; 217 } 218 219 typedef struct { 220 int src_index; 221 struct iovec *src_iov; 222 void *dest_base; 223 } IOVectorSortElem; 224 225 static int sortelem_cmp_src_base(const void *a, const void *b) 226 { 227 const IOVectorSortElem *elem_a = a; 228 const IOVectorSortElem *elem_b = b; 229 230 /* Don't overflow */ 231 if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) { 232 return -1; 233 } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) { 234 return 1; 235 } else { 236 return 0; 237 } 238 } 239 240 static int sortelem_cmp_src_index(const void *a, const void *b) 241 { 242 const IOVectorSortElem *elem_a = a; 243 const IOVectorSortElem *elem_b = b; 244 245 return elem_a->src_index - elem_b->src_index; 246 } 247 248 /** 249 * Copy contents of I/O vector 250 * 251 * The relative relationships of overlapping iovecs are preserved. This is 252 * necessary to ensure identical semantics in the cloned I/O vector. 253 */ 254 static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, 255 void *buf) 256 { 257 IOVectorSortElem sortelems[src->niov]; 258 void *last_end; 259 int i; 260 261 /* Sort by source iovecs by base address */ 262 for (i = 0; i < src->niov; i++) { 263 sortelems[i].src_index = i; 264 sortelems[i].src_iov = &src->iov[i]; 265 } 266 qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base); 267 268 /* Allocate buffer space taking into account overlapping iovecs */ 269 last_end = NULL; 270 for (i = 0; i < src->niov; i++) { 271 struct iovec *cur = sortelems[i].src_iov; 272 ptrdiff_t rewind = 0; 273 274 /* Detect overlap */ 275 if (last_end && last_end > cur->iov_base) { 276 rewind = last_end - cur->iov_base; 277 } 278 279 sortelems[i].dest_base = buf - rewind; 280 buf += cur->iov_len - MIN(rewind, cur->iov_len); 281 last_end = MAX(cur->iov_base + cur->iov_len, last_end); 282 } 283 284 /* Sort by source iovec index and build destination iovec */ 285 qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index); 286 for (i = 0; i < src->niov; i++) { 287 qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len); 288 } 289 } 290 291 static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, 292 int64_t sector_num, QEMUIOVector *qiov, 293 int nb_sectors, 294 BlockDriverCompletionFunc *cb, 295 void *opaque) 296 { 297 BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); 298 299 acb->bh = NULL; 300 acb->is_write = is_write; 301 acb->sector_num = sector_num; 302 acb->nb_sectors = nb_sectors; 303 acb->ret = -EINPROGRESS; 304 acb->done = 0; 305 acb->qiov = qiov; 306 acb->buf = NULL; 307 acb->verify = NULL; 308 acb->finished = NULL; 309 return acb; 310 } 311 312 static void blkverify_aio_bh(void *opaque) 313 { 314 BlkverifyAIOCB *acb = opaque; 315 316 qemu_bh_delete(acb->bh); 317 if (acb->buf) { 318 qemu_iovec_destroy(&acb->raw_qiov); 319 qemu_vfree(acb->buf); 320 } 321 acb->common.cb(acb->common.opaque, acb->ret); 322 if (acb->finished) { 323 *acb->finished = true; 324 } 325 qemu_aio_release(acb); 326 } 327 328 static void blkverify_aio_cb(void *opaque, int ret) 329 { 330 BlkverifyAIOCB *acb = opaque; 331 332 switch (++acb->done) { 333 case 1: 334 acb->ret = ret; 335 break; 336 337 case 2: 338 if (acb->ret != ret) { 339 blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret); 340 } 341 342 if (acb->verify) { 343 acb->verify(acb); 344 } 345 346 acb->bh = qemu_bh_new(blkverify_aio_bh, acb); 347 qemu_bh_schedule(acb->bh); 348 break; 349 } 350 } 351 352 static void blkverify_verify_readv(BlkverifyAIOCB *acb) 353 { 354 ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov); 355 if (offset != -1) { 356 blkverify_err(acb, "contents mismatch in sector %" PRId64, 357 acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); 358 } 359 } 360 361 static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs, 362 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 363 BlockDriverCompletionFunc *cb, void *opaque) 364 { 365 BDRVBlkverifyState *s = bs->opaque; 366 BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov, 367 nb_sectors, cb, opaque); 368 369 acb->verify = blkverify_verify_readv; 370 acb->buf = qemu_blockalign(bs->file, qiov->size); 371 qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); 372 blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf); 373 374 bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, 375 blkverify_aio_cb, acb); 376 bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors, 377 blkverify_aio_cb, acb); 378 return &acb->common; 379 } 380 381 static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs, 382 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 383 BlockDriverCompletionFunc *cb, void *opaque) 384 { 385 BDRVBlkverifyState *s = bs->opaque; 386 BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, 387 nb_sectors, cb, opaque); 388 389 bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors, 390 blkverify_aio_cb, acb); 391 bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, 392 blkverify_aio_cb, acb); 393 return &acb->common; 394 } 395 396 static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs, 397 BlockDriverCompletionFunc *cb, 398 void *opaque) 399 { 400 BDRVBlkverifyState *s = bs->opaque; 401 402 /* Only flush test file, the raw file is not important */ 403 return bdrv_aio_flush(s->test_file, cb, opaque); 404 } 405 406 static BlockDriver bdrv_blkverify = { 407 .format_name = "blkverify", 408 .protocol_name = "blkverify", 409 .instance_size = sizeof(BDRVBlkverifyState), 410 411 .bdrv_parse_filename = blkverify_parse_filename, 412 .bdrv_file_open = blkverify_open, 413 .bdrv_close = blkverify_close, 414 .bdrv_getlength = blkverify_getlength, 415 416 .bdrv_aio_readv = blkverify_aio_readv, 417 .bdrv_aio_writev = blkverify_aio_writev, 418 .bdrv_aio_flush = blkverify_aio_flush, 419 420 .bdrv_check_ext_snapshot = bdrv_check_ext_snapshot_forbidden, 421 }; 422 423 static void bdrv_blkverify_init(void) 424 { 425 bdrv_register(&bdrv_blkverify); 426 } 427 428 block_init(bdrv_blkverify_init); 429