16a143727SKevin Wolf /* 26a143727SKevin Wolf * Block protocol for I/O error injection 36a143727SKevin Wolf * 46a143727SKevin Wolf * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com> 56a143727SKevin Wolf * 66a143727SKevin Wolf * Permission is hereby granted, free of charge, to any person obtaining a copy 76a143727SKevin Wolf * of this software and associated documentation files (the "Software"), to deal 86a143727SKevin Wolf * in the Software without restriction, including without limitation the rights 96a143727SKevin Wolf * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 106a143727SKevin Wolf * copies of the Software, and to permit persons to whom the Software is 116a143727SKevin Wolf * furnished to do so, subject to the following conditions: 126a143727SKevin Wolf * 136a143727SKevin Wolf * The above copyright notice and this permission notice shall be included in 146a143727SKevin Wolf * all copies or substantial portions of the Software. 156a143727SKevin Wolf * 166a143727SKevin Wolf * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 176a143727SKevin Wolf * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 186a143727SKevin Wolf * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 196a143727SKevin Wolf * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 206a143727SKevin Wolf * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 216a143727SKevin Wolf * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 226a143727SKevin Wolf * THE SOFTWARE. 236a143727SKevin Wolf */ 246a143727SKevin Wolf 256a143727SKevin Wolf #include "qemu-common.h" 266a143727SKevin Wolf #include "block_int.h" 276a143727SKevin Wolf #include "module.h" 286a143727SKevin Wolf 296a143727SKevin Wolf typedef struct BDRVBlkdebugState { 30571cd43eSPaolo Bonzini int state; 31571cd43eSPaolo Bonzini QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; 32571cd43eSPaolo Bonzini QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 336a143727SKevin Wolf } BDRVBlkdebugState; 346a143727SKevin Wolf 35b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB { 36b9f66d96SKevin Wolf BlockDriverAIOCB common; 37b9f66d96SKevin Wolf QEMUBH *bh; 38b9f66d96SKevin Wolf int ret; 39b9f66d96SKevin Wolf } BlkdebugAIOCB; 40b9f66d96SKevin Wolf 41b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); 42b9f66d96SKevin Wolf 43b9f66d96SKevin Wolf static AIOPool blkdebug_aio_pool = { 44b9f66d96SKevin Wolf .aiocb_size = sizeof(BlkdebugAIOCB), 45b9f66d96SKevin Wolf .cancel = blkdebug_aio_cancel, 46b9f66d96SKevin Wolf }; 47b9f66d96SKevin Wolf 488b9b0cc2SKevin Wolf enum { 498b9b0cc2SKevin Wolf ACTION_INJECT_ERROR, 508b9b0cc2SKevin Wolf ACTION_SET_STATE, 518b9b0cc2SKevin Wolf }; 528b9b0cc2SKevin Wolf 538b9b0cc2SKevin Wolf typedef struct BlkdebugRule { 548b9b0cc2SKevin Wolf BlkDebugEvent event; 558b9b0cc2SKevin Wolf int action; 568b9b0cc2SKevin Wolf int state; 578b9b0cc2SKevin Wolf union { 588b9b0cc2SKevin Wolf struct { 598b9b0cc2SKevin Wolf int error; 608b9b0cc2SKevin Wolf int immediately; 618b9b0cc2SKevin Wolf int once; 62*e4780db4SPaolo Bonzini int64_t sector; 638b9b0cc2SKevin Wolf } inject; 648b9b0cc2SKevin Wolf struct { 658b9b0cc2SKevin Wolf int new_state; 668b9b0cc2SKevin Wolf } set_state; 678b9b0cc2SKevin Wolf } options; 688b9b0cc2SKevin Wolf QLIST_ENTRY(BlkdebugRule) next; 69571cd43eSPaolo Bonzini QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 708b9b0cc2SKevin Wolf } BlkdebugRule; 718b9b0cc2SKevin Wolf 728b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = { 738b9b0cc2SKevin Wolf .name = "inject-error", 748b9b0cc2SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 758b9b0cc2SKevin Wolf .desc = { 768b9b0cc2SKevin Wolf { 778b9b0cc2SKevin Wolf .name = "event", 788b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 798b9b0cc2SKevin Wolf }, 808b9b0cc2SKevin Wolf { 818b9b0cc2SKevin Wolf .name = "state", 828b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 838b9b0cc2SKevin Wolf }, 848b9b0cc2SKevin Wolf { 858b9b0cc2SKevin Wolf .name = "errno", 868b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 878b9b0cc2SKevin Wolf }, 888b9b0cc2SKevin Wolf { 89*e4780db4SPaolo Bonzini .name = "sector", 90*e4780db4SPaolo Bonzini .type = QEMU_OPT_NUMBER, 91*e4780db4SPaolo Bonzini }, 92*e4780db4SPaolo Bonzini { 938b9b0cc2SKevin Wolf .name = "once", 948b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 958b9b0cc2SKevin Wolf }, 968b9b0cc2SKevin Wolf { 978b9b0cc2SKevin Wolf .name = "immediately", 988b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 998b9b0cc2SKevin Wolf }, 1008b9b0cc2SKevin Wolf { /* end of list */ } 1018b9b0cc2SKevin Wolf }, 1028b9b0cc2SKevin Wolf }; 1038b9b0cc2SKevin Wolf 1048b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = { 1058b9b0cc2SKevin Wolf .name = "set-state", 106327cdad4SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 1078b9b0cc2SKevin Wolf .desc = { 1088b9b0cc2SKevin Wolf { 1098b9b0cc2SKevin Wolf .name = "event", 1108b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 1118b9b0cc2SKevin Wolf }, 1128b9b0cc2SKevin Wolf { 1138b9b0cc2SKevin Wolf .name = "state", 1148b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1158b9b0cc2SKevin Wolf }, 1168b9b0cc2SKevin Wolf { 1178b9b0cc2SKevin Wolf .name = "new_state", 1188b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1198b9b0cc2SKevin Wolf }, 1208b9b0cc2SKevin Wolf { /* end of list */ } 1218b9b0cc2SKevin Wolf }, 1228b9b0cc2SKevin Wolf }; 1238b9b0cc2SKevin Wolf 1248b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = { 1258b9b0cc2SKevin Wolf &inject_error_opts, 1268b9b0cc2SKevin Wolf &set_state_opts, 1278b9b0cc2SKevin Wolf NULL 1288b9b0cc2SKevin Wolf }; 1298b9b0cc2SKevin Wolf 1308b9b0cc2SKevin Wolf static const char *event_names[BLKDBG_EVENT_MAX] = { 1318252278aSKevin Wolf [BLKDBG_L1_UPDATE] = "l1_update", 1328252278aSKevin Wolf [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table", 1338252278aSKevin Wolf [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table", 1348252278aSKevin Wolf [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table", 1358252278aSKevin Wolf 1368252278aSKevin Wolf [BLKDBG_L2_LOAD] = "l2_load", 1378252278aSKevin Wolf [BLKDBG_L2_UPDATE] = "l2_update", 1388252278aSKevin Wolf [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed", 1398252278aSKevin Wolf [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read", 1408252278aSKevin Wolf [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write", 1418252278aSKevin Wolf 1428252278aSKevin Wolf [BLKDBG_READ_AIO] = "read_aio", 1438252278aSKevin Wolf [BLKDBG_READ_BACKING_AIO] = "read_backing_aio", 1448252278aSKevin Wolf [BLKDBG_READ_COMPRESSED] = "read_compressed", 1458252278aSKevin Wolf 1468252278aSKevin Wolf [BLKDBG_WRITE_AIO] = "write_aio", 1478252278aSKevin Wolf [BLKDBG_WRITE_COMPRESSED] = "write_compressed", 1488252278aSKevin Wolf 1498252278aSKevin Wolf [BLKDBG_VMSTATE_LOAD] = "vmstate_load", 1508252278aSKevin Wolf [BLKDBG_VMSTATE_SAVE] = "vmstate_save", 1518252278aSKevin Wolf 1528252278aSKevin Wolf [BLKDBG_COW_READ] = "cow_read", 1538252278aSKevin Wolf [BLKDBG_COW_WRITE] = "cow_write", 1548252278aSKevin Wolf 1558252278aSKevin Wolf [BLKDBG_REFTABLE_LOAD] = "reftable_load", 1568252278aSKevin Wolf [BLKDBG_REFTABLE_GROW] = "reftable_grow", 1578252278aSKevin Wolf 1588252278aSKevin Wolf [BLKDBG_REFBLOCK_LOAD] = "refblock_load", 1598252278aSKevin Wolf [BLKDBG_REFBLOCK_UPDATE] = "refblock_update", 1608252278aSKevin Wolf [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part", 1618252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc", 1628252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup", 1638252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write", 1648252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks", 1658252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table", 1668252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table", 1678252278aSKevin Wolf 1688252278aSKevin Wolf [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc", 1698252278aSKevin Wolf [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", 1708252278aSKevin Wolf [BLKDBG_CLUSTER_FREE] = "cluster_free", 1718b9b0cc2SKevin Wolf }; 1728b9b0cc2SKevin Wolf 1738b9b0cc2SKevin Wolf static int get_event_by_name(const char *name, BlkDebugEvent *event) 1748b9b0cc2SKevin Wolf { 1758b9b0cc2SKevin Wolf int i; 1768b9b0cc2SKevin Wolf 1778b9b0cc2SKevin Wolf for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 1788b9b0cc2SKevin Wolf if (!strcmp(event_names[i], name)) { 1798b9b0cc2SKevin Wolf *event = i; 1808b9b0cc2SKevin Wolf return 0; 1818b9b0cc2SKevin Wolf } 1828b9b0cc2SKevin Wolf } 1838b9b0cc2SKevin Wolf 1848b9b0cc2SKevin Wolf return -1; 1858b9b0cc2SKevin Wolf } 1868b9b0cc2SKevin Wolf 1878b9b0cc2SKevin Wolf struct add_rule_data { 1888b9b0cc2SKevin Wolf BDRVBlkdebugState *s; 1898b9b0cc2SKevin Wolf int action; 1908b9b0cc2SKevin Wolf }; 1918b9b0cc2SKevin Wolf 1928b9b0cc2SKevin Wolf static int add_rule(QemuOpts *opts, void *opaque) 1938b9b0cc2SKevin Wolf { 1948b9b0cc2SKevin Wolf struct add_rule_data *d = opaque; 1958b9b0cc2SKevin Wolf BDRVBlkdebugState *s = d->s; 1968b9b0cc2SKevin Wolf const char* event_name; 1978b9b0cc2SKevin Wolf BlkDebugEvent event; 1988b9b0cc2SKevin Wolf struct BlkdebugRule *rule; 1998b9b0cc2SKevin Wolf 2008b9b0cc2SKevin Wolf /* Find the right event for the rule */ 2018b9b0cc2SKevin Wolf event_name = qemu_opt_get(opts, "event"); 2028b9b0cc2SKevin Wolf if (!event_name || get_event_by_name(event_name, &event) < 0) { 2038b9b0cc2SKevin Wolf return -1; 2048b9b0cc2SKevin Wolf } 2058b9b0cc2SKevin Wolf 2068b9b0cc2SKevin Wolf /* Set attributes common for all actions */ 2077267c094SAnthony Liguori rule = g_malloc0(sizeof(*rule)); 2088b9b0cc2SKevin Wolf *rule = (struct BlkdebugRule) { 2098b9b0cc2SKevin Wolf .event = event, 2108b9b0cc2SKevin Wolf .action = d->action, 2118b9b0cc2SKevin Wolf .state = qemu_opt_get_number(opts, "state", 0), 2128b9b0cc2SKevin Wolf }; 2138b9b0cc2SKevin Wolf 2148b9b0cc2SKevin Wolf /* Parse action-specific options */ 2158b9b0cc2SKevin Wolf switch (d->action) { 2168b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 2178b9b0cc2SKevin Wolf rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 2188b9b0cc2SKevin Wolf rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 2198b9b0cc2SKevin Wolf rule->options.inject.immediately = 2208b9b0cc2SKevin Wolf qemu_opt_get_bool(opts, "immediately", 0); 221*e4780db4SPaolo Bonzini rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); 2228b9b0cc2SKevin Wolf break; 2238b9b0cc2SKevin Wolf 2248b9b0cc2SKevin Wolf case ACTION_SET_STATE: 2258b9b0cc2SKevin Wolf rule->options.set_state.new_state = 2268b9b0cc2SKevin Wolf qemu_opt_get_number(opts, "new_state", 0); 2278b9b0cc2SKevin Wolf break; 2288b9b0cc2SKevin Wolf }; 2298b9b0cc2SKevin Wolf 2308b9b0cc2SKevin Wolf /* Add the rule */ 2318b9b0cc2SKevin Wolf QLIST_INSERT_HEAD(&s->rules[event], rule, next); 2328b9b0cc2SKevin Wolf 2338b9b0cc2SKevin Wolf return 0; 2348b9b0cc2SKevin Wolf } 2358b9b0cc2SKevin Wolf 2368b9b0cc2SKevin Wolf static int read_config(BDRVBlkdebugState *s, const char *filename) 2378b9b0cc2SKevin Wolf { 2388b9b0cc2SKevin Wolf FILE *f; 2398b9b0cc2SKevin Wolf int ret; 2408b9b0cc2SKevin Wolf struct add_rule_data d; 2418b9b0cc2SKevin Wolf 2428b9b0cc2SKevin Wolf f = fopen(filename, "r"); 2438b9b0cc2SKevin Wolf if (f == NULL) { 2448b9b0cc2SKevin Wolf return -errno; 2458b9b0cc2SKevin Wolf } 2468b9b0cc2SKevin Wolf 2478b9b0cc2SKevin Wolf ret = qemu_config_parse(f, config_groups, filename); 2488b9b0cc2SKevin Wolf if (ret < 0) { 2498b9b0cc2SKevin Wolf goto fail; 2508b9b0cc2SKevin Wolf } 2518b9b0cc2SKevin Wolf 2528b9b0cc2SKevin Wolf d.s = s; 2538b9b0cc2SKevin Wolf d.action = ACTION_INJECT_ERROR; 2548b9b0cc2SKevin Wolf qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0); 2558b9b0cc2SKevin Wolf 2568b9b0cc2SKevin Wolf d.action = ACTION_SET_STATE; 2578b9b0cc2SKevin Wolf qemu_opts_foreach(&set_state_opts, add_rule, &d, 0); 2588b9b0cc2SKevin Wolf 2598b9b0cc2SKevin Wolf ret = 0; 2608b9b0cc2SKevin Wolf fail: 261698f0d52SKevin Wolf qemu_opts_reset(&inject_error_opts); 262698f0d52SKevin Wolf qemu_opts_reset(&set_state_opts); 2638b9b0cc2SKevin Wolf fclose(f); 2648b9b0cc2SKevin Wolf return ret; 2658b9b0cc2SKevin Wolf } 2668b9b0cc2SKevin Wolf 2678b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 2686a143727SKevin Wolf static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) 2696a143727SKevin Wolf { 2706a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 2718b9b0cc2SKevin Wolf int ret; 2728b9b0cc2SKevin Wolf char *config, *c; 2736a143727SKevin Wolf 2748b9b0cc2SKevin Wolf /* Parse the blkdebug: prefix */ 2756a143727SKevin Wolf if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) { 2766a143727SKevin Wolf return -EINVAL; 2776a143727SKevin Wolf } 2786a143727SKevin Wolf filename += strlen("blkdebug:"); 2796a143727SKevin Wolf 2808b9b0cc2SKevin Wolf /* Read rules from config file */ 2818b9b0cc2SKevin Wolf c = strchr(filename, ':'); 2828b9b0cc2SKevin Wolf if (c == NULL) { 2838b9b0cc2SKevin Wolf return -EINVAL; 2848b9b0cc2SKevin Wolf } 2858b9b0cc2SKevin Wolf 286031380d8SStefan Hajnoczi config = g_strdup(filename); 2878b9b0cc2SKevin Wolf config[c - filename] = '\0'; 2888b9b0cc2SKevin Wolf ret = read_config(s, config); 289031380d8SStefan Hajnoczi g_free(config); 2908b9b0cc2SKevin Wolf if (ret < 0) { 2918b9b0cc2SKevin Wolf return ret; 2928b9b0cc2SKevin Wolf } 2938b9b0cc2SKevin Wolf filename = c + 1; 2948b9b0cc2SKevin Wolf 2958db520ceSKevin Wolf /* Set initial state */ 296571cd43eSPaolo Bonzini s->state = 1; 2978db520ceSKevin Wolf 2988b9b0cc2SKevin Wolf /* Open the backing file */ 29966f82ceeSKevin Wolf ret = bdrv_file_open(&bs->file, filename, flags); 3008b9b0cc2SKevin Wolf if (ret < 0) { 3018b9b0cc2SKevin Wolf return ret; 3028b9b0cc2SKevin Wolf } 3038b9b0cc2SKevin Wolf 3048b9b0cc2SKevin Wolf return 0; 3056a143727SKevin Wolf } 3066a143727SKevin Wolf 307b9f66d96SKevin Wolf static void error_callback_bh(void *opaque) 308b9f66d96SKevin Wolf { 309b9f66d96SKevin Wolf struct BlkdebugAIOCB *acb = opaque; 310b9f66d96SKevin Wolf qemu_bh_delete(acb->bh); 311b9f66d96SKevin Wolf acb->common.cb(acb->common.opaque, acb->ret); 312b9f66d96SKevin Wolf qemu_aio_release(acb); 313b9f66d96SKevin Wolf } 314b9f66d96SKevin Wolf 315b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) 316b9f66d96SKevin Wolf { 317b666d239SKevin Wolf BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); 318b9f66d96SKevin Wolf qemu_aio_release(acb); 319b9f66d96SKevin Wolf } 320b9f66d96SKevin Wolf 321b9f66d96SKevin Wolf static BlockDriverAIOCB *inject_error(BlockDriverState *bs, 322571cd43eSPaolo Bonzini BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule) 323b9f66d96SKevin Wolf { 324b9f66d96SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 325571cd43eSPaolo Bonzini int error = rule->options.inject.error; 326b9f66d96SKevin Wolf struct BlkdebugAIOCB *acb; 327b9f66d96SKevin Wolf QEMUBH *bh; 328b9f66d96SKevin Wolf 329571cd43eSPaolo Bonzini if (rule->options.inject.once) { 330571cd43eSPaolo Bonzini QSIMPLEQ_INIT(&s->active_rules); 331b9f66d96SKevin Wolf } 332b9f66d96SKevin Wolf 333571cd43eSPaolo Bonzini if (rule->options.inject.immediately) { 334b9f66d96SKevin Wolf return NULL; 335b9f66d96SKevin Wolf } 336b9f66d96SKevin Wolf 337b9f66d96SKevin Wolf acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque); 338b9f66d96SKevin Wolf acb->ret = -error; 339b9f66d96SKevin Wolf 340b9f66d96SKevin Wolf bh = qemu_bh_new(error_callback_bh, acb); 341b9f66d96SKevin Wolf acb->bh = bh; 342b9f66d96SKevin Wolf qemu_bh_schedule(bh); 343b9f66d96SKevin Wolf 344b666d239SKevin Wolf return &acb->common; 345b9f66d96SKevin Wolf } 346b9f66d96SKevin Wolf 3476a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, 3486a143727SKevin Wolf int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 3496a143727SKevin Wolf BlockDriverCompletionFunc *cb, void *opaque) 3506a143727SKevin Wolf { 3516a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 352*e4780db4SPaolo Bonzini BlkdebugRule *rule = NULL; 353*e4780db4SPaolo Bonzini 354*e4780db4SPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 355*e4780db4SPaolo Bonzini if (rule->options.inject.sector == -1 || 356*e4780db4SPaolo Bonzini (rule->options.inject.sector >= sector_num && 357*e4780db4SPaolo Bonzini rule->options.inject.sector < sector_num + nb_sectors)) { 358*e4780db4SPaolo Bonzini break; 359*e4780db4SPaolo Bonzini } 360*e4780db4SPaolo Bonzini } 361b9f66d96SKevin Wolf 362571cd43eSPaolo Bonzini if (rule && rule->options.inject.error) { 363571cd43eSPaolo Bonzini return inject_error(bs, cb, opaque, rule); 364b9f66d96SKevin Wolf } 365b9f66d96SKevin Wolf 366368e8dd1SPaolo Bonzini return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 3676a143727SKevin Wolf } 3686a143727SKevin Wolf 3696a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, 3706a143727SKevin Wolf int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 3716a143727SKevin Wolf BlockDriverCompletionFunc *cb, void *opaque) 3726a143727SKevin Wolf { 3736a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 374*e4780db4SPaolo Bonzini BlkdebugRule *rule = NULL; 375*e4780db4SPaolo Bonzini 376*e4780db4SPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 377*e4780db4SPaolo Bonzini if (rule->options.inject.sector == -1 || 378*e4780db4SPaolo Bonzini (rule->options.inject.sector >= sector_num && 379*e4780db4SPaolo Bonzini rule->options.inject.sector < sector_num + nb_sectors)) { 380*e4780db4SPaolo Bonzini break; 381*e4780db4SPaolo Bonzini } 382*e4780db4SPaolo Bonzini } 383b9f66d96SKevin Wolf 384571cd43eSPaolo Bonzini if (rule && rule->options.inject.error) { 385571cd43eSPaolo Bonzini return inject_error(bs, cb, opaque, rule); 386b9f66d96SKevin Wolf } 387b9f66d96SKevin Wolf 388368e8dd1SPaolo Bonzini return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 3896a143727SKevin Wolf } 3906a143727SKevin Wolf 3916a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs) 3926a143727SKevin Wolf { 3936a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 3948b9b0cc2SKevin Wolf BlkdebugRule *rule, *next; 3958b9b0cc2SKevin Wolf int i; 3968b9b0cc2SKevin Wolf 3978b9b0cc2SKevin Wolf for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 3988b9b0cc2SKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 3998b9b0cc2SKevin Wolf QLIST_REMOVE(rule, next); 4007267c094SAnthony Liguori g_free(rule); 4018b9b0cc2SKevin Wolf } 4028b9b0cc2SKevin Wolf } 4036a143727SKevin Wolf } 4046a143727SKevin Wolf 405571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 406571cd43eSPaolo Bonzini int old_state, bool injected) 4078b9b0cc2SKevin Wolf { 4088b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 4098b9b0cc2SKevin Wolf 4108b9b0cc2SKevin Wolf /* Only process rules for the current state */ 411571cd43eSPaolo Bonzini if (rule->state && rule->state != old_state) { 412571cd43eSPaolo Bonzini return injected; 4138b9b0cc2SKevin Wolf } 4148b9b0cc2SKevin Wolf 4158b9b0cc2SKevin Wolf /* Take the action */ 4168b9b0cc2SKevin Wolf switch (rule->action) { 4178b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 418571cd43eSPaolo Bonzini if (!injected) { 419571cd43eSPaolo Bonzini QSIMPLEQ_INIT(&s->active_rules); 420571cd43eSPaolo Bonzini injected = true; 421571cd43eSPaolo Bonzini } 422571cd43eSPaolo Bonzini QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 4238b9b0cc2SKevin Wolf break; 4248b9b0cc2SKevin Wolf 4258b9b0cc2SKevin Wolf case ACTION_SET_STATE: 426571cd43eSPaolo Bonzini s->state = rule->options.set_state.new_state; 4278b9b0cc2SKevin Wolf break; 4288b9b0cc2SKevin Wolf } 429571cd43eSPaolo Bonzini return injected; 4308b9b0cc2SKevin Wolf } 4318b9b0cc2SKevin Wolf 4328b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) 4338b9b0cc2SKevin Wolf { 4348b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 4358b9b0cc2SKevin Wolf struct BlkdebugRule *rule; 436571cd43eSPaolo Bonzini int old_state = s->state; 437571cd43eSPaolo Bonzini bool injected; 4388b9b0cc2SKevin Wolf 43995ee3914SBlue Swirl assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); 4408b9b0cc2SKevin Wolf 441571cd43eSPaolo Bonzini injected = false; 4428b9b0cc2SKevin Wolf QLIST_FOREACH(rule, &s->rules[event], next) { 443571cd43eSPaolo Bonzini injected = process_rule(bs, rule, old_state, injected); 4448b9b0cc2SKevin Wolf } 4458b9b0cc2SKevin Wolf } 4468b9b0cc2SKevin Wolf 447e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs) 448e1302255SPaolo Bonzini { 449e1302255SPaolo Bonzini return bdrv_getlength(bs->file); 450e1302255SPaolo Bonzini } 451e1302255SPaolo Bonzini 4526a143727SKevin Wolf static BlockDriver bdrv_blkdebug = { 4536a143727SKevin Wolf .format_name = "blkdebug", 4546a143727SKevin Wolf .protocol_name = "blkdebug", 4556a143727SKevin Wolf 4566a143727SKevin Wolf .instance_size = sizeof(BDRVBlkdebugState), 4576a143727SKevin Wolf 45866f82ceeSKevin Wolf .bdrv_file_open = blkdebug_open, 4596a143727SKevin Wolf .bdrv_close = blkdebug_close, 460e1302255SPaolo Bonzini .bdrv_getlength = blkdebug_getlength, 4616a143727SKevin Wolf 4626a143727SKevin Wolf .bdrv_aio_readv = blkdebug_aio_readv, 4636a143727SKevin Wolf .bdrv_aio_writev = blkdebug_aio_writev, 4648b9b0cc2SKevin Wolf 4658b9b0cc2SKevin Wolf .bdrv_debug_event = blkdebug_debug_event, 4666a143727SKevin Wolf }; 4676a143727SKevin Wolf 4686a143727SKevin Wolf static void bdrv_blkdebug_init(void) 4696a143727SKevin Wolf { 4706a143727SKevin Wolf bdrv_register(&bdrv_blkdebug); 4716a143727SKevin Wolf } 4726a143727SKevin Wolf 4736a143727SKevin Wolf block_init(bdrv_blkdebug_init); 474