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); 384