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