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 AioContext *aio_context = bdrv_get_aio_context(blockacb->bs); 43 bool finished = false; 44 45 /* Wait until request completes, invokes its callback, and frees itself */ 46 acb->finished = &finished; 47 while (!finished) { 48 aio_poll(aio_context, true); 49 } 50 } 51 52 static const AIOCBInfo blkverify_aiocb_info = { 53 .aiocb_size = sizeof(BlkverifyAIOCB), 54 .cancel = blkverify_aio_cancel, 55 }; 56 57 static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb, 58 const char *fmt, ...) 59 { 60 va_list ap; 61 62 va_start(ap, fmt); 63 fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ", 64 acb->is_write ? "write" : "read", acb->sector_num, 65 acb->nb_sectors); 66 vfprintf(stderr, fmt, ap); 67 fprintf(stderr, "\n"); 68 va_end(ap); 69 exit(1); 70 } 71 72 /* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */ 73 static void blkverify_parse_filename(const char *filename, QDict *options, 74 Error **errp) 75 { 76 const char *c; 77 QString *raw_path; 78 79 80 /* Parse the blkverify: prefix */ 81 if (!strstart(filename, "blkverify:", &filename)) { 82 /* There was no prefix; therefore, all options have to be already 83 present in the QDict (except for the filename) */ 84 qdict_put(options, "x-image", qstring_from_str(filename)); 85 return; 86 } 87 88 /* Parse the raw image filename */ 89 c = strchr(filename, ':'); 90 if (c == NULL) { 91 error_setg(errp, "blkverify requires raw copy and original image path"); 92 return; 93 } 94 95 /* TODO Implement option pass-through and set raw.filename here */ 96 raw_path = qstring_from_substr(filename, 0, c - filename - 1); 97 qdict_put(options, "x-raw", raw_path); 98 99 /* TODO Allow multi-level nesting and set file.filename here */ 100 filename = c + 1; 101 qdict_put(options, "x-image", qstring_from_str(filename)); 102 } 103 104 static QemuOptsList runtime_opts = { 105 .name = "blkverify", 106 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 107 .desc = { 108 { 109 .name = "x-raw", 110 .type = QEMU_OPT_STRING, 111 .help = "[internal use only, will be removed]", 112 }, 113 { 114 .name = "x-image", 115 .type = QEMU_OPT_STRING, 116 .help = "[internal use only, will be removed]", 117 }, 118 { /* end of list */ } 119 }, 120 }; 121 122 static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, 123 Error **errp) 124 { 125 BDRVBlkverifyState *s = bs->opaque; 126 QemuOpts *opts; 127 Error *local_err = NULL; 128 int ret; 129 130 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 131 qemu_opts_absorb_qdict(opts, options, &local_err); 132 if (local_err) { 133 error_propagate(errp, local_err); 134 ret = -EINVAL; 135 goto fail; 136 } 137 138 /* Open the raw file */ 139 assert(bs->file == NULL); 140 ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options, 141 "raw", flags | BDRV_O_PROTOCOL, false, &local_err); 142 if (ret < 0) { 143 error_propagate(errp, local_err); 144 goto fail; 145 } 146 147 /* Open the test file */ 148 assert(s->test_file == NULL); 149 ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options, 150 "test", flags, false, &local_err); 151 if (ret < 0) { 152 error_propagate(errp, local_err); 153 s->test_file = NULL; 154 goto fail; 155 } 156 157 ret = 0; 158 fail: 159 return ret; 160 } 161 162 static void blkverify_close(BlockDriverState *bs) 163 { 164 BDRVBlkverifyState *s = bs->opaque; 165 166 bdrv_unref(s->test_file); 167 s->test_file = NULL; 168 } 169 170 static int64_t blkverify_getlength(BlockDriverState *bs) 171 { 172 BDRVBlkverifyState *s = bs->opaque; 173 174 return bdrv_getlength(s->test_file); 175 } 176 177 static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, 178 int64_t sector_num, QEMUIOVector *qiov, 179 int nb_sectors, 180 BlockDriverCompletionFunc *cb, 181 void *opaque) 182 { 183 BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); 184 185 acb->bh = NULL; 186 acb->is_write = is_write; 187 acb->sector_num = sector_num; 188 acb->nb_sectors = nb_sectors; 189 acb->ret = -EINPROGRESS; 190 acb->done = 0; 191 acb->qiov = qiov; 192 acb->buf = NULL; 193 acb->verify = NULL; 194 acb->finished = NULL; 195 return acb; 196 } 197 198 static void blkverify_aio_bh(void *opaque) 199 { 200 BlkverifyAIOCB *acb = opaque; 201 202 qemu_bh_delete(acb->bh); 203 if (acb->buf) { 204 qemu_iovec_destroy(&acb->raw_qiov); 205 qemu_vfree(acb->buf); 206 } 207 acb->common.cb(acb->common.opaque, acb->ret); 208 if (acb->finished) { 209 *acb->finished = true; 210 } 211 qemu_aio_release(acb); 212 } 213 214 static void blkverify_aio_cb(void *opaque, int ret) 215 { 216 BlkverifyAIOCB *acb = opaque; 217 218 switch (++acb->done) { 219 case 1: 220 acb->ret = ret; 221 break; 222 223 case 2: 224 if (acb->ret != ret) { 225 blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret); 226 } 227 228 if (acb->verify) { 229 acb->verify(acb); 230 } 231 232 acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), 233 blkverify_aio_bh, acb); 234 qemu_bh_schedule(acb->bh); 235 break; 236 } 237 } 238 239 static void blkverify_verify_readv(BlkverifyAIOCB *acb) 240 { 241 ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov); 242 if (offset != -1) { 243 blkverify_err(acb, "contents mismatch in sector %" PRId64, 244 acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); 245 } 246 } 247 248 static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs, 249 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 250 BlockDriverCompletionFunc *cb, void *opaque) 251 { 252 BDRVBlkverifyState *s = bs->opaque; 253 BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov, 254 nb_sectors, cb, opaque); 255 256 acb->verify = blkverify_verify_readv; 257 acb->buf = qemu_blockalign(bs->file, qiov->size); 258 qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); 259 qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf); 260 261 bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, 262 blkverify_aio_cb, acb); 263 bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors, 264 blkverify_aio_cb, acb); 265 return &acb->common; 266 } 267 268 static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs, 269 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 270 BlockDriverCompletionFunc *cb, void *opaque) 271 { 272 BDRVBlkverifyState *s = bs->opaque; 273 BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, 274 nb_sectors, cb, opaque); 275 276 bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors, 277 blkverify_aio_cb, acb); 278 bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, 279 blkverify_aio_cb, acb); 280 return &acb->common; 281 } 282 283 static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs, 284 BlockDriverCompletionFunc *cb, 285 void *opaque) 286 { 287 BDRVBlkverifyState *s = bs->opaque; 288 289 /* Only flush test file, the raw file is not important */ 290 return bdrv_aio_flush(s->test_file, cb, opaque); 291 } 292 293 static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, 294 BlockDriverState *candidate) 295 { 296 BDRVBlkverifyState *s = bs->opaque; 297 298 bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate); 299 300 if (perm) { 301 return true; 302 } 303 304 return bdrv_recurse_is_first_non_filter(s->test_file, candidate); 305 } 306 307 /* Propagate AioContext changes to ->test_file */ 308 static void blkverify_detach_aio_context(BlockDriverState *bs) 309 { 310 BDRVBlkverifyState *s = bs->opaque; 311 312 bdrv_detach_aio_context(s->test_file); 313 } 314 315 static void blkverify_attach_aio_context(BlockDriverState *bs, 316 AioContext *new_context) 317 { 318 BDRVBlkverifyState *s = bs->opaque; 319 320 bdrv_attach_aio_context(s->test_file, new_context); 321 } 322 323 static BlockDriver bdrv_blkverify = { 324 .format_name = "blkverify", 325 .protocol_name = "blkverify", 326 .instance_size = sizeof(BDRVBlkverifyState), 327 328 .bdrv_parse_filename = blkverify_parse_filename, 329 .bdrv_file_open = blkverify_open, 330 .bdrv_close = blkverify_close, 331 .bdrv_getlength = blkverify_getlength, 332 333 .bdrv_aio_readv = blkverify_aio_readv, 334 .bdrv_aio_writev = blkverify_aio_writev, 335 .bdrv_aio_flush = blkverify_aio_flush, 336 337 .bdrv_attach_aio_context = blkverify_attach_aio_context, 338 .bdrv_detach_aio_context = blkverify_detach_aio_context, 339 340 .is_filter = true, 341 .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter, 342 }; 343 344 static void bdrv_blkverify_init(void) 345 { 346 bdrv_register(&bdrv_blkverify); 347 } 348 349 block_init(bdrv_blkverify_init); 350