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(options, "x-image", qstring_from_str(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(options, "x-image", qstring_from_str(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 fail_unref; 393 } 394 395 ret = 0; 396 goto out; 397 398 fail_unref: 399 bdrv_unref_child(bs, bs->file); 400 out: 401 if (ret < 0) { 402 g_free(s->config_file); 403 } 404 qemu_opts_del(opts); 405 return ret; 406 } 407 408 static int inject_error(BlockDriverState *bs, BlkdebugRule *rule) 409 { 410 BDRVBlkdebugState *s = bs->opaque; 411 int error = rule->options.inject.error; 412 bool immediately = rule->options.inject.immediately; 413 414 if (rule->options.inject.once) { 415 QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next); 416 remove_rule(rule); 417 } 418 419 if (!immediately) { 420 aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); 421 qemu_coroutine_yield(); 422 } 423 424 return -error; 425 } 426 427 static int coroutine_fn 428 blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 429 QEMUIOVector *qiov, int flags) 430 { 431 BDRVBlkdebugState *s = bs->opaque; 432 BlkdebugRule *rule = NULL; 433 434 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 435 uint64_t inject_offset = rule->options.inject.offset; 436 437 if (inject_offset == -1 || 438 (inject_offset >= offset && inject_offset < offset + bytes)) 439 { 440 break; 441 } 442 } 443 444 if (rule && rule->options.inject.error) { 445 return inject_error(bs, rule); 446 } 447 448 return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 449 } 450 451 static int coroutine_fn 452 blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 453 QEMUIOVector *qiov, int flags) 454 { 455 BDRVBlkdebugState *s = bs->opaque; 456 BlkdebugRule *rule = NULL; 457 458 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 459 uint64_t inject_offset = rule->options.inject.offset; 460 461 if (inject_offset == -1 || 462 (inject_offset >= offset && inject_offset < offset + bytes)) 463 { 464 break; 465 } 466 } 467 468 if (rule && rule->options.inject.error) { 469 return inject_error(bs, rule); 470 } 471 472 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 473 } 474 475 static int blkdebug_co_flush(BlockDriverState *bs) 476 { 477 BDRVBlkdebugState *s = bs->opaque; 478 BlkdebugRule *rule = NULL; 479 480 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 481 if (rule->options.inject.offset == -1) { 482 break; 483 } 484 } 485 486 if (rule && rule->options.inject.error) { 487 return inject_error(bs, rule); 488 } 489 490 return bdrv_co_flush(bs->file->bs); 491 } 492 493 494 static void blkdebug_close(BlockDriverState *bs) 495 { 496 BDRVBlkdebugState *s = bs->opaque; 497 BlkdebugRule *rule, *next; 498 int i; 499 500 for (i = 0; i < BLKDBG__MAX; i++) { 501 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 502 remove_rule(rule); 503 } 504 } 505 506 g_free(s->config_file); 507 } 508 509 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 510 { 511 BDRVBlkdebugState *s = bs->opaque; 512 BlkdebugSuspendedReq r; 513 514 r = (BlkdebugSuspendedReq) { 515 .co = qemu_coroutine_self(), 516 .tag = g_strdup(rule->options.suspend.tag), 517 }; 518 519 remove_rule(rule); 520 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 521 522 if (!qtest_enabled()) { 523 printf("blkdebug: Suspended request '%s'\n", r.tag); 524 } 525 qemu_coroutine_yield(); 526 if (!qtest_enabled()) { 527 printf("blkdebug: Resuming request '%s'\n", r.tag); 528 } 529 530 QLIST_REMOVE(&r, next); 531 g_free(r.tag); 532 } 533 534 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 535 bool injected) 536 { 537 BDRVBlkdebugState *s = bs->opaque; 538 539 /* Only process rules for the current state */ 540 if (rule->state && rule->state != s->state) { 541 return injected; 542 } 543 544 /* Take the action */ 545 switch (rule->action) { 546 case ACTION_INJECT_ERROR: 547 if (!injected) { 548 QSIMPLEQ_INIT(&s->active_rules); 549 injected = true; 550 } 551 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 552 break; 553 554 case ACTION_SET_STATE: 555 s->new_state = rule->options.set_state.new_state; 556 break; 557 558 case ACTION_SUSPEND: 559 suspend_request(bs, rule); 560 break; 561 } 562 return injected; 563 } 564 565 static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) 566 { 567 BDRVBlkdebugState *s = bs->opaque; 568 struct BlkdebugRule *rule, *next; 569 bool injected; 570 571 assert((int)event >= 0 && event < BLKDBG__MAX); 572 573 injected = false; 574 s->new_state = s->state; 575 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 576 injected = process_rule(bs, rule, injected); 577 } 578 s->state = s->new_state; 579 } 580 581 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 582 const char *tag) 583 { 584 BDRVBlkdebugState *s = bs->opaque; 585 struct BlkdebugRule *rule; 586 BlkdebugEvent blkdebug_event; 587 588 if (get_event_by_name(event, &blkdebug_event) < 0) { 589 return -ENOENT; 590 } 591 592 593 rule = g_malloc(sizeof(*rule)); 594 *rule = (struct BlkdebugRule) { 595 .event = blkdebug_event, 596 .action = ACTION_SUSPEND, 597 .state = 0, 598 .options.suspend.tag = g_strdup(tag), 599 }; 600 601 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 602 603 return 0; 604 } 605 606 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 607 { 608 BDRVBlkdebugState *s = bs->opaque; 609 BlkdebugSuspendedReq *r, *next; 610 611 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { 612 if (!strcmp(r->tag, tag)) { 613 qemu_coroutine_enter(r->co); 614 return 0; 615 } 616 } 617 return -ENOENT; 618 } 619 620 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, 621 const char *tag) 622 { 623 BDRVBlkdebugState *s = bs->opaque; 624 BlkdebugSuspendedReq *r, *r_next; 625 BlkdebugRule *rule, *next; 626 int i, ret = -ENOENT; 627 628 for (i = 0; i < BLKDBG__MAX; i++) { 629 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 630 if (rule->action == ACTION_SUSPEND && 631 !strcmp(rule->options.suspend.tag, tag)) { 632 remove_rule(rule); 633 ret = 0; 634 } 635 } 636 } 637 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { 638 if (!strcmp(r->tag, tag)) { 639 qemu_coroutine_enter(r->co); 640 ret = 0; 641 } 642 } 643 return ret; 644 } 645 646 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 647 { 648 BDRVBlkdebugState *s = bs->opaque; 649 BlkdebugSuspendedReq *r; 650 651 QLIST_FOREACH(r, &s->suspended_reqs, next) { 652 if (!strcmp(r->tag, tag)) { 653 return true; 654 } 655 } 656 return false; 657 } 658 659 static int64_t blkdebug_getlength(BlockDriverState *bs) 660 { 661 return bdrv_getlength(bs->file->bs); 662 } 663 664 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset) 665 { 666 return bdrv_truncate(bs->file, offset); 667 } 668 669 static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) 670 { 671 BDRVBlkdebugState *s = bs->opaque; 672 QDict *opts; 673 const QDictEntry *e; 674 bool force_json = false; 675 676 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 677 if (strcmp(qdict_entry_key(e), "config") && 678 strcmp(qdict_entry_key(e), "x-image")) 679 { 680 force_json = true; 681 break; 682 } 683 } 684 685 if (force_json && !bs->file->bs->full_open_options) { 686 /* The config file cannot be recreated, so creating a plain filename 687 * is impossible */ 688 return; 689 } 690 691 if (!force_json && bs->file->bs->exact_filename[0]) { 692 snprintf(bs->exact_filename, sizeof(bs->exact_filename), 693 "blkdebug:%s:%s", s->config_file ?: "", 694 bs->file->bs->exact_filename); 695 } 696 697 opts = qdict_new(); 698 qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug"))); 699 700 QINCREF(bs->file->bs->full_open_options); 701 qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options)); 702 703 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 704 if (strcmp(qdict_entry_key(e), "x-image")) { 705 qobject_incref(qdict_entry_value(e)); 706 qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); 707 } 708 } 709 710 bs->full_open_options = opts; 711 } 712 713 static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) 714 { 715 BDRVBlkdebugState *s = bs->opaque; 716 717 if (s->align) { 718 bs->bl.request_alignment = s->align; 719 } 720 } 721 722 static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, 723 BlockReopenQueue *queue, Error **errp) 724 { 725 return 0; 726 } 727 728 static BlockDriver bdrv_blkdebug = { 729 .format_name = "blkdebug", 730 .protocol_name = "blkdebug", 731 .instance_size = sizeof(BDRVBlkdebugState), 732 733 .bdrv_parse_filename = blkdebug_parse_filename, 734 .bdrv_file_open = blkdebug_open, 735 .bdrv_close = blkdebug_close, 736 .bdrv_reopen_prepare = blkdebug_reopen_prepare, 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