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/osdep.h" 26 #include "qapi/error.h" 27 #include "qemu/cutils.h" 28 #include "qemu/config-file.h" 29 #include "block/block_int.h" 30 #include "qemu/module.h" 31 #include "qapi/qmp/qbool.h" 32 #include "qapi/qmp/qdict.h" 33 #include "qapi/qmp/qint.h" 34 #include "qapi/qmp/qstring.h" 35 #include "sysemu/qtest.h" 36 37 typedef struct BDRVBlkdebugState { 38 int state; 39 int new_state; 40 int align; 41 42 /* For blkdebug_refresh_filename() */ 43 char *config_file; 44 45 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX]; 46 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 47 QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 48 } BDRVBlkdebugState; 49 50 typedef struct BlkdebugAIOCB { 51 BlockAIOCB common; 52 int ret; 53 } BlkdebugAIOCB; 54 55 typedef struct BlkdebugSuspendedReq { 56 Coroutine *co; 57 char *tag; 58 QLIST_ENTRY(BlkdebugSuspendedReq) next; 59 } BlkdebugSuspendedReq; 60 61 enum { 62 ACTION_INJECT_ERROR, 63 ACTION_SET_STATE, 64 ACTION_SUSPEND, 65 }; 66 67 typedef struct BlkdebugRule { 68 BlkdebugEvent event; 69 int action; 70 int state; 71 union { 72 struct { 73 int error; 74 int immediately; 75 int once; 76 int64_t offset; 77 } inject; 78 struct { 79 int new_state; 80 } set_state; 81 struct { 82 char *tag; 83 } suspend; 84 } options; 85 QLIST_ENTRY(BlkdebugRule) next; 86 QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 87 } BlkdebugRule; 88 89 static QemuOptsList inject_error_opts = { 90 .name = "inject-error", 91 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 92 .desc = { 93 { 94 .name = "event", 95 .type = QEMU_OPT_STRING, 96 }, 97 { 98 .name = "state", 99 .type = QEMU_OPT_NUMBER, 100 }, 101 { 102 .name = "errno", 103 .type = QEMU_OPT_NUMBER, 104 }, 105 { 106 .name = "sector", 107 .type = QEMU_OPT_NUMBER, 108 }, 109 { 110 .name = "once", 111 .type = QEMU_OPT_BOOL, 112 }, 113 { 114 .name = "immediately", 115 .type = QEMU_OPT_BOOL, 116 }, 117 { /* end of list */ } 118 }, 119 }; 120 121 static QemuOptsList set_state_opts = { 122 .name = "set-state", 123 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 124 .desc = { 125 { 126 .name = "event", 127 .type = QEMU_OPT_STRING, 128 }, 129 { 130 .name = "state", 131 .type = QEMU_OPT_NUMBER, 132 }, 133 { 134 .name = "new_state", 135 .type = QEMU_OPT_NUMBER, 136 }, 137 { /* end of list */ } 138 }, 139 }; 140 141 static QemuOptsList *config_groups[] = { 142 &inject_error_opts, 143 &set_state_opts, 144 NULL 145 }; 146 147 static int get_event_by_name(const char *name, BlkdebugEvent *event) 148 { 149 int i; 150 151 for (i = 0; i < BLKDBG__MAX; i++) { 152 if (!strcmp(BlkdebugEvent_lookup[i], name)) { 153 *event = i; 154 return 0; 155 } 156 } 157 158 return -1; 159 } 160 161 struct add_rule_data { 162 BDRVBlkdebugState *s; 163 int action; 164 }; 165 166 static int add_rule(void *opaque, QemuOpts *opts, Error **errp) 167 { 168 struct add_rule_data *d = opaque; 169 BDRVBlkdebugState *s = d->s; 170 const char* event_name; 171 BlkdebugEvent event; 172 struct BlkdebugRule *rule; 173 int64_t sector; 174 175 /* Find the right event for the rule */ 176 event_name = qemu_opt_get(opts, "event"); 177 if (!event_name) { 178 error_setg(errp, "Missing event name for rule"); 179 return -1; 180 } else if (get_event_by_name(event_name, &event) < 0) { 181 error_setg(errp, "Invalid event name \"%s\"", event_name); 182 return -1; 183 } 184 185 /* Set attributes common for all actions */ 186 rule = g_malloc0(sizeof(*rule)); 187 *rule = (struct BlkdebugRule) { 188 .event = event, 189 .action = d->action, 190 .state = qemu_opt_get_number(opts, "state", 0), 191 }; 192 193 /* Parse action-specific options */ 194 switch (d->action) { 195 case ACTION_INJECT_ERROR: 196 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 197 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 198 rule->options.inject.immediately = 199 qemu_opt_get_bool(opts, "immediately", 0); 200 sector = qemu_opt_get_number(opts, "sector", -1); 201 rule->options.inject.offset = 202 sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; 203 break; 204 205 case ACTION_SET_STATE: 206 rule->options.set_state.new_state = 207 qemu_opt_get_number(opts, "new_state", 0); 208 break; 209 210 case ACTION_SUSPEND: 211 rule->options.suspend.tag = 212 g_strdup(qemu_opt_get(opts, "tag")); 213 break; 214 }; 215 216 /* Add the rule */ 217 QLIST_INSERT_HEAD(&s->rules[event], rule, next); 218 219 return 0; 220 } 221 222 static void remove_rule(BlkdebugRule *rule) 223 { 224 switch (rule->action) { 225 case ACTION_INJECT_ERROR: 226 case ACTION_SET_STATE: 227 break; 228 case ACTION_SUSPEND: 229 g_free(rule->options.suspend.tag); 230 break; 231 } 232 233 QLIST_REMOVE(rule, next); 234 g_free(rule); 235 } 236 237 static int read_config(BDRVBlkdebugState *s, const char *filename, 238 QDict *options, Error **errp) 239 { 240 FILE *f = NULL; 241 int ret; 242 struct add_rule_data d; 243 Error *local_err = NULL; 244 245 if (filename) { 246 f = fopen(filename, "r"); 247 if (f == NULL) { 248 error_setg_errno(errp, errno, "Could not read blkdebug config file"); 249 return -errno; 250 } 251 252 ret = qemu_config_parse(f, config_groups, filename); 253 if (ret < 0) { 254 error_setg(errp, "Could not parse blkdebug config file"); 255 ret = -EINVAL; 256 goto fail; 257 } 258 } 259 260 qemu_config_parse_qdict(options, config_groups, &local_err); 261 if (local_err) { 262 error_propagate(errp, local_err); 263 ret = -EINVAL; 264 goto fail; 265 } 266 267 d.s = s; 268 d.action = ACTION_INJECT_ERROR; 269 qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err); 270 if (local_err) { 271 error_propagate(errp, local_err); 272 ret = -EINVAL; 273 goto fail; 274 } 275 276 d.action = ACTION_SET_STATE; 277 qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err); 278 if (local_err) { 279 error_propagate(errp, local_err); 280 ret = -EINVAL; 281 goto fail; 282 } 283 284 ret = 0; 285 fail: 286 qemu_opts_reset(&inject_error_opts); 287 qemu_opts_reset(&set_state_opts); 288 if (f) { 289 fclose(f); 290 } 291 return ret; 292 } 293 294 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 295 static void blkdebug_parse_filename(const char *filename, QDict *options, 296 Error **errp) 297 { 298 const char *c; 299 300 /* Parse the blkdebug: prefix */ 301 if (!strstart(filename, "blkdebug:", &filename)) { 302 /* There was no prefix; therefore, all options have to be already 303 present in the QDict (except for the filename) */ 304 qdict_put_str(options, "x-image", filename); 305 return; 306 } 307 308 /* Parse config file path */ 309 c = strchr(filename, ':'); 310 if (c == NULL) { 311 error_setg(errp, "blkdebug requires both config file and image path"); 312 return; 313 } 314 315 if (c != filename) { 316 QString *config_path; 317 config_path = qstring_from_substr(filename, 0, c - filename - 1); 318 qdict_put(options, "config", config_path); 319 } 320 321 /* TODO Allow multi-level nesting and set file.filename here */ 322 filename = c + 1; 323 qdict_put_str(options, "x-image", filename); 324 } 325 326 static QemuOptsList runtime_opts = { 327 .name = "blkdebug", 328 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 329 .desc = { 330 { 331 .name = "config", 332 .type = QEMU_OPT_STRING, 333 .help = "Path to the configuration file", 334 }, 335 { 336 .name = "x-image", 337 .type = QEMU_OPT_STRING, 338 .help = "[internal use only, will be removed]", 339 }, 340 { 341 .name = "align", 342 .type = QEMU_OPT_SIZE, 343 .help = "Required alignment in bytes", 344 }, 345 { /* end of list */ } 346 }, 347 }; 348 349 static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, 350 Error **errp) 351 { 352 BDRVBlkdebugState *s = bs->opaque; 353 QemuOpts *opts; 354 Error *local_err = NULL; 355 uint64_t align; 356 int ret; 357 358 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 359 qemu_opts_absorb_qdict(opts, options, &local_err); 360 if (local_err) { 361 error_propagate(errp, local_err); 362 ret = -EINVAL; 363 goto out; 364 } 365 366 /* Read rules from config file or command line options */ 367 s->config_file = g_strdup(qemu_opt_get(opts, "config")); 368 ret = read_config(s, s->config_file, options, errp); 369 if (ret) { 370 goto out; 371 } 372 373 /* Set initial state */ 374 s->state = 1; 375 376 /* Open the image file */ 377 bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", 378 bs, &child_file, false, &local_err); 379 if (local_err) { 380 ret = -EINVAL; 381 error_propagate(errp, local_err); 382 goto out; 383 } 384 385 /* Set request alignment */ 386 align = qemu_opt_get_size(opts, "align", 0); 387 if (align < INT_MAX && is_power_of_2(align)) { 388 s->align = align; 389 } else if (align) { 390 error_setg(errp, "Invalid alignment"); 391 ret = -EINVAL; 392 goto out; 393 } 394 395 ret = 0; 396 goto out; 397 398 out: 399 if (ret < 0) { 400 g_free(s->config_file); 401 } 402 qemu_opts_del(opts); 403 return ret; 404 } 405 406 static int inject_error(BlockDriverState *bs, BlkdebugRule *rule) 407 { 408 BDRVBlkdebugState *s = bs->opaque; 409 int error = rule->options.inject.error; 410 bool immediately = rule->options.inject.immediately; 411 412 if (rule->options.inject.once) { 413 QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next); 414 remove_rule(rule); 415 } 416 417 if (!immediately) { 418 aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); 419 qemu_coroutine_yield(); 420 } 421 422 return -error; 423 } 424 425 static int coroutine_fn 426 blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 427 QEMUIOVector *qiov, int flags) 428 { 429 BDRVBlkdebugState *s = bs->opaque; 430 BlkdebugRule *rule = NULL; 431 432 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 433 uint64_t inject_offset = rule->options.inject.offset; 434 435 if (inject_offset == -1 || 436 (inject_offset >= offset && inject_offset < offset + bytes)) 437 { 438 break; 439 } 440 } 441 442 if (rule && rule->options.inject.error) { 443 return inject_error(bs, rule); 444 } 445 446 return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 447 } 448 449 static int coroutine_fn 450 blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 451 QEMUIOVector *qiov, int flags) 452 { 453 BDRVBlkdebugState *s = bs->opaque; 454 BlkdebugRule *rule = NULL; 455 456 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 457 uint64_t inject_offset = rule->options.inject.offset; 458 459 if (inject_offset == -1 || 460 (inject_offset >= offset && inject_offset < offset + bytes)) 461 { 462 break; 463 } 464 } 465 466 if (rule && rule->options.inject.error) { 467 return inject_error(bs, rule); 468 } 469 470 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 471 } 472 473 static int blkdebug_co_flush(BlockDriverState *bs) 474 { 475 BDRVBlkdebugState *s = bs->opaque; 476 BlkdebugRule *rule = NULL; 477 478 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 479 if (rule->options.inject.offset == -1) { 480 break; 481 } 482 } 483 484 if (rule && rule->options.inject.error) { 485 return inject_error(bs, rule); 486 } 487 488 return bdrv_co_flush(bs->file->bs); 489 } 490 491 492 static void blkdebug_close(BlockDriverState *bs) 493 { 494 BDRVBlkdebugState *s = bs->opaque; 495 BlkdebugRule *rule, *next; 496 int i; 497 498 for (i = 0; i < BLKDBG__MAX; i++) { 499 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 500 remove_rule(rule); 501 } 502 } 503 504 g_free(s->config_file); 505 } 506 507 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 508 { 509 BDRVBlkdebugState *s = bs->opaque; 510 BlkdebugSuspendedReq r; 511 512 r = (BlkdebugSuspendedReq) { 513 .co = qemu_coroutine_self(), 514 .tag = g_strdup(rule->options.suspend.tag), 515 }; 516 517 remove_rule(rule); 518 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 519 520 if (!qtest_enabled()) { 521 printf("blkdebug: Suspended request '%s'\n", r.tag); 522 } 523 qemu_coroutine_yield(); 524 if (!qtest_enabled()) { 525 printf("blkdebug: Resuming request '%s'\n", r.tag); 526 } 527 528 QLIST_REMOVE(&r, next); 529 g_free(r.tag); 530 } 531 532 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 533 bool injected) 534 { 535 BDRVBlkdebugState *s = bs->opaque; 536 537 /* Only process rules for the current state */ 538 if (rule->state && rule->state != s->state) { 539 return injected; 540 } 541 542 /* Take the action */ 543 switch (rule->action) { 544 case ACTION_INJECT_ERROR: 545 if (!injected) { 546 QSIMPLEQ_INIT(&s->active_rules); 547 injected = true; 548 } 549 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 550 break; 551 552 case ACTION_SET_STATE: 553 s->new_state = rule->options.set_state.new_state; 554 break; 555 556 case ACTION_SUSPEND: 557 suspend_request(bs, rule); 558 break; 559 } 560 return injected; 561 } 562 563 static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) 564 { 565 BDRVBlkdebugState *s = bs->opaque; 566 struct BlkdebugRule *rule, *next; 567 bool injected; 568 569 assert((int)event >= 0 && event < BLKDBG__MAX); 570 571 injected = false; 572 s->new_state = s->state; 573 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 574 injected = process_rule(bs, rule, injected); 575 } 576 s->state = s->new_state; 577 } 578 579 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 580 const char *tag) 581 { 582 BDRVBlkdebugState *s = bs->opaque; 583 struct BlkdebugRule *rule; 584 BlkdebugEvent blkdebug_event; 585 586 if (get_event_by_name(event, &blkdebug_event) < 0) { 587 return -ENOENT; 588 } 589 590 591 rule = g_malloc(sizeof(*rule)); 592 *rule = (struct BlkdebugRule) { 593 .event = blkdebug_event, 594 .action = ACTION_SUSPEND, 595 .state = 0, 596 .options.suspend.tag = g_strdup(tag), 597 }; 598 599 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 600 601 return 0; 602 } 603 604 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 605 { 606 BDRVBlkdebugState *s = bs->opaque; 607 BlkdebugSuspendedReq *r, *next; 608 609 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { 610 if (!strcmp(r->tag, tag)) { 611 qemu_coroutine_enter(r->co); 612 return 0; 613 } 614 } 615 return -ENOENT; 616 } 617 618 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, 619 const char *tag) 620 { 621 BDRVBlkdebugState *s = bs->opaque; 622 BlkdebugSuspendedReq *r, *r_next; 623 BlkdebugRule *rule, *next; 624 int i, ret = -ENOENT; 625 626 for (i = 0; i < BLKDBG__MAX; i++) { 627 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 628 if (rule->action == ACTION_SUSPEND && 629 !strcmp(rule->options.suspend.tag, tag)) { 630 remove_rule(rule); 631 ret = 0; 632 } 633 } 634 } 635 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { 636 if (!strcmp(r->tag, tag)) { 637 qemu_coroutine_enter(r->co); 638 ret = 0; 639 } 640 } 641 return ret; 642 } 643 644 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 645 { 646 BDRVBlkdebugState *s = bs->opaque; 647 BlkdebugSuspendedReq *r; 648 649 QLIST_FOREACH(r, &s->suspended_reqs, next) { 650 if (!strcmp(r->tag, tag)) { 651 return true; 652 } 653 } 654 return false; 655 } 656 657 static int64_t blkdebug_getlength(BlockDriverState *bs) 658 { 659 return bdrv_getlength(bs->file->bs); 660 } 661 662 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp) 663 { 664 return bdrv_truncate(bs->file, offset, errp); 665 } 666 667 static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) 668 { 669 BDRVBlkdebugState *s = bs->opaque; 670 QDict *opts; 671 const QDictEntry *e; 672 bool force_json = false; 673 674 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 675 if (strcmp(qdict_entry_key(e), "config") && 676 strcmp(qdict_entry_key(e), "x-image")) 677 { 678 force_json = true; 679 break; 680 } 681 } 682 683 if (force_json && !bs->file->bs->full_open_options) { 684 /* The config file cannot be recreated, so creating a plain filename 685 * is impossible */ 686 return; 687 } 688 689 if (!force_json && bs->file->bs->exact_filename[0]) { 690 snprintf(bs->exact_filename, sizeof(bs->exact_filename), 691 "blkdebug:%s:%s", s->config_file ?: "", 692 bs->file->bs->exact_filename); 693 } 694 695 opts = qdict_new(); 696 qdict_put_str(opts, "driver", "blkdebug"); 697 698 QINCREF(bs->file->bs->full_open_options); 699 qdict_put(opts, "image", bs->file->bs->full_open_options); 700 701 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 702 if (strcmp(qdict_entry_key(e), "x-image")) { 703 qobject_incref(qdict_entry_value(e)); 704 qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); 705 } 706 } 707 708 bs->full_open_options = opts; 709 } 710 711 static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) 712 { 713 BDRVBlkdebugState *s = bs->opaque; 714 715 if (s->align) { 716 bs->bl.request_alignment = s->align; 717 } 718 } 719 720 static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, 721 BlockReopenQueue *queue, Error **errp) 722 { 723 return 0; 724 } 725 726 static BlockDriver bdrv_blkdebug = { 727 .format_name = "blkdebug", 728 .protocol_name = "blkdebug", 729 .instance_size = sizeof(BDRVBlkdebugState), 730 731 .bdrv_parse_filename = blkdebug_parse_filename, 732 .bdrv_file_open = blkdebug_open, 733 .bdrv_close = blkdebug_close, 734 .bdrv_reopen_prepare = blkdebug_reopen_prepare, 735 .bdrv_child_perm = bdrv_filter_default_perms, 736 737 .bdrv_getlength = blkdebug_getlength, 738 .bdrv_truncate = blkdebug_truncate, 739 .bdrv_refresh_filename = blkdebug_refresh_filename, 740 .bdrv_refresh_limits = blkdebug_refresh_limits, 741 742 .bdrv_co_preadv = blkdebug_co_preadv, 743 .bdrv_co_pwritev = blkdebug_co_pwritev, 744 .bdrv_co_flush_to_disk = blkdebug_co_flush, 745 746 .bdrv_debug_event = blkdebug_debug_event, 747 .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 748 .bdrv_debug_remove_breakpoint 749 = blkdebug_debug_remove_breakpoint, 750 .bdrv_debug_resume = blkdebug_debug_resume, 751 .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 752 }; 753 754 static void bdrv_blkdebug_init(void) 755 { 756 bdrv_register(&bdrv_blkdebug); 757 } 758 759 block_init(bdrv_blkdebug_init); 760