1 /* 2 * Block protocol for I/O error injection 3 * 4 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu-common.h" 26 #include "qemu/config-file.h" 27 #include "block/block_int.h" 28 #include "qemu/module.h" 29 30 typedef struct BDRVBlkdebugState { 31 int state; 32 int new_state; 33 34 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; 35 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 36 QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 37 } BDRVBlkdebugState; 38 39 typedef struct BlkdebugAIOCB { 40 BlockDriverAIOCB common; 41 QEMUBH *bh; 42 int ret; 43 } BlkdebugAIOCB; 44 45 typedef struct BlkdebugSuspendedReq { 46 Coroutine *co; 47 char *tag; 48 QLIST_ENTRY(BlkdebugSuspendedReq) next; 49 } BlkdebugSuspendedReq; 50 51 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); 52 53 static const AIOCBInfo blkdebug_aiocb_info = { 54 .aiocb_size = sizeof(BlkdebugAIOCB), 55 .cancel = blkdebug_aio_cancel, 56 }; 57 58 enum { 59 ACTION_INJECT_ERROR, 60 ACTION_SET_STATE, 61 ACTION_SUSPEND, 62 }; 63 64 typedef struct BlkdebugRule { 65 BlkDebugEvent event; 66 int action; 67 int state; 68 union { 69 struct { 70 int error; 71 int immediately; 72 int once; 73 int64_t sector; 74 } inject; 75 struct { 76 int new_state; 77 } set_state; 78 struct { 79 char *tag; 80 } suspend; 81 } options; 82 QLIST_ENTRY(BlkdebugRule) next; 83 QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 84 } BlkdebugRule; 85 86 static QemuOptsList inject_error_opts = { 87 .name = "inject-error", 88 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 89 .desc = { 90 { 91 .name = "event", 92 .type = QEMU_OPT_STRING, 93 }, 94 { 95 .name = "state", 96 .type = QEMU_OPT_NUMBER, 97 }, 98 { 99 .name = "errno", 100 .type = QEMU_OPT_NUMBER, 101 }, 102 { 103 .name = "sector", 104 .type = QEMU_OPT_NUMBER, 105 }, 106 { 107 .name = "once", 108 .type = QEMU_OPT_BOOL, 109 }, 110 { 111 .name = "immediately", 112 .type = QEMU_OPT_BOOL, 113 }, 114 { /* end of list */ } 115 }, 116 }; 117 118 static QemuOptsList set_state_opts = { 119 .name = "set-state", 120 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 121 .desc = { 122 { 123 .name = "event", 124 .type = QEMU_OPT_STRING, 125 }, 126 { 127 .name = "state", 128 .type = QEMU_OPT_NUMBER, 129 }, 130 { 131 .name = "new_state", 132 .type = QEMU_OPT_NUMBER, 133 }, 134 { /* end of list */ } 135 }, 136 }; 137 138 static QemuOptsList *config_groups[] = { 139 &inject_error_opts, 140 &set_state_opts, 141 NULL 142 }; 143 144 static const char *event_names[BLKDBG_EVENT_MAX] = { 145 [BLKDBG_L1_UPDATE] = "l1_update", 146 [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table", 147 [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table", 148 [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table", 149 150 [BLKDBG_L2_LOAD] = "l2_load", 151 [BLKDBG_L2_UPDATE] = "l2_update", 152 [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed", 153 [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read", 154 [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write", 155 156 [BLKDBG_READ_AIO] = "read_aio", 157 [BLKDBG_READ_BACKING_AIO] = "read_backing_aio", 158 [BLKDBG_READ_COMPRESSED] = "read_compressed", 159 160 [BLKDBG_WRITE_AIO] = "write_aio", 161 [BLKDBG_WRITE_COMPRESSED] = "write_compressed", 162 163 [BLKDBG_VMSTATE_LOAD] = "vmstate_load", 164 [BLKDBG_VMSTATE_SAVE] = "vmstate_save", 165 166 [BLKDBG_COW_READ] = "cow_read", 167 [BLKDBG_COW_WRITE] = "cow_write", 168 169 [BLKDBG_REFTABLE_LOAD] = "reftable_load", 170 [BLKDBG_REFTABLE_GROW] = "reftable_grow", 171 [BLKDBG_REFTABLE_UPDATE] = "reftable_update", 172 173 [BLKDBG_REFBLOCK_LOAD] = "refblock_load", 174 [BLKDBG_REFBLOCK_UPDATE] = "refblock_update", 175 [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part", 176 [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc", 177 [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup", 178 [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write", 179 [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks", 180 [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table", 181 [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table", 182 183 [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc", 184 [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", 185 [BLKDBG_CLUSTER_FREE] = "cluster_free", 186 187 [BLKDBG_FLUSH_TO_OS] = "flush_to_os", 188 [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk", 189 }; 190 191 static int get_event_by_name(const char *name, BlkDebugEvent *event) 192 { 193 int i; 194 195 for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 196 if (!strcmp(event_names[i], name)) { 197 *event = i; 198 return 0; 199 } 200 } 201 202 return -1; 203 } 204 205 struct add_rule_data { 206 BDRVBlkdebugState *s; 207 int action; 208 }; 209 210 static int add_rule(QemuOpts *opts, void *opaque) 211 { 212 struct add_rule_data *d = opaque; 213 BDRVBlkdebugState *s = d->s; 214 const char* event_name; 215 BlkDebugEvent event; 216 struct BlkdebugRule *rule; 217 218 /* Find the right event for the rule */ 219 event_name = qemu_opt_get(opts, "event"); 220 if (!event_name || get_event_by_name(event_name, &event) < 0) { 221 return -1; 222 } 223 224 /* Set attributes common for all actions */ 225 rule = g_malloc0(sizeof(*rule)); 226 *rule = (struct BlkdebugRule) { 227 .event = event, 228 .action = d->action, 229 .state = qemu_opt_get_number(opts, "state", 0), 230 }; 231 232 /* Parse action-specific options */ 233 switch (d->action) { 234 case ACTION_INJECT_ERROR: 235 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 236 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 237 rule->options.inject.immediately = 238 qemu_opt_get_bool(opts, "immediately", 0); 239 rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); 240 break; 241 242 case ACTION_SET_STATE: 243 rule->options.set_state.new_state = 244 qemu_opt_get_number(opts, "new_state", 0); 245 break; 246 247 case ACTION_SUSPEND: 248 rule->options.suspend.tag = 249 g_strdup(qemu_opt_get(opts, "tag")); 250 break; 251 }; 252 253 /* Add the rule */ 254 QLIST_INSERT_HEAD(&s->rules[event], rule, next); 255 256 return 0; 257 } 258 259 static void remove_rule(BlkdebugRule *rule) 260 { 261 switch (rule->action) { 262 case ACTION_INJECT_ERROR: 263 case ACTION_SET_STATE: 264 break; 265 case ACTION_SUSPEND: 266 g_free(rule->options.suspend.tag); 267 break; 268 } 269 270 QLIST_REMOVE(rule, next); 271 g_free(rule); 272 } 273 274 static int read_config(BDRVBlkdebugState *s, const char *filename) 275 { 276 FILE *f; 277 int ret; 278 struct add_rule_data d; 279 280 f = fopen(filename, "r"); 281 if (f == NULL) { 282 return -errno; 283 } 284 285 ret = qemu_config_parse(f, config_groups, filename); 286 if (ret < 0) { 287 goto fail; 288 } 289 290 d.s = s; 291 d.action = ACTION_INJECT_ERROR; 292 qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0); 293 294 d.action = ACTION_SET_STATE; 295 qemu_opts_foreach(&set_state_opts, add_rule, &d, 0); 296 297 ret = 0; 298 fail: 299 qemu_opts_reset(&inject_error_opts); 300 qemu_opts_reset(&set_state_opts); 301 fclose(f); 302 return ret; 303 } 304 305 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 306 static void blkdebug_parse_filename(const char *filename, QDict *options, 307 Error **errp) 308 { 309 const char *c; 310 311 /* Parse the blkdebug: prefix */ 312 if (!strstart(filename, "blkdebug:", &filename)) { 313 error_setg(errp, "File name string must start with 'blkdebug:'"); 314 return; 315 } 316 317 /* Parse config file path */ 318 c = strchr(filename, ':'); 319 if (c == NULL) { 320 error_setg(errp, "blkdebug requires both config file and image path"); 321 return; 322 } 323 324 if (c != filename) { 325 QString *config_path; 326 config_path = qstring_from_substr(filename, 0, c - filename - 1); 327 qdict_put(options, "config", config_path); 328 } 329 330 /* TODO Allow multi-level nesting and set file.filename here */ 331 filename = c + 1; 332 qdict_put(options, "x-image", qstring_from_str(filename)); 333 } 334 335 static QemuOptsList runtime_opts = { 336 .name = "blkdebug", 337 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 338 .desc = { 339 { 340 .name = "config", 341 .type = QEMU_OPT_STRING, 342 .help = "Path to the configuration file", 343 }, 344 { 345 .name = "x-image", 346 .type = QEMU_OPT_STRING, 347 .help = "[internal use only, will be removed]", 348 }, 349 { /* end of list */ } 350 }, 351 }; 352 353 static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags) 354 { 355 BDRVBlkdebugState *s = bs->opaque; 356 QemuOpts *opts; 357 Error *local_err = NULL; 358 const char *filename, *config; 359 int ret; 360 361 opts = qemu_opts_create_nofail(&runtime_opts); 362 qemu_opts_absorb_qdict(opts, options, &local_err); 363 if (error_is_set(&local_err)) { 364 qerror_report_err(local_err); 365 error_free(local_err); 366 ret = -EINVAL; 367 goto fail; 368 } 369 370 /* Read rules from config file */ 371 config = qemu_opt_get(opts, "config"); 372 if (config) { 373 ret = read_config(s, config); 374 if (ret < 0) { 375 goto fail; 376 } 377 } 378 379 /* Set initial state */ 380 s->state = 1; 381 382 /* Open the backing file */ 383 filename = qemu_opt_get(opts, "x-image"); 384 if (filename == NULL) { 385 ret = -EINVAL; 386 goto fail; 387 } 388 389 ret = bdrv_file_open(&bs->file, filename, NULL, flags); 390 if (ret < 0) { 391 goto fail; 392 } 393 394 ret = 0; 395 fail: 396 qemu_opts_del(opts); 397 return ret; 398 } 399 400 static void error_callback_bh(void *opaque) 401 { 402 struct BlkdebugAIOCB *acb = opaque; 403 qemu_bh_delete(acb->bh); 404 acb->common.cb(acb->common.opaque, acb->ret); 405 qemu_aio_release(acb); 406 } 407 408 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) 409 { 410 BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); 411 qemu_aio_release(acb); 412 } 413 414 static BlockDriverAIOCB *inject_error(BlockDriverState *bs, 415 BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule) 416 { 417 BDRVBlkdebugState *s = bs->opaque; 418 int error = rule->options.inject.error; 419 struct BlkdebugAIOCB *acb; 420 QEMUBH *bh; 421 422 if (rule->options.inject.once) { 423 QSIMPLEQ_INIT(&s->active_rules); 424 } 425 426 if (rule->options.inject.immediately) { 427 return NULL; 428 } 429 430 acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); 431 acb->ret = -error; 432 433 bh = qemu_bh_new(error_callback_bh, acb); 434 acb->bh = bh; 435 qemu_bh_schedule(bh); 436 437 return &acb->common; 438 } 439 440 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, 441 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 442 BlockDriverCompletionFunc *cb, void *opaque) 443 { 444 BDRVBlkdebugState *s = bs->opaque; 445 BlkdebugRule *rule = NULL; 446 447 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 448 if (rule->options.inject.sector == -1 || 449 (rule->options.inject.sector >= sector_num && 450 rule->options.inject.sector < sector_num + nb_sectors)) { 451 break; 452 } 453 } 454 455 if (rule && rule->options.inject.error) { 456 return inject_error(bs, cb, opaque, rule); 457 } 458 459 return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 460 } 461 462 static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, 463 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 464 BlockDriverCompletionFunc *cb, void *opaque) 465 { 466 BDRVBlkdebugState *s = bs->opaque; 467 BlkdebugRule *rule = NULL; 468 469 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 470 if (rule->options.inject.sector == -1 || 471 (rule->options.inject.sector >= sector_num && 472 rule->options.inject.sector < sector_num + nb_sectors)) { 473 break; 474 } 475 } 476 477 if (rule && rule->options.inject.error) { 478 return inject_error(bs, cb, opaque, rule); 479 } 480 481 return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 482 } 483 484 485 static void blkdebug_close(BlockDriverState *bs) 486 { 487 BDRVBlkdebugState *s = bs->opaque; 488 BlkdebugRule *rule, *next; 489 int i; 490 491 for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 492 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 493 remove_rule(rule); 494 } 495 } 496 } 497 498 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 499 { 500 BDRVBlkdebugState *s = bs->opaque; 501 BlkdebugSuspendedReq r; 502 503 r = (BlkdebugSuspendedReq) { 504 .co = qemu_coroutine_self(), 505 .tag = g_strdup(rule->options.suspend.tag), 506 }; 507 508 remove_rule(rule); 509 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 510 511 printf("blkdebug: Suspended request '%s'\n", r.tag); 512 qemu_coroutine_yield(); 513 printf("blkdebug: Resuming request '%s'\n", r.tag); 514 515 QLIST_REMOVE(&r, next); 516 g_free(r.tag); 517 } 518 519 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 520 bool injected) 521 { 522 BDRVBlkdebugState *s = bs->opaque; 523 524 /* Only process rules for the current state */ 525 if (rule->state && rule->state != s->state) { 526 return injected; 527 } 528 529 /* Take the action */ 530 switch (rule->action) { 531 case ACTION_INJECT_ERROR: 532 if (!injected) { 533 QSIMPLEQ_INIT(&s->active_rules); 534 injected = true; 535 } 536 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 537 break; 538 539 case ACTION_SET_STATE: 540 s->new_state = rule->options.set_state.new_state; 541 break; 542 543 case ACTION_SUSPEND: 544 suspend_request(bs, rule); 545 break; 546 } 547 return injected; 548 } 549 550 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) 551 { 552 BDRVBlkdebugState *s = bs->opaque; 553 struct BlkdebugRule *rule, *next; 554 bool injected; 555 556 assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); 557 558 injected = false; 559 s->new_state = s->state; 560 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 561 injected = process_rule(bs, rule, injected); 562 } 563 s->state = s->new_state; 564 } 565 566 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 567 const char *tag) 568 { 569 BDRVBlkdebugState *s = bs->opaque; 570 struct BlkdebugRule *rule; 571 BlkDebugEvent blkdebug_event; 572 573 if (get_event_by_name(event, &blkdebug_event) < 0) { 574 return -ENOENT; 575 } 576 577 578 rule = g_malloc(sizeof(*rule)); 579 *rule = (struct BlkdebugRule) { 580 .event = blkdebug_event, 581 .action = ACTION_SUSPEND, 582 .state = 0, 583 .options.suspend.tag = g_strdup(tag), 584 }; 585 586 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 587 588 return 0; 589 } 590 591 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 592 { 593 BDRVBlkdebugState *s = bs->opaque; 594 BlkdebugSuspendedReq *r; 595 596 QLIST_FOREACH(r, &s->suspended_reqs, next) { 597 if (!strcmp(r->tag, tag)) { 598 qemu_coroutine_enter(r->co, NULL); 599 return 0; 600 } 601 } 602 return -ENOENT; 603 } 604 605 606 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 607 { 608 BDRVBlkdebugState *s = bs->opaque; 609 BlkdebugSuspendedReq *r; 610 611 QLIST_FOREACH(r, &s->suspended_reqs, next) { 612 if (!strcmp(r->tag, tag)) { 613 return true; 614 } 615 } 616 return false; 617 } 618 619 static int64_t blkdebug_getlength(BlockDriverState *bs) 620 { 621 return bdrv_getlength(bs->file); 622 } 623 624 static BlockDriver bdrv_blkdebug = { 625 .format_name = "blkdebug", 626 .protocol_name = "blkdebug", 627 .instance_size = sizeof(BDRVBlkdebugState), 628 629 .bdrv_parse_filename = blkdebug_parse_filename, 630 .bdrv_file_open = blkdebug_open, 631 .bdrv_close = blkdebug_close, 632 .bdrv_getlength = blkdebug_getlength, 633 634 .bdrv_aio_readv = blkdebug_aio_readv, 635 .bdrv_aio_writev = blkdebug_aio_writev, 636 637 .bdrv_debug_event = blkdebug_debug_event, 638 .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 639 .bdrv_debug_resume = blkdebug_debug_resume, 640 .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 641 }; 642 643 static void bdrv_blkdebug_init(void) 644 { 645 bdrv_register(&bdrv_blkdebug); 646 } 647 648 block_init(bdrv_blkdebug_init); 649