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 int64_t coroutine_fn blkdebug_co_get_block_status( 645 BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, 646 BlockDriverState **file) 647 { 648 *pnum = nb_sectors; 649 *file = bs->file->bs; 650 return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | 651 (sector_num << BDRV_SECTOR_BITS); 652 } 653 654 static void blkdebug_close(BlockDriverState *bs) 655 { 656 BDRVBlkdebugState *s = bs->opaque; 657 BlkdebugRule *rule, *next; 658 int i; 659 660 for (i = 0; i < BLKDBG__MAX; i++) { 661 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 662 remove_rule(rule); 663 } 664 } 665 666 g_free(s->config_file); 667 } 668 669 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 670 { 671 BDRVBlkdebugState *s = bs->opaque; 672 BlkdebugSuspendedReq r; 673 674 r = (BlkdebugSuspendedReq) { 675 .co = qemu_coroutine_self(), 676 .tag = g_strdup(rule->options.suspend.tag), 677 }; 678 679 remove_rule(rule); 680 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 681 682 if (!qtest_enabled()) { 683 printf("blkdebug: Suspended request '%s'\n", r.tag); 684 } 685 qemu_coroutine_yield(); 686 if (!qtest_enabled()) { 687 printf("blkdebug: Resuming request '%s'\n", r.tag); 688 } 689 690 QLIST_REMOVE(&r, next); 691 g_free(r.tag); 692 } 693 694 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 695 bool injected) 696 { 697 BDRVBlkdebugState *s = bs->opaque; 698 699 /* Only process rules for the current state */ 700 if (rule->state && rule->state != s->state) { 701 return injected; 702 } 703 704 /* Take the action */ 705 switch (rule->action) { 706 case ACTION_INJECT_ERROR: 707 if (!injected) { 708 QSIMPLEQ_INIT(&s->active_rules); 709 injected = true; 710 } 711 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 712 break; 713 714 case ACTION_SET_STATE: 715 s->new_state = rule->options.set_state.new_state; 716 break; 717 718 case ACTION_SUSPEND: 719 suspend_request(bs, rule); 720 break; 721 } 722 return injected; 723 } 724 725 static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) 726 { 727 BDRVBlkdebugState *s = bs->opaque; 728 struct BlkdebugRule *rule, *next; 729 bool injected; 730 731 assert((int)event >= 0 && event < BLKDBG__MAX); 732 733 injected = false; 734 s->new_state = s->state; 735 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 736 injected = process_rule(bs, rule, injected); 737 } 738 s->state = s->new_state; 739 } 740 741 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 742 const char *tag) 743 { 744 BDRVBlkdebugState *s = bs->opaque; 745 struct BlkdebugRule *rule; 746 BlkdebugEvent blkdebug_event; 747 748 if (get_event_by_name(event, &blkdebug_event) < 0) { 749 return -ENOENT; 750 } 751 752 753 rule = g_malloc(sizeof(*rule)); 754 *rule = (struct BlkdebugRule) { 755 .event = blkdebug_event, 756 .action = ACTION_SUSPEND, 757 .state = 0, 758 .options.suspend.tag = g_strdup(tag), 759 }; 760 761 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 762 763 return 0; 764 } 765 766 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 767 { 768 BDRVBlkdebugState *s = bs->opaque; 769 BlkdebugSuspendedReq *r, *next; 770 771 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { 772 if (!strcmp(r->tag, tag)) { 773 qemu_coroutine_enter(r->co); 774 return 0; 775 } 776 } 777 return -ENOENT; 778 } 779 780 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, 781 const char *tag) 782 { 783 BDRVBlkdebugState *s = bs->opaque; 784 BlkdebugSuspendedReq *r, *r_next; 785 BlkdebugRule *rule, *next; 786 int i, ret = -ENOENT; 787 788 for (i = 0; i < BLKDBG__MAX; i++) { 789 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 790 if (rule->action == ACTION_SUSPEND && 791 !strcmp(rule->options.suspend.tag, tag)) { 792 remove_rule(rule); 793 ret = 0; 794 } 795 } 796 } 797 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { 798 if (!strcmp(r->tag, tag)) { 799 qemu_coroutine_enter(r->co); 800 ret = 0; 801 } 802 } 803 return ret; 804 } 805 806 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 807 { 808 BDRVBlkdebugState *s = bs->opaque; 809 BlkdebugSuspendedReq *r; 810 811 QLIST_FOREACH(r, &s->suspended_reqs, next) { 812 if (!strcmp(r->tag, tag)) { 813 return true; 814 } 815 } 816 return false; 817 } 818 819 static int64_t blkdebug_getlength(BlockDriverState *bs) 820 { 821 return bdrv_getlength(bs->file->bs); 822 } 823 824 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp) 825 { 826 return bdrv_truncate(bs->file, offset, errp); 827 } 828 829 static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) 830 { 831 BDRVBlkdebugState *s = bs->opaque; 832 QDict *opts; 833 const QDictEntry *e; 834 bool force_json = false; 835 836 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 837 if (strcmp(qdict_entry_key(e), "config") && 838 strcmp(qdict_entry_key(e), "x-image")) 839 { 840 force_json = true; 841 break; 842 } 843 } 844 845 if (force_json && !bs->file->bs->full_open_options) { 846 /* The config file cannot be recreated, so creating a plain filename 847 * is impossible */ 848 return; 849 } 850 851 if (!force_json && bs->file->bs->exact_filename[0]) { 852 int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), 853 "blkdebug:%s:%s", s->config_file ?: "", 854 bs->file->bs->exact_filename); 855 if (ret >= sizeof(bs->exact_filename)) { 856 /* An overflow makes the filename unusable, so do not report any */ 857 bs->exact_filename[0] = 0; 858 } 859 } 860 861 opts = qdict_new(); 862 qdict_put_str(opts, "driver", "blkdebug"); 863 864 QINCREF(bs->file->bs->full_open_options); 865 qdict_put(opts, "image", bs->file->bs->full_open_options); 866 867 for (e = qdict_first(options); e; e = qdict_next(options, e)) { 868 if (strcmp(qdict_entry_key(e), "x-image")) { 869 qobject_incref(qdict_entry_value(e)); 870 qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); 871 } 872 } 873 874 bs->full_open_options = opts; 875 } 876 877 static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) 878 { 879 BDRVBlkdebugState *s = bs->opaque; 880 881 if (s->align) { 882 bs->bl.request_alignment = s->align; 883 } 884 if (s->max_transfer) { 885 bs->bl.max_transfer = s->max_transfer; 886 } 887 if (s->opt_write_zero) { 888 bs->bl.pwrite_zeroes_alignment = s->opt_write_zero; 889 } 890 if (s->max_write_zero) { 891 bs->bl.max_pwrite_zeroes = s->max_write_zero; 892 } 893 if (s->opt_discard) { 894 bs->bl.pdiscard_alignment = s->opt_discard; 895 } 896 if (s->max_discard) { 897 bs->bl.max_pdiscard = s->max_discard; 898 } 899 } 900 901 static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, 902 BlockReopenQueue *queue, Error **errp) 903 { 904 return 0; 905 } 906 907 static BlockDriver bdrv_blkdebug = { 908 .format_name = "blkdebug", 909 .protocol_name = "blkdebug", 910 .instance_size = sizeof(BDRVBlkdebugState), 911 912 .bdrv_parse_filename = blkdebug_parse_filename, 913 .bdrv_file_open = blkdebug_open, 914 .bdrv_close = blkdebug_close, 915 .bdrv_reopen_prepare = blkdebug_reopen_prepare, 916 .bdrv_child_perm = bdrv_filter_default_perms, 917 918 .bdrv_getlength = blkdebug_getlength, 919 .bdrv_truncate = blkdebug_truncate, 920 .bdrv_refresh_filename = blkdebug_refresh_filename, 921 .bdrv_refresh_limits = blkdebug_refresh_limits, 922 923 .bdrv_co_preadv = blkdebug_co_preadv, 924 .bdrv_co_pwritev = blkdebug_co_pwritev, 925 .bdrv_co_flush_to_disk = blkdebug_co_flush, 926 .bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes, 927 .bdrv_co_pdiscard = blkdebug_co_pdiscard, 928 .bdrv_co_get_block_status = blkdebug_co_get_block_status, 929 930 .bdrv_debug_event = blkdebug_debug_event, 931 .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 932 .bdrv_debug_remove_breakpoint 933 = blkdebug_debug_remove_breakpoint, 934 .bdrv_debug_resume = blkdebug_debug_resume, 935 .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 936 }; 937 938 static void bdrv_blkdebug_init(void) 939 { 940 bdrv_register(&bdrv_blkdebug); 941 } 942 943 block_init(bdrv_blkdebug_init); 944