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 "block_int.h" 27 #include "module.h" 28 29 typedef struct BDRVBlkdebugState { 30 int state; 31 int new_state; 32 33 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; 34 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 35 QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 36 } BDRVBlkdebugState; 37 38 typedef struct BlkdebugAIOCB { 39 BlockDriverAIOCB common; 40 QEMUBH *bh; 41 int ret; 42 } BlkdebugAIOCB; 43 44 typedef struct BlkdebugSuspendedReq { 45 Coroutine *co; 46 char *tag; 47 QLIST_ENTRY(BlkdebugSuspendedReq) next; 48 } BlkdebugSuspendedReq; 49 50 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); 51 52 static const AIOCBInfo blkdebug_aiocb_info = { 53 .aiocb_size = sizeof(BlkdebugAIOCB), 54 .cancel = blkdebug_aio_cancel, 55 }; 56 57 enum { 58 ACTION_INJECT_ERROR, 59 ACTION_SET_STATE, 60 ACTION_SUSPEND, 61 }; 62 63 typedef struct BlkdebugRule { 64 BlkDebugEvent event; 65 int action; 66 int state; 67 union { 68 struct { 69 int error; 70 int immediately; 71 int once; 72 int64_t sector; 73 } inject; 74 struct { 75 int new_state; 76 } set_state; 77 struct { 78 char *tag; 79 } suspend; 80 } options; 81 QLIST_ENTRY(BlkdebugRule) next; 82 QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 83 } BlkdebugRule; 84 85 static QemuOptsList inject_error_opts = { 86 .name = "inject-error", 87 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 88 .desc = { 89 { 90 .name = "event", 91 .type = QEMU_OPT_STRING, 92 }, 93 { 94 .name = "state", 95 .type = QEMU_OPT_NUMBER, 96 }, 97 { 98 .name = "errno", 99 .type = QEMU_OPT_NUMBER, 100 }, 101 { 102 .name = "sector", 103 .type = QEMU_OPT_NUMBER, 104 }, 105 { 106 .name = "once", 107 .type = QEMU_OPT_BOOL, 108 }, 109 { 110 .name = "immediately", 111 .type = QEMU_OPT_BOOL, 112 }, 113 { /* end of list */ } 114 }, 115 }; 116 117 static QemuOptsList set_state_opts = { 118 .name = "set-state", 119 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 120 .desc = { 121 { 122 .name = "event", 123 .type = QEMU_OPT_STRING, 124 }, 125 { 126 .name = "state", 127 .type = QEMU_OPT_NUMBER, 128 }, 129 { 130 .name = "new_state", 131 .type = QEMU_OPT_NUMBER, 132 }, 133 { /* end of list */ } 134 }, 135 }; 136 137 static QemuOptsList *config_groups[] = { 138 &inject_error_opts, 139 &set_state_opts, 140 NULL 141 }; 142 143 static const char *event_names[BLKDBG_EVENT_MAX] = { 144 [BLKDBG_L1_UPDATE] = "l1_update", 145 [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table", 146 [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table", 147 [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table", 148 149 [BLKDBG_L2_LOAD] = "l2_load", 150 [BLKDBG_L2_UPDATE] = "l2_update", 151 [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed", 152 [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read", 153 [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write", 154 155 [BLKDBG_READ_AIO] = "read_aio", 156 [BLKDBG_READ_BACKING_AIO] = "read_backing_aio", 157 [BLKDBG_READ_COMPRESSED] = "read_compressed", 158 159 [BLKDBG_WRITE_AIO] = "write_aio", 160 [BLKDBG_WRITE_COMPRESSED] = "write_compressed", 161 162 [BLKDBG_VMSTATE_LOAD] = "vmstate_load", 163 [BLKDBG_VMSTATE_SAVE] = "vmstate_save", 164 165 [BLKDBG_COW_READ] = "cow_read", 166 [BLKDBG_COW_WRITE] = "cow_write", 167 168 [BLKDBG_REFTABLE_LOAD] = "reftable_load", 169 [BLKDBG_REFTABLE_GROW] = "reftable_grow", 170 171 [BLKDBG_REFBLOCK_LOAD] = "refblock_load", 172 [BLKDBG_REFBLOCK_UPDATE] = "refblock_update", 173 [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part", 174 [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc", 175 [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup", 176 [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write", 177 [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks", 178 [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table", 179 [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table", 180 181 [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc", 182 [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", 183 [BLKDBG_CLUSTER_FREE] = "cluster_free", 184 }; 185 186 static int get_event_by_name(const char *name, BlkDebugEvent *event) 187 { 188 int i; 189 190 for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 191 if (!strcmp(event_names[i], name)) { 192 *event = i; 193 return 0; 194 } 195 } 196 197 return -1; 198 } 199 200 struct add_rule_data { 201 BDRVBlkdebugState *s; 202 int action; 203 }; 204 205 static int add_rule(QemuOpts *opts, void *opaque) 206 { 207 struct add_rule_data *d = opaque; 208 BDRVBlkdebugState *s = d->s; 209 const char* event_name; 210 BlkDebugEvent event; 211 struct BlkdebugRule *rule; 212 213 /* Find the right event for the rule */ 214 event_name = qemu_opt_get(opts, "event"); 215 if (!event_name || get_event_by_name(event_name, &event) < 0) { 216 return -1; 217 } 218 219 /* Set attributes common for all actions */ 220 rule = g_malloc0(sizeof(*rule)); 221 *rule = (struct BlkdebugRule) { 222 .event = event, 223 .action = d->action, 224 .state = qemu_opt_get_number(opts, "state", 0), 225 }; 226 227 /* Parse action-specific options */ 228 switch (d->action) { 229 case ACTION_INJECT_ERROR: 230 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 231 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 232 rule->options.inject.immediately = 233 qemu_opt_get_bool(opts, "immediately", 0); 234 rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); 235 break; 236 237 case ACTION_SET_STATE: 238 rule->options.set_state.new_state = 239 qemu_opt_get_number(opts, "new_state", 0); 240 break; 241 242 case ACTION_SUSPEND: 243 rule->options.suspend.tag = 244 g_strdup(qemu_opt_get(opts, "tag")); 245 break; 246 }; 247 248 /* Add the rule */ 249 QLIST_INSERT_HEAD(&s->rules[event], rule, next); 250 251 return 0; 252 } 253 254 static void remove_rule(BlkdebugRule *rule) 255 { 256 switch (rule->action) { 257 case ACTION_INJECT_ERROR: 258 case ACTION_SET_STATE: 259 break; 260 case ACTION_SUSPEND: 261 g_free(rule->options.suspend.tag); 262 break; 263 } 264 265 QLIST_REMOVE(rule, next); 266 g_free(rule); 267 } 268 269 static int read_config(BDRVBlkdebugState *s, const char *filename) 270 { 271 FILE *f; 272 int ret; 273 struct add_rule_data d; 274 275 /* Allow usage without config file */ 276 if (!*filename) { 277 return 0; 278 } 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 int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) 307 { 308 BDRVBlkdebugState *s = bs->opaque; 309 int ret; 310 char *config, *c; 311 312 /* Parse the blkdebug: prefix */ 313 if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) { 314 return -EINVAL; 315 } 316 filename += strlen("blkdebug:"); 317 318 /* Read rules from config file */ 319 c = strchr(filename, ':'); 320 if (c == NULL) { 321 return -EINVAL; 322 } 323 324 config = g_strdup(filename); 325 config[c - filename] = '\0'; 326 ret = read_config(s, config); 327 g_free(config); 328 if (ret < 0) { 329 return ret; 330 } 331 filename = c + 1; 332 333 /* Set initial state */ 334 s->state = 1; 335 336 /* Open the backing file */ 337 ret = bdrv_file_open(&bs->file, filename, flags); 338 if (ret < 0) { 339 return ret; 340 } 341 342 return 0; 343 } 344 345 static void error_callback_bh(void *opaque) 346 { 347 struct BlkdebugAIOCB *acb = opaque; 348 qemu_bh_delete(acb->bh); 349 acb->common.cb(acb->common.opaque, acb->ret); 350 qemu_aio_release(acb); 351 } 352 353 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) 354 { 355 BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); 356 qemu_aio_release(acb); 357 } 358 359 static BlockDriverAIOCB *inject_error(BlockDriverState *bs, 360 BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule) 361 { 362 BDRVBlkdebugState *s = bs->opaque; 363 int error = rule->options.inject.error; 364 struct BlkdebugAIOCB *acb; 365 QEMUBH *bh; 366 367 if (rule->options.inject.once) { 368 QSIMPLEQ_INIT(&s->active_rules); 369 } 370 371 if (rule->options.inject.immediately) { 372 return NULL; 373 } 374 375 acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); 376 acb->ret = -error; 377 378 bh = qemu_bh_new(error_callback_bh, acb); 379 acb->bh = bh; 380 qemu_bh_schedule(bh); 381 382 return &acb->common; 383 } 384 385 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, 386 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 387 BlockDriverCompletionFunc *cb, void *opaque) 388 { 389 BDRVBlkdebugState *s = bs->opaque; 390 BlkdebugRule *rule = NULL; 391 392 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 393 if (rule->options.inject.sector == -1 || 394 (rule->options.inject.sector >= sector_num && 395 rule->options.inject.sector < sector_num + nb_sectors)) { 396 break; 397 } 398 } 399 400 if (rule && rule->options.inject.error) { 401 return inject_error(bs, cb, opaque, rule); 402 } 403 404 return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 405 } 406 407 static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, 408 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 409 BlockDriverCompletionFunc *cb, void *opaque) 410 { 411 BDRVBlkdebugState *s = bs->opaque; 412 BlkdebugRule *rule = NULL; 413 414 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 415 if (rule->options.inject.sector == -1 || 416 (rule->options.inject.sector >= sector_num && 417 rule->options.inject.sector < sector_num + nb_sectors)) { 418 break; 419 } 420 } 421 422 if (rule && rule->options.inject.error) { 423 return inject_error(bs, cb, opaque, rule); 424 } 425 426 return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 427 } 428 429 430 static void blkdebug_close(BlockDriverState *bs) 431 { 432 BDRVBlkdebugState *s = bs->opaque; 433 BlkdebugRule *rule, *next; 434 int i; 435 436 for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 437 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 438 remove_rule(rule); 439 } 440 } 441 } 442 443 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 444 { 445 BDRVBlkdebugState *s = bs->opaque; 446 BlkdebugSuspendedReq r; 447 448 r = (BlkdebugSuspendedReq) { 449 .co = qemu_coroutine_self(), 450 .tag = g_strdup(rule->options.suspend.tag), 451 }; 452 453 remove_rule(rule); 454 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 455 456 printf("blkdebug: Suspended request '%s'\n", r.tag); 457 qemu_coroutine_yield(); 458 printf("blkdebug: Resuming request '%s'\n", r.tag); 459 460 QLIST_REMOVE(&r, next); 461 g_free(r.tag); 462 } 463 464 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 465 bool injected) 466 { 467 BDRVBlkdebugState *s = bs->opaque; 468 469 /* Only process rules for the current state */ 470 if (rule->state && rule->state != s->state) { 471 return injected; 472 } 473 474 /* Take the action */ 475 switch (rule->action) { 476 case ACTION_INJECT_ERROR: 477 if (!injected) { 478 QSIMPLEQ_INIT(&s->active_rules); 479 injected = true; 480 } 481 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 482 break; 483 484 case ACTION_SET_STATE: 485 s->new_state = rule->options.set_state.new_state; 486 break; 487 488 case ACTION_SUSPEND: 489 suspend_request(bs, rule); 490 break; 491 } 492 return injected; 493 } 494 495 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) 496 { 497 BDRVBlkdebugState *s = bs->opaque; 498 struct BlkdebugRule *rule, *next; 499 bool injected; 500 501 assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); 502 503 injected = false; 504 s->new_state = s->state; 505 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 506 injected = process_rule(bs, rule, injected); 507 } 508 s->state = s->new_state; 509 } 510 511 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 512 const char *tag) 513 { 514 BDRVBlkdebugState *s = bs->opaque; 515 struct BlkdebugRule *rule; 516 BlkDebugEvent blkdebug_event; 517 518 if (get_event_by_name(event, &blkdebug_event) < 0) { 519 return -ENOENT; 520 } 521 522 523 rule = g_malloc(sizeof(*rule)); 524 *rule = (struct BlkdebugRule) { 525 .event = blkdebug_event, 526 .action = ACTION_SUSPEND, 527 .state = 0, 528 .options.suspend.tag = g_strdup(tag), 529 }; 530 531 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 532 533 return 0; 534 } 535 536 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 537 { 538 BDRVBlkdebugState *s = bs->opaque; 539 BlkdebugSuspendedReq *r; 540 541 QLIST_FOREACH(r, &s->suspended_reqs, next) { 542 if (!strcmp(r->tag, tag)) { 543 qemu_coroutine_enter(r->co, NULL); 544 return 0; 545 } 546 } 547 return -ENOENT; 548 } 549 550 551 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 552 { 553 BDRVBlkdebugState *s = bs->opaque; 554 BlkdebugSuspendedReq *r; 555 556 QLIST_FOREACH(r, &s->suspended_reqs, next) { 557 if (!strcmp(r->tag, tag)) { 558 return true; 559 } 560 } 561 return false; 562 } 563 564 static int64_t blkdebug_getlength(BlockDriverState *bs) 565 { 566 return bdrv_getlength(bs->file); 567 } 568 569 static BlockDriver bdrv_blkdebug = { 570 .format_name = "blkdebug", 571 .protocol_name = "blkdebug", 572 573 .instance_size = sizeof(BDRVBlkdebugState), 574 575 .bdrv_file_open = blkdebug_open, 576 .bdrv_close = blkdebug_close, 577 .bdrv_getlength = blkdebug_getlength, 578 579 .bdrv_aio_readv = blkdebug_aio_readv, 580 .bdrv_aio_writev = blkdebug_aio_writev, 581 582 .bdrv_debug_event = blkdebug_debug_event, 583 .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 584 .bdrv_debug_resume = blkdebug_debug_resume, 585 .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 586 }; 587 588 static void bdrv_blkdebug_init(void) 589 { 590 bdrv_register(&bdrv_blkdebug); 591 } 592 593 block_init(bdrv_blkdebug_init); 594