1 /* 2 * Block protocol for I/O error injection 3 * 4 * Copyright (C) 2016-2017 Red Hat, Inc. 5 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 #include "qemu/osdep.h" 27 #include "qapi/error.h" 28 #include "qemu/cutils.h" 29 #include "qemu/config-file.h" 30 #include "block/block_int.h" 31 #include "qemu/module.h" 32 #include "qapi/qmp/qbool.h" 33 #include "qapi/qmp/qdict.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 uint64_t align; 41 uint64_t max_transfer; 42 uint64_t opt_write_zero; 43 uint64_t max_write_zero; 44 uint64_t opt_discard; 45 uint64_t max_discard; 46 47 /* For blkdebug_refresh_filename() */ 48 char *config_file; 49 50 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX]; 51 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 52 QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 53 } BDRVBlkdebugState; 54 55 typedef struct BlkdebugAIOCB { 56 BlockAIOCB common; 57 int ret; 58 } BlkdebugAIOCB; 59 60 typedef struct BlkdebugSuspendedReq { 61 Coroutine *co; 62 char *tag; 63 QLIST_ENTRY(BlkdebugSuspendedReq) next; 64 } BlkdebugSuspendedReq; 65 66 enum { 67 ACTION_INJECT_ERROR, 68 ACTION_SET_STATE, 69 ACTION_SUSPEND, 70 }; 71 72 typedef struct BlkdebugRule { 73 BlkdebugEvent event; 74 int action; 75 int state; 76 union { 77 struct { 78 int error; 79 int immediately; 80 int once; 81 int64_t offset; 82 } inject; 83 struct { 84 int new_state; 85 } set_state; 86 struct { 87 char *tag; 88 } suspend; 89 } options; 90 QLIST_ENTRY(BlkdebugRule) next; 91 QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 92 } BlkdebugRule; 93 94 static QemuOptsList inject_error_opts = { 95 .name = "inject-error", 96 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 97 .desc = { 98 { 99 .name = "event", 100 .type = QEMU_OPT_STRING, 101 }, 102 { 103 .name = "state", 104 .type = QEMU_OPT_NUMBER, 105 }, 106 { 107 .name = "errno", 108 .type = QEMU_OPT_NUMBER, 109 }, 110 { 111 .name = "sector", 112 .type = QEMU_OPT_NUMBER, 113 }, 114 { 115 .name = "once", 116 .type = QEMU_OPT_BOOL, 117 }, 118 { 119 .name = "immediately", 120 .type = QEMU_OPT_BOOL, 121 }, 122 { /* end of list */ } 123 }, 124 }; 125 126 static QemuOptsList set_state_opts = { 127 .name = "set-state", 128 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 129 .desc = { 130 { 131 .name = "event", 132 .type = QEMU_OPT_STRING, 133 }, 134 { 135 .name = "state", 136 .type = QEMU_OPT_NUMBER, 137 }, 138 { 139 .name = "new_state", 140 .type = QEMU_OPT_NUMBER, 141 }, 142 { /* end of list */ } 143 }, 144 }; 145 146 static QemuOptsList *config_groups[] = { 147 &inject_error_opts, 148 &set_state_opts, 149 NULL 150 }; 151 152 static int get_event_by_name(const char *name, BlkdebugEvent *event) 153 { 154 int i; 155 156 for (i = 0; i < BLKDBG__MAX; i++) { 157 if (!strcmp(BlkdebugEvent_lookup[i], name)) { 158 *event = i; 159 return 0; 160 } 161 } 162 163 return -1; 164 } 165 166 struct add_rule_data { 167 BDRVBlkdebugState *s; 168 int action; 169 }; 170 171 static int add_rule(void *opaque, QemuOpts *opts, Error **errp) 172 { 173 struct add_rule_data *d = opaque; 174 BDRVBlkdebugState *s = d->s; 175 const char* event_name; 176 BlkdebugEvent event; 177 struct BlkdebugRule *rule; 178 int64_t sector; 179 180 /* Find the right event for the rule */ 181 event_name = qemu_opt_get(opts, "event"); 182 if (!event_name) { 183 error_setg(errp, "Missing event name for rule"); 184 return -1; 185 } else if (get_event_by_name(event_name, &event) < 0) { 186 error_setg(errp, "Invalid event name \"%s\"", event_name); 187 return -1; 188 } 189 190 /* Set attributes common for all actions */ 191 rule = g_malloc0(sizeof(*rule)); 192 *rule = (struct BlkdebugRule) { 193 .event = event, 194 .action = d->action, 195 .state = qemu_opt_get_number(opts, "state", 0), 196 }; 197 198 /* Parse action-specific options */ 199 switch (d->action) { 200 case ACTION_INJECT_ERROR: 201 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 202 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 203 rule->options.inject.immediately = 204 qemu_opt_get_bool(opts, "immediately", 0); 205 sector = qemu_opt_get_number(opts, "sector", -1); 206 rule->options.inject.offset = 207 sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; 208 break; 209 210 case ACTION_SET_STATE: 211 rule->options.set_state.new_state = 212 qemu_opt_get_number(opts, "new_state", 0); 213 break; 214 215 case ACTION_SUSPEND: 216 rule->options.suspend.tag = 217 g_strdup(qemu_opt_get(opts, "tag")); 218 break; 219 }; 220 221 /* Add the rule */ 222 QLIST_INSERT_HEAD(&s->rules[event], rule, next); 223 224 return 0; 225 } 226 227 static void remove_rule(BlkdebugRule *rule) 228 { 229 switch (rule->action) { 230 case ACTION_INJECT_ERROR: 231 case ACTION_SET_STATE: 232 break; 233 case ACTION_SUSPEND: 234 g_free(rule->options.suspend.tag); 235 break; 236 } 237 238 QLIST_REMOVE(rule, next); 239 g_free(rule); 240 } 241 242 static int read_config(BDRVBlkdebugState *s, const char *filename, 243 QDict *options, Error **errp) 244 { 245 FILE *f = NULL; 246 int ret; 247 struct add_rule_data d; 248 Error *local_err = NULL; 249 250 if (filename) { 251 f = fopen(filename, "r"); 252 if (f == NULL) { 253 error_setg_errno(errp, errno, "Could not read blkdebug config file"); 254 return -errno; 255 } 256 257 ret = qemu_config_parse(f, config_groups, filename); 258 if (ret < 0) { 259 error_setg(errp, "Could not parse blkdebug config file"); 260 ret = -EINVAL; 261 goto fail; 262 } 263 } 264 265 qemu_config_parse_qdict(options, config_groups, &local_err); 266 if (local_err) { 267 error_propagate(errp, local_err); 268 ret = -EINVAL; 269 goto fail; 270 } 271 272 d.s = s; 273 d.action = ACTION_INJECT_ERROR; 274 qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err); 275 if (local_err) { 276 error_propagate(errp, local_err); 277 ret = -EINVAL; 278 goto fail; 279 } 280 281 d.action = ACTION_SET_STATE; 282 qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err); 283 if (local_err) { 284 error_propagate(errp, local_err); 285 ret = -EINVAL; 286 goto fail; 287 } 288 289 ret = 0; 290 fail: 291 qemu_opts_reset(&inject_error_opts); 292 qemu_opts_reset(&set_state_opts); 293 if (f) { 294 fclose(f); 295 } 296 return ret; 297 } 298 299 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 300 static void blkdebug_parse_filename(const char *filename, QDict *options, 301 Error **errp) 302 { 303 const char *c; 304 305 /* Parse the blkdebug: prefix */ 306 if (!strstart(filename, "blkdebug:", &filename)) { 307 /* There was no prefix; therefore, all options have to be already 308 present in the QDict (except for the filename) */ 309 qdict_put_str(options, "x-image", filename); 310 return; 311 } 312 313 /* Parse config file path */ 314 c = strchr(filename, ':'); 315 if (c == NULL) { 316 error_setg(errp, "blkdebug requires both config file and image path"); 317 return; 318 } 319 320 if (c != filename) { 321 QString *config_path; 322 config_path = qstring_from_substr(filename, 0, c - filename - 1); 323 qdict_put(options, "config", config_path); 324 } 325 326 /* TODO Allow multi-level nesting and set file.filename here */ 327 filename = c + 1; 328 qdict_put_str(options, "x-image", filename); 329 } 330 331 static QemuOptsList runtime_opts = { 332 .name = "blkdebug", 333 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 334 .desc = { 335 { 336 .name = "config", 337 .type = QEMU_OPT_STRING, 338 .help = "Path to the configuration file", 339 }, 340 { 341 .name = "x-image", 342 .type = QEMU_OPT_STRING, 343 .help = "[internal use only, will be removed]", 344 }, 345 { 346 .name = "align", 347 .type = QEMU_OPT_SIZE, 348 .help = "Required alignment in bytes", 349 }, 350 { 351 .name = "max-transfer", 352 .type = QEMU_OPT_SIZE, 353 .help = "Maximum transfer size in bytes", 354 }, 355 { 356 .name = "opt-write-zero", 357 .type = QEMU_OPT_SIZE, 358 .help = "Optimum write zero alignment in bytes", 359 }, 360 { 361 .name = "max-write-zero", 362 .type = QEMU_OPT_SIZE, 363 .help = "Maximum write zero size in bytes", 364 }, 365 { 366 .name = "opt-discard", 367 .type = QEMU_OPT_SIZE, 368 .help = "Optimum discard alignment in bytes", 369 }, 370 { 371 .name = "max-discard", 372 .type = QEMU_OPT_SIZE, 373 .help = "Maximum discard size in bytes", 374 }, 375 { /* end of list */ } 376 }, 377 }; 378 379 static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, 380 Error **errp) 381 { 382 BDRVBlkdebugState *s = bs->opaque; 383 QemuOpts *opts; 384 Error *local_err = NULL; 385 int ret; 386 uint64_t align; 387 388 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 389 qemu_opts_absorb_qdict(opts, options, &local_err); 390 if (local_err) { 391 error_propagate(errp, local_err); 392 ret = -EINVAL; 393 goto out; 394 } 395 396 /* Read rules from config file or command line options */ 397 s->config_file = g_strdup(qemu_opt_get(opts, "config")); 398 ret = read_config(s, s->config_file, options, errp); 399 if (ret) { 400 goto out; 401 } 402 403 /* Set initial state */ 404 s->state = 1; 405 406 /* Open the image file */ 407 bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", 408 bs, &child_file, false, &local_err); 409 if (local_err) { 410 ret = -EINVAL; 411 error_propagate(errp, local_err); 412 goto out; 413 } 414 415 bs->supported_write_flags = BDRV_REQ_FUA & 416 bs->file->bs->supported_write_flags; 417 bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & 418 bs->file->bs->supported_zero_flags; 419 ret = -EINVAL; 420 421 /* Set alignment overrides */ 422 s->align = qemu_opt_get_size(opts, "align", 0); 423 if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) { 424 error_setg(errp, "Cannot meet constraints with align %" PRIu64, 425 s->align); 426 goto out; 427 } 428 align = MAX(s->align, bs->file->bs->bl.request_alignment); 429 430 s->max_transfer = qemu_opt_get_size(opts, "max-transfer", 0); 431 if (s->max_transfer && 432 (s->max_transfer >= INT_MAX || 433 !QEMU_IS_ALIGNED(s->max_transfer, align))) { 434 error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64, 435 s->max_transfer); 436 goto out; 437 } 438 439 s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0); 440 if (s->opt_write_zero && 441 (s->opt_write_zero >= INT_MAX || 442 !QEMU_IS_ALIGNED(s->opt_write_zero, align))) { 443 error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64, 444 s->opt_write_zero); 445 goto out; 446 } 447 448 s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0); 449 if (s->max_write_zero && 450 (s->max_write_zero >= INT_MAX || 451 !QEMU_IS_ALIGNED(s->max_write_zero, 452 MAX(s->opt_write_zero, align)))) { 453 error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64, 454 s->max_write_zero); 455 goto out; 456 } 457 458 s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0); 459 if (s->opt_discard && 460 (s->opt_discard >= INT_MAX || 461 !QEMU_IS_ALIGNED(s->opt_discard, align))) { 462 error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64, 463 s->opt_discard); 464 goto out; 465 } 466 467 s->max_discard = qemu_opt_get_size(opts, "max-discard", 0); 468 if (s->max_discard && 469 (s->max_discard >= INT_MAX || 470 !QEMU_IS_ALIGNED(s->max_discard, 471 MAX(s->opt_discard, align)))) { 472 error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64, 473 s->max_discard); 474 goto out; 475 } 476 477 ret = 0; 478 out: 479 if (ret < 0) { 480 g_free(s->config_file); 481 } 482 qemu_opts_del(opts); 483 return ret; 484 } 485 486 static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes) 487 { 488 BDRVBlkdebugState *s = bs->opaque; 489 BlkdebugRule *rule = NULL; 490 int error; 491 bool immediately; 492 493 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 494 uint64_t inject_offset = rule->options.inject.offset; 495 496 if (inject_offset == -1 || 497 (bytes && inject_offset >= offset && 498 inject_offset < offset + bytes)) 499 { 500 break; 501 } 502 } 503 504 if (!rule || !rule->options.inject.error) { 505 return 0; 506 } 507 508 immediately = rule->options.inject.immediately; 509 error = rule->options.inject.error; 510 511 if (rule->options.inject.once) { 512 QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next); 513 remove_rule(rule); 514 } 515 516 if (!immediately) { 517 aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); 518 qemu_coroutine_yield(); 519 } 520 521 return -error; 522 } 523 524 static int coroutine_fn 525 blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 526 QEMUIOVector *qiov, int flags) 527 { 528 int err; 529 530 /* Sanity check block layer guarantees */ 531 assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); 532 assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); 533 if (bs->bl.max_transfer) { 534 assert(bytes <= bs->bl.max_transfer); 535 } 536 537 err = rule_check(bs, offset, bytes); 538 if (err) { 539 return err; 540 } 541 542 return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 543 } 544 545 static int coroutine_fn 546 blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 547 QEMUIOVector *qiov, int flags) 548 { 549 int err; 550 551 /* Sanity check block layer guarantees */ 552 assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); 553 assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); 554 if (bs->bl.max_transfer) { 555 assert(bytes <= bs->bl.max_transfer); 556 } 557 558 err = rule_check(bs, offset, bytes); 559 if (err) { 560 return err; 561 } 562 563 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 564 } 565 566 static int blkdebug_co_flush(BlockDriverState *bs) 567 { 568 int err = rule_check(bs, 0, 0); 569 570 if (err) { 571 return err; 572 } 573 574 return bdrv_co_flush(bs->file->bs); 575 } 576 577 static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs, 578 int64_t offset, int bytes, 579 BdrvRequestFlags flags) 580 { 581 uint32_t align = MAX(bs->bl.request_alignment, 582 bs->bl.pwrite_zeroes_alignment); 583 int err; 584 585 /* Only pass through requests that are larger than requested 586 * preferred alignment (so that we test the fallback to writes on 587 * unaligned portions), and check that the block layer never hands 588 * us anything unaligned that crosses an alignment boundary. */ 589 if (bytes < align) { 590 assert(QEMU_IS_ALIGNED(offset, align) || 591 QEMU_IS_ALIGNED(offset + bytes, align) || 592 DIV_ROUND_UP(offset, align) == 593 DIV_ROUND_UP(offset + bytes, align)); 594 return -ENOTSUP; 595 } 596 assert(QEMU_IS_ALIGNED(offset, align)); 597 assert(QEMU_IS_ALIGNED(bytes, align)); 598 if (bs->bl.max_pwrite_zeroes) { 599 assert(bytes <= bs->bl.max_pwrite_zeroes); 600 } 601 602 err = rule_check(bs, offset, bytes); 603 if (err) { 604 return err; 605 } 606 607 return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); 608 } 609 610 static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, 611 int64_t offset, int bytes) 612 { 613 uint32_t align = bs->bl.pdiscard_alignment; 614 int err; 615 616 /* Only pass through requests that are larger than requested 617 * minimum alignment, and ensure that unaligned requests do not 618 * cross optimum discard boundaries. */ 619 if (bytes < bs->bl.request_alignment) { 620 assert(QEMU_IS_ALIGNED(offset, align) || 621 QEMU_IS_ALIGNED(offset + bytes, align) || 622 DIV_ROUND_UP(offset, align) == 623 DIV_ROUND_UP(offset + bytes, align)); 624 return -ENOTSUP; 625 } 626 assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); 627 assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); 628 if (align && bytes >= align) { 629 assert(QEMU_IS_ALIGNED(offset, align)); 630 assert(QEMU_IS_ALIGNED(bytes, align)); 631 } 632 if (bs->bl.max_pdiscard) { 633 assert(bytes <= bs->bl.max_pdiscard); 634 } 635 636 err = rule_check(bs, offset, bytes); 637 if (err) { 638 return err; 639 } 640 641 return bdrv_co_pdiscard(bs->file->bs, offset, bytes); 642 } 643 644 static void blkdebug_close(BlockDriverState *bs) 645 { 646 BDRVBlkdebugState *s = bs->opaque; 647 BlkdebugRule *rule, *next; 648 int i; 649 650 for (i = 0; i < BLKDBG__MAX; i++) { 651 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 652 remove_rule(rule); 653 } 654 } 655 656 g_free(s->config_file); 657 } 658 659 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 660 { 661 BDRVBlkdebugState *s = bs->opaque; 662 BlkdebugSuspendedReq r; 663 664 r = (BlkdebugSuspendedReq) { 665 .co = qemu_coroutine_self(), 666 .tag = g_strdup(rule->options.suspend.tag), 667 }; 668 669 remove_rule(rule); 670 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 671 672 if (!qtest_enabled()) { 673 printf("blkdebug: Suspended request '%s'\n", r.tag); 674 } 675 qemu_coroutine_yield(); 676 if (!qtest_enabled()) { 677 printf("blkdebug: Resuming request '%s'\n", r.tag); 678 } 679 680 QLIST_REMOVE(&r, next); 681 g_free(r.tag); 682 } 683 684 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 685 bool injected) 686 { 687 BDRVBlkdebugState *s = bs->opaque; 688 689 /* Only process rules for the current state */ 690 if (rule->state && rule->state != s->state) { 691 return injected; 692 } 693 694 /* Take the action */ 695 switch (rule->action) { 696 case ACTION_INJECT_ERROR: 697 if (!injected) { 698 QSIMPLEQ_INIT(&s->active_rules); 699 injected = true; 700 } 701 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 702 break; 703 704 case ACTION_SET_STATE: 705 s->new_state = rule->options.set_state.new_state; 706 break; 707 708 case ACTION_SUSPEND: 709 suspend_request(bs, rule); 710 break; 711 } 712 return injected; 713 } 714 715 static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) 716 { 717 BDRVBlkdebugState *s = bs->opaque; 718 struct BlkdebugRule *rule, *next; 719 bool injected; 720 721 assert((int)event >= 0 && event < BLKDBG__MAX); 722 723 injected = false; 724 s->new_state = s->state; 725 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 726 injected = process_rule(bs, rule, injected); 727 } 728 s->state = s->new_state; 729 } 730 731 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 732 const char *tag) 733 { 734 BDRVBlkdebugState *s = bs->opaque; 735 struct BlkdebugRule *rule; 736 BlkdebugEvent blkdebug_event; 737 738 if (get_event_by_name(event, &blkdebug_event) < 0) { 739 return -ENOENT; 740 } 741 742 743 rule = g_malloc(sizeof(*rule)); 744 *rule = (struct BlkdebugRule) { 745 .event = blkdebug_event, 746 .action = ACTION_SUSPEND, 747 .state = 0, 748 .options.suspend.tag = g_strdup(tag), 749 }; 750 751 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 752 753 return 0; 754 } 755 756 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 757 { 758 BDRVBlkdebugState *s = bs->opaque; 759 BlkdebugSuspendedReq *r, *next; 760 761 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { 762 if (!strcmp(r->tag, tag)) { 763 qemu_coroutine_enter(r->co); 764 return 0; 765 } 766 } 767 return -ENOENT; 768 } 769 770 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, 771 const char *tag) 772 { 773 BDRVBlkdebugState *s = bs->opaque; 774 BlkdebugSuspendedReq *r, *r_next; 775 BlkdebugRule *rule, *next; 776 int i, ret = -ENOENT; 777 778 for (i = 0; i < BLKDBG__MAX; i++) { 779 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 780 if (rule->action == ACTION_SUSPEND && 781 !strcmp(rule->options.suspend.tag, tag)) { 782 remove_rule(rule); 783 ret = 0; 784 } 785 } 786 } 787 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { 788 if (!strcmp(r->tag, tag)) { 789 qemu_coroutine_enter(r->co); 790 ret = 0; 791 } 792 } 793 return ret; 794 } 795 796 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 797 { 798 BDRVBlkdebugState *s = bs->opaque; 799 BlkdebugSuspendedReq *r; 800 801 QLIST_FOREACH(r, &s->suspended_reqs, next) { 802 if (!strcmp(r->tag, tag)) { 803 return true; 804 } 805 } 806 return false; 807 } 808 809 static int64_t blkdebug_getlength(BlockDriverState *bs) 810 { 811 return bdrv_getlength(bs->file->bs); 812 } 813 814 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp) 815 { 816 return bdrv_truncate(bs->file, offset, errp); 817 } 818 819 static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) 820 { 821 BDRVBlkdebugState *s = bs->opaque; 822 QDict *opts; 823 const QDictEntry *e; 824 bool force_json = false; 825 826 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 827 if (strcmp(qdict_entry_key(e), "config") && 828 strcmp(qdict_entry_key(e), "x-image")) 829 { 830 force_json = true; 831 break; 832 } 833 } 834 835 if (force_json && !bs->file->bs->full_open_options) { 836 /* The config file cannot be recreated, so creating a plain filename 837 * is impossible */ 838 return; 839 } 840 841 if (!force_json && bs->file->bs->exact_filename[0]) { 842 int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), 843 "blkdebug:%s:%s", s->config_file ?: "", 844 bs->file->bs->exact_filename); 845 if (ret >= sizeof(bs->exact_filename)) { 846 /* An overflow makes the filename unusable, so do not report any */ 847 bs->exact_filename[0] = 0; 848 } 849 } 850 851 opts = qdict_new(); 852 qdict_put_str(opts, "driver", "blkdebug"); 853 854 QINCREF(bs->file->bs->full_open_options); 855 qdict_put(opts, "image", bs->file->bs->full_open_options); 856 857 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 858 if (strcmp(qdict_entry_key(e), "x-image")) { 859 qobject_incref(qdict_entry_value(e)); 860 qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); 861 } 862 } 863 864 bs->full_open_options = opts; 865 } 866 867 static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) 868 { 869 BDRVBlkdebugState *s = bs->opaque; 870 871 if (s->align) { 872 bs->bl.request_alignment = s->align; 873 } 874 if (s->max_transfer) { 875 bs->bl.max_transfer = s->max_transfer; 876 } 877 if (s->opt_write_zero) { 878 bs->bl.pwrite_zeroes_alignment = s->opt_write_zero; 879 } 880 if (s->max_write_zero) { 881 bs->bl.max_pwrite_zeroes = s->max_write_zero; 882 } 883 if (s->opt_discard) { 884 bs->bl.pdiscard_alignment = s->opt_discard; 885 } 886 if (s->max_discard) { 887 bs->bl.max_pdiscard = s->max_discard; 888 } 889 } 890 891 static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, 892 BlockReopenQueue *queue, Error **errp) 893 { 894 return 0; 895 } 896 897 static BlockDriver bdrv_blkdebug = { 898 .format_name = "blkdebug", 899 .protocol_name = "blkdebug", 900 .instance_size = sizeof(BDRVBlkdebugState), 901 902 .bdrv_parse_filename = blkdebug_parse_filename, 903 .bdrv_file_open = blkdebug_open, 904 .bdrv_close = blkdebug_close, 905 .bdrv_reopen_prepare = blkdebug_reopen_prepare, 906 .bdrv_child_perm = bdrv_filter_default_perms, 907 908 .bdrv_getlength = blkdebug_getlength, 909 .bdrv_truncate = blkdebug_truncate, 910 .bdrv_refresh_filename = blkdebug_refresh_filename, 911 .bdrv_refresh_limits = blkdebug_refresh_limits, 912 913 .bdrv_co_preadv = blkdebug_co_preadv, 914 .bdrv_co_pwritev = blkdebug_co_pwritev, 915 .bdrv_co_flush_to_disk = blkdebug_co_flush, 916 .bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes, 917 .bdrv_co_pdiscard = blkdebug_co_pdiscard, 918 919 .bdrv_debug_event = blkdebug_debug_event, 920 .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 921 .bdrv_debug_remove_breakpoint 922 = blkdebug_debug_remove_breakpoint, 923 .bdrv_debug_resume = blkdebug_debug_resume, 924 .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 925 }; 926 927 static void bdrv_blkdebug_init(void) 928 { 929 bdrv_register(&bdrv_blkdebug); 930 } 931 932 block_init(bdrv_blkdebug_init); 933