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 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; 32 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 33 } BDRVBlkdebugState; 34 35 typedef struct BlkdebugAIOCB { 36 BlockDriverAIOCB common; 37 QEMUBH *bh; 38 int ret; 39 } BlkdebugAIOCB; 40 41 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); 42 43 static AIOPool blkdebug_aio_pool = { 44 .aiocb_size = sizeof(BlkdebugAIOCB), 45 .cancel = blkdebug_aio_cancel, 46 }; 47 48 enum { 49 ACTION_INJECT_ERROR, 50 ACTION_SET_STATE, 51 }; 52 53 typedef struct BlkdebugRule { 54 BlkDebugEvent event; 55 int action; 56 int state; 57 union { 58 struct { 59 int error; 60 int immediately; 61 int once; 62 int64_t sector; 63 } inject; 64 struct { 65 int new_state; 66 } set_state; 67 } options; 68 QLIST_ENTRY(BlkdebugRule) next; 69 QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 70 } BlkdebugRule; 71 72 static QemuOptsList inject_error_opts = { 73 .name = "inject-error", 74 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 75 .desc = { 76 { 77 .name = "event", 78 .type = QEMU_OPT_STRING, 79 }, 80 { 81 .name = "state", 82 .type = QEMU_OPT_NUMBER, 83 }, 84 { 85 .name = "errno", 86 .type = QEMU_OPT_NUMBER, 87 }, 88 { 89 .name = "sector", 90 .type = QEMU_OPT_NUMBER, 91 }, 92 { 93 .name = "once", 94 .type = QEMU_OPT_BOOL, 95 }, 96 { 97 .name = "immediately", 98 .type = QEMU_OPT_BOOL, 99 }, 100 { /* end of list */ } 101 }, 102 }; 103 104 static QemuOptsList set_state_opts = { 105 .name = "set-state", 106 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 107 .desc = { 108 { 109 .name = "event", 110 .type = QEMU_OPT_STRING, 111 }, 112 { 113 .name = "state", 114 .type = QEMU_OPT_NUMBER, 115 }, 116 { 117 .name = "new_state", 118 .type = QEMU_OPT_NUMBER, 119 }, 120 { /* end of list */ } 121 }, 122 }; 123 124 static QemuOptsList *config_groups[] = { 125 &inject_error_opts, 126 &set_state_opts, 127 NULL 128 }; 129 130 static const char *event_names[BLKDBG_EVENT_MAX] = { 131 [BLKDBG_L1_UPDATE] = "l1_update", 132 [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table", 133 [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table", 134 [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table", 135 136 [BLKDBG_L2_LOAD] = "l2_load", 137 [BLKDBG_L2_UPDATE] = "l2_update", 138 [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed", 139 [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read", 140 [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write", 141 142 [BLKDBG_READ_AIO] = "read_aio", 143 [BLKDBG_READ_BACKING_AIO] = "read_backing_aio", 144 [BLKDBG_READ_COMPRESSED] = "read_compressed", 145 146 [BLKDBG_WRITE_AIO] = "write_aio", 147 [BLKDBG_WRITE_COMPRESSED] = "write_compressed", 148 149 [BLKDBG_VMSTATE_LOAD] = "vmstate_load", 150 [BLKDBG_VMSTATE_SAVE] = "vmstate_save", 151 152 [BLKDBG_COW_READ] = "cow_read", 153 [BLKDBG_COW_WRITE] = "cow_write", 154 155 [BLKDBG_REFTABLE_LOAD] = "reftable_load", 156 [BLKDBG_REFTABLE_GROW] = "reftable_grow", 157 158 [BLKDBG_REFBLOCK_LOAD] = "refblock_load", 159 [BLKDBG_REFBLOCK_UPDATE] = "refblock_update", 160 [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part", 161 [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc", 162 [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup", 163 [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write", 164 [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks", 165 [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table", 166 [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table", 167 168 [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc", 169 [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", 170 [BLKDBG_CLUSTER_FREE] = "cluster_free", 171 }; 172 173 static int get_event_by_name(const char *name, BlkDebugEvent *event) 174 { 175 int i; 176 177 for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 178 if (!strcmp(event_names[i], name)) { 179 *event = i; 180 return 0; 181 } 182 } 183 184 return -1; 185 } 186 187 struct add_rule_data { 188 BDRVBlkdebugState *s; 189 int action; 190 }; 191 192 static int add_rule(QemuOpts *opts, void *opaque) 193 { 194 struct add_rule_data *d = opaque; 195 BDRVBlkdebugState *s = d->s; 196 const char* event_name; 197 BlkDebugEvent event; 198 struct BlkdebugRule *rule; 199 200 /* Find the right event for the rule */ 201 event_name = qemu_opt_get(opts, "event"); 202 if (!event_name || get_event_by_name(event_name, &event) < 0) { 203 return -1; 204 } 205 206 /* Set attributes common for all actions */ 207 rule = g_malloc0(sizeof(*rule)); 208 *rule = (struct BlkdebugRule) { 209 .event = event, 210 .action = d->action, 211 .state = qemu_opt_get_number(opts, "state", 0), 212 }; 213 214 /* Parse action-specific options */ 215 switch (d->action) { 216 case ACTION_INJECT_ERROR: 217 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 218 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 219 rule->options.inject.immediately = 220 qemu_opt_get_bool(opts, "immediately", 0); 221 rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); 222 break; 223 224 case ACTION_SET_STATE: 225 rule->options.set_state.new_state = 226 qemu_opt_get_number(opts, "new_state", 0); 227 break; 228 }; 229 230 /* Add the rule */ 231 QLIST_INSERT_HEAD(&s->rules[event], rule, next); 232 233 return 0; 234 } 235 236 static int read_config(BDRVBlkdebugState *s, const char *filename) 237 { 238 FILE *f; 239 int ret; 240 struct add_rule_data d; 241 242 f = fopen(filename, "r"); 243 if (f == NULL) { 244 return -errno; 245 } 246 247 ret = qemu_config_parse(f, config_groups, filename); 248 if (ret < 0) { 249 goto fail; 250 } 251 252 d.s = s; 253 d.action = ACTION_INJECT_ERROR; 254 qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0); 255 256 d.action = ACTION_SET_STATE; 257 qemu_opts_foreach(&set_state_opts, add_rule, &d, 0); 258 259 ret = 0; 260 fail: 261 qemu_opts_reset(&inject_error_opts); 262 qemu_opts_reset(&set_state_opts); 263 fclose(f); 264 return ret; 265 } 266 267 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 268 static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) 269 { 270 BDRVBlkdebugState *s = bs->opaque; 271 int ret; 272 char *config, *c; 273 274 /* Parse the blkdebug: prefix */ 275 if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) { 276 return -EINVAL; 277 } 278 filename += strlen("blkdebug:"); 279 280 /* Read rules from config file */ 281 c = strchr(filename, ':'); 282 if (c == NULL) { 283 return -EINVAL; 284 } 285 286 config = g_strdup(filename); 287 config[c - filename] = '\0'; 288 ret = read_config(s, config); 289 g_free(config); 290 if (ret < 0) { 291 return ret; 292 } 293 filename = c + 1; 294 295 /* Set initial state */ 296 s->state = 1; 297 298 /* Open the backing file */ 299 ret = bdrv_file_open(&bs->file, filename, flags); 300 if (ret < 0) { 301 return ret; 302 } 303 304 return 0; 305 } 306 307 static void error_callback_bh(void *opaque) 308 { 309 struct BlkdebugAIOCB *acb = opaque; 310 qemu_bh_delete(acb->bh); 311 acb->common.cb(acb->common.opaque, acb->ret); 312 qemu_aio_release(acb); 313 } 314 315 static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) 316 { 317 BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); 318 qemu_aio_release(acb); 319 } 320 321 static BlockDriverAIOCB *inject_error(BlockDriverState *bs, 322 BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule) 323 { 324 BDRVBlkdebugState *s = bs->opaque; 325 int error = rule->options.inject.error; 326 struct BlkdebugAIOCB *acb; 327 QEMUBH *bh; 328 329 if (rule->options.inject.once) { 330 QSIMPLEQ_INIT(&s->active_rules); 331 } 332 333 if (rule->options.inject.immediately) { 334 return NULL; 335 } 336 337 acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque); 338 acb->ret = -error; 339 340 bh = qemu_bh_new(error_callback_bh, acb); 341 acb->bh = bh; 342 qemu_bh_schedule(bh); 343 344 return &acb->common; 345 } 346 347 static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, 348 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 349 BlockDriverCompletionFunc *cb, void *opaque) 350 { 351 BDRVBlkdebugState *s = bs->opaque; 352 BlkdebugRule *rule = NULL; 353 354 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 355 if (rule->options.inject.sector == -1 || 356 (rule->options.inject.sector >= sector_num && 357 rule->options.inject.sector < sector_num + nb_sectors)) { 358 break; 359 } 360 } 361 362 if (rule && rule->options.inject.error) { 363 return inject_error(bs, cb, opaque, rule); 364 } 365 366 return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 367 } 368 369 static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, 370 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 371 BlockDriverCompletionFunc *cb, void *opaque) 372 { 373 BDRVBlkdebugState *s = bs->opaque; 374 BlkdebugRule *rule = NULL; 375 376 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 377 if (rule->options.inject.sector == -1 || 378 (rule->options.inject.sector >= sector_num && 379 rule->options.inject.sector < sector_num + nb_sectors)) { 380 break; 381 } 382 } 383 384 if (rule && rule->options.inject.error) { 385 return inject_error(bs, cb, opaque, rule); 386 } 387 388 return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 389 } 390 391 static void blkdebug_close(BlockDriverState *bs) 392 { 393 BDRVBlkdebugState *s = bs->opaque; 394 BlkdebugRule *rule, *next; 395 int i; 396 397 for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 398 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 399 QLIST_REMOVE(rule, next); 400 g_free(rule); 401 } 402 } 403 } 404 405 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 406 int old_state, bool injected) 407 { 408 BDRVBlkdebugState *s = bs->opaque; 409 410 /* Only process rules for the current state */ 411 if (rule->state && rule->state != old_state) { 412 return injected; 413 } 414 415 /* Take the action */ 416 switch (rule->action) { 417 case ACTION_INJECT_ERROR: 418 if (!injected) { 419 QSIMPLEQ_INIT(&s->active_rules); 420 injected = true; 421 } 422 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 423 break; 424 425 case ACTION_SET_STATE: 426 s->state = rule->options.set_state.new_state; 427 break; 428 } 429 return injected; 430 } 431 432 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) 433 { 434 BDRVBlkdebugState *s = bs->opaque; 435 struct BlkdebugRule *rule; 436 int old_state = s->state; 437 bool injected; 438 439 assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); 440 441 injected = false; 442 QLIST_FOREACH(rule, &s->rules[event], next) { 443 injected = process_rule(bs, rule, old_state, injected); 444 } 445 } 446 447 static int64_t blkdebug_getlength(BlockDriverState *bs) 448 { 449 return bdrv_getlength(bs->file); 450 } 451 452 static BlockDriver bdrv_blkdebug = { 453 .format_name = "blkdebug", 454 .protocol_name = "blkdebug", 455 456 .instance_size = sizeof(BDRVBlkdebugState), 457 458 .bdrv_file_open = blkdebug_open, 459 .bdrv_close = blkdebug_close, 460 .bdrv_getlength = blkdebug_getlength, 461 462 .bdrv_aio_readv = blkdebug_aio_readv, 463 .bdrv_aio_writev = blkdebug_aio_writev, 464 465 .bdrv_debug_event = blkdebug_debug_event, 466 }; 467 468 static void bdrv_blkdebug_init(void) 469 { 470 bdrv_register(&bdrv_blkdebug); 471 } 472 473 block_init(bdrv_blkdebug_init); 474