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" 261de7afc9SPaolo Bonzini #include "qemu/config-file.h" 27737e150eSPaolo Bonzini #include "block/block_int.h" 281de7afc9SPaolo Bonzini #include "qemu/module.h" 296a143727SKevin Wolf 306a143727SKevin Wolf typedef struct BDRVBlkdebugState { 31571cd43eSPaolo Bonzini int state; 328f96b5beSPaolo Bonzini int new_state; 333c90c65dSKevin Wolf 34571cd43eSPaolo Bonzini QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; 35571cd43eSPaolo Bonzini QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 363c90c65dSKevin Wolf QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 376a143727SKevin Wolf } BDRVBlkdebugState; 386a143727SKevin Wolf 39b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB { 40b9f66d96SKevin Wolf BlockDriverAIOCB common; 41b9f66d96SKevin Wolf QEMUBH *bh; 42b9f66d96SKevin Wolf int ret; 43b9f66d96SKevin Wolf } BlkdebugAIOCB; 44b9f66d96SKevin Wolf 453c90c65dSKevin Wolf typedef struct BlkdebugSuspendedReq { 463c90c65dSKevin Wolf Coroutine *co; 473c90c65dSKevin Wolf char *tag; 483c90c65dSKevin Wolf QLIST_ENTRY(BlkdebugSuspendedReq) next; 493c90c65dSKevin Wolf } BlkdebugSuspendedReq; 503c90c65dSKevin Wolf 51b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); 52b9f66d96SKevin Wolf 53d7331bedSStefan Hajnoczi static const AIOCBInfo blkdebug_aiocb_info = { 54b9f66d96SKevin Wolf .aiocb_size = sizeof(BlkdebugAIOCB), 55b9f66d96SKevin Wolf .cancel = blkdebug_aio_cancel, 56b9f66d96SKevin Wolf }; 57b9f66d96SKevin Wolf 588b9b0cc2SKevin Wolf enum { 598b9b0cc2SKevin Wolf ACTION_INJECT_ERROR, 608b9b0cc2SKevin Wolf ACTION_SET_STATE, 613c90c65dSKevin Wolf ACTION_SUSPEND, 628b9b0cc2SKevin Wolf }; 638b9b0cc2SKevin Wolf 648b9b0cc2SKevin Wolf typedef struct BlkdebugRule { 658b9b0cc2SKevin Wolf BlkDebugEvent event; 668b9b0cc2SKevin Wolf int action; 678b9b0cc2SKevin Wolf int state; 688b9b0cc2SKevin Wolf union { 698b9b0cc2SKevin Wolf struct { 708b9b0cc2SKevin Wolf int error; 718b9b0cc2SKevin Wolf int immediately; 728b9b0cc2SKevin Wolf int once; 73e4780db4SPaolo Bonzini int64_t sector; 748b9b0cc2SKevin Wolf } inject; 758b9b0cc2SKevin Wolf struct { 768b9b0cc2SKevin Wolf int new_state; 778b9b0cc2SKevin Wolf } set_state; 783c90c65dSKevin Wolf struct { 793c90c65dSKevin Wolf char *tag; 803c90c65dSKevin Wolf } suspend; 818b9b0cc2SKevin Wolf } options; 828b9b0cc2SKevin Wolf QLIST_ENTRY(BlkdebugRule) next; 83571cd43eSPaolo Bonzini QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 848b9b0cc2SKevin Wolf } BlkdebugRule; 858b9b0cc2SKevin Wolf 868b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = { 878b9b0cc2SKevin Wolf .name = "inject-error", 888b9b0cc2SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 898b9b0cc2SKevin Wolf .desc = { 908b9b0cc2SKevin Wolf { 918b9b0cc2SKevin Wolf .name = "event", 928b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 938b9b0cc2SKevin Wolf }, 948b9b0cc2SKevin Wolf { 958b9b0cc2SKevin Wolf .name = "state", 968b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 978b9b0cc2SKevin Wolf }, 988b9b0cc2SKevin Wolf { 998b9b0cc2SKevin Wolf .name = "errno", 1008b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1018b9b0cc2SKevin Wolf }, 1028b9b0cc2SKevin Wolf { 103e4780db4SPaolo Bonzini .name = "sector", 104e4780db4SPaolo Bonzini .type = QEMU_OPT_NUMBER, 105e4780db4SPaolo Bonzini }, 106e4780db4SPaolo Bonzini { 1078b9b0cc2SKevin Wolf .name = "once", 1088b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 1098b9b0cc2SKevin Wolf }, 1108b9b0cc2SKevin Wolf { 1118b9b0cc2SKevin Wolf .name = "immediately", 1128b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 1138b9b0cc2SKevin Wolf }, 1148b9b0cc2SKevin Wolf { /* end of list */ } 1158b9b0cc2SKevin Wolf }, 1168b9b0cc2SKevin Wolf }; 1178b9b0cc2SKevin Wolf 1188b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = { 1198b9b0cc2SKevin Wolf .name = "set-state", 120327cdad4SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 1218b9b0cc2SKevin Wolf .desc = { 1228b9b0cc2SKevin Wolf { 1238b9b0cc2SKevin Wolf .name = "event", 1248b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 1258b9b0cc2SKevin Wolf }, 1268b9b0cc2SKevin Wolf { 1278b9b0cc2SKevin Wolf .name = "state", 1288b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1298b9b0cc2SKevin Wolf }, 1308b9b0cc2SKevin Wolf { 1318b9b0cc2SKevin Wolf .name = "new_state", 1328b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1338b9b0cc2SKevin Wolf }, 1348b9b0cc2SKevin Wolf { /* end of list */ } 1358b9b0cc2SKevin Wolf }, 1368b9b0cc2SKevin Wolf }; 1378b9b0cc2SKevin Wolf 1388b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = { 1398b9b0cc2SKevin Wolf &inject_error_opts, 1408b9b0cc2SKevin Wolf &set_state_opts, 1418b9b0cc2SKevin Wolf NULL 1428b9b0cc2SKevin Wolf }; 1438b9b0cc2SKevin Wolf 1448b9b0cc2SKevin Wolf static const char *event_names[BLKDBG_EVENT_MAX] = { 1458252278aSKevin Wolf [BLKDBG_L1_UPDATE] = "l1_update", 1468252278aSKevin Wolf [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table", 1478252278aSKevin Wolf [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table", 1488252278aSKevin Wolf [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table", 1498252278aSKevin Wolf 1508252278aSKevin Wolf [BLKDBG_L2_LOAD] = "l2_load", 1518252278aSKevin Wolf [BLKDBG_L2_UPDATE] = "l2_update", 1528252278aSKevin Wolf [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed", 1538252278aSKevin Wolf [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read", 1548252278aSKevin Wolf [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write", 1558252278aSKevin Wolf 1568252278aSKevin Wolf [BLKDBG_READ_AIO] = "read_aio", 1578252278aSKevin Wolf [BLKDBG_READ_BACKING_AIO] = "read_backing_aio", 1588252278aSKevin Wolf [BLKDBG_READ_COMPRESSED] = "read_compressed", 1598252278aSKevin Wolf 1608252278aSKevin Wolf [BLKDBG_WRITE_AIO] = "write_aio", 1618252278aSKevin Wolf [BLKDBG_WRITE_COMPRESSED] = "write_compressed", 1628252278aSKevin Wolf 1638252278aSKevin Wolf [BLKDBG_VMSTATE_LOAD] = "vmstate_load", 1648252278aSKevin Wolf [BLKDBG_VMSTATE_SAVE] = "vmstate_save", 1658252278aSKevin Wolf 1668252278aSKevin Wolf [BLKDBG_COW_READ] = "cow_read", 1678252278aSKevin Wolf [BLKDBG_COW_WRITE] = "cow_write", 1688252278aSKevin Wolf 1698252278aSKevin Wolf [BLKDBG_REFTABLE_LOAD] = "reftable_load", 1708252278aSKevin Wolf [BLKDBG_REFTABLE_GROW] = "reftable_grow", 171afa50193SMax Reitz [BLKDBG_REFTABLE_UPDATE] = "reftable_update", 1728252278aSKevin Wolf 1738252278aSKevin Wolf [BLKDBG_REFBLOCK_LOAD] = "refblock_load", 1748252278aSKevin Wolf [BLKDBG_REFBLOCK_UPDATE] = "refblock_update", 1758252278aSKevin Wolf [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part", 1768252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc", 1778252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup", 1788252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write", 1798252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks", 1808252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table", 1818252278aSKevin Wolf [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table", 1828252278aSKevin Wolf 1838252278aSKevin Wolf [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc", 1848252278aSKevin Wolf [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", 1858252278aSKevin Wolf [BLKDBG_CLUSTER_FREE] = "cluster_free", 186bf736fe3SKevin Wolf 187bf736fe3SKevin Wolf [BLKDBG_FLUSH_TO_OS] = "flush_to_os", 188bf736fe3SKevin Wolf [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk", 1898b9b0cc2SKevin Wolf }; 1908b9b0cc2SKevin Wolf 1918b9b0cc2SKevin Wolf static int get_event_by_name(const char *name, BlkDebugEvent *event) 1928b9b0cc2SKevin Wolf { 1938b9b0cc2SKevin Wolf int i; 1948b9b0cc2SKevin Wolf 1958b9b0cc2SKevin Wolf for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 1968b9b0cc2SKevin Wolf if (!strcmp(event_names[i], name)) { 1978b9b0cc2SKevin Wolf *event = i; 1988b9b0cc2SKevin Wolf return 0; 1998b9b0cc2SKevin Wolf } 2008b9b0cc2SKevin Wolf } 2018b9b0cc2SKevin Wolf 2028b9b0cc2SKevin Wolf return -1; 2038b9b0cc2SKevin Wolf } 2048b9b0cc2SKevin Wolf 2058b9b0cc2SKevin Wolf struct add_rule_data { 2068b9b0cc2SKevin Wolf BDRVBlkdebugState *s; 2078b9b0cc2SKevin Wolf int action; 2088b9b0cc2SKevin Wolf }; 2098b9b0cc2SKevin Wolf 2108b9b0cc2SKevin Wolf static int add_rule(QemuOpts *opts, void *opaque) 2118b9b0cc2SKevin Wolf { 2128b9b0cc2SKevin Wolf struct add_rule_data *d = opaque; 2138b9b0cc2SKevin Wolf BDRVBlkdebugState *s = d->s; 2148b9b0cc2SKevin Wolf const char* event_name; 2158b9b0cc2SKevin Wolf BlkDebugEvent event; 2168b9b0cc2SKevin Wolf struct BlkdebugRule *rule; 2178b9b0cc2SKevin Wolf 2188b9b0cc2SKevin Wolf /* Find the right event for the rule */ 2198b9b0cc2SKevin Wolf event_name = qemu_opt_get(opts, "event"); 2208b9b0cc2SKevin Wolf if (!event_name || get_event_by_name(event_name, &event) < 0) { 2218b9b0cc2SKevin Wolf return -1; 2228b9b0cc2SKevin Wolf } 2238b9b0cc2SKevin Wolf 2248b9b0cc2SKevin Wolf /* Set attributes common for all actions */ 2257267c094SAnthony Liguori rule = g_malloc0(sizeof(*rule)); 2268b9b0cc2SKevin Wolf *rule = (struct BlkdebugRule) { 2278b9b0cc2SKevin Wolf .event = event, 2288b9b0cc2SKevin Wolf .action = d->action, 2298b9b0cc2SKevin Wolf .state = qemu_opt_get_number(opts, "state", 0), 2308b9b0cc2SKevin Wolf }; 2318b9b0cc2SKevin Wolf 2328b9b0cc2SKevin Wolf /* Parse action-specific options */ 2338b9b0cc2SKevin Wolf switch (d->action) { 2348b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 2358b9b0cc2SKevin Wolf rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 2368b9b0cc2SKevin Wolf rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 2378b9b0cc2SKevin Wolf rule->options.inject.immediately = 2388b9b0cc2SKevin Wolf qemu_opt_get_bool(opts, "immediately", 0); 239e4780db4SPaolo Bonzini rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); 2408b9b0cc2SKevin Wolf break; 2418b9b0cc2SKevin Wolf 2428b9b0cc2SKevin Wolf case ACTION_SET_STATE: 2438b9b0cc2SKevin Wolf rule->options.set_state.new_state = 2448b9b0cc2SKevin Wolf qemu_opt_get_number(opts, "new_state", 0); 2458b9b0cc2SKevin Wolf break; 2463c90c65dSKevin Wolf 2473c90c65dSKevin Wolf case ACTION_SUSPEND: 2483c90c65dSKevin Wolf rule->options.suspend.tag = 2493c90c65dSKevin Wolf g_strdup(qemu_opt_get(opts, "tag")); 2503c90c65dSKevin Wolf break; 2518b9b0cc2SKevin Wolf }; 2528b9b0cc2SKevin Wolf 2538b9b0cc2SKevin Wolf /* Add the rule */ 2548b9b0cc2SKevin Wolf QLIST_INSERT_HEAD(&s->rules[event], rule, next); 2558b9b0cc2SKevin Wolf 2568b9b0cc2SKevin Wolf return 0; 2578b9b0cc2SKevin Wolf } 2588b9b0cc2SKevin Wolf 2599e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule) 2609e35542bSKevin Wolf { 2619e35542bSKevin Wolf switch (rule->action) { 2629e35542bSKevin Wolf case ACTION_INJECT_ERROR: 2639e35542bSKevin Wolf case ACTION_SET_STATE: 2649e35542bSKevin Wolf break; 2653c90c65dSKevin Wolf case ACTION_SUSPEND: 2663c90c65dSKevin Wolf g_free(rule->options.suspend.tag); 2673c90c65dSKevin Wolf break; 2689e35542bSKevin Wolf } 2699e35542bSKevin Wolf 2709e35542bSKevin Wolf QLIST_REMOVE(rule, next); 2719e35542bSKevin Wolf g_free(rule); 2729e35542bSKevin Wolf } 2739e35542bSKevin Wolf 2748b9b0cc2SKevin Wolf static int read_config(BDRVBlkdebugState *s, const char *filename) 2758b9b0cc2SKevin Wolf { 2768b9b0cc2SKevin Wolf FILE *f; 2778b9b0cc2SKevin Wolf int ret; 2788b9b0cc2SKevin Wolf struct add_rule_data d; 2798b9b0cc2SKevin Wolf 2808b9b0cc2SKevin Wolf f = fopen(filename, "r"); 2818b9b0cc2SKevin Wolf if (f == NULL) { 2828b9b0cc2SKevin Wolf return -errno; 2838b9b0cc2SKevin Wolf } 2848b9b0cc2SKevin Wolf 2858b9b0cc2SKevin Wolf ret = qemu_config_parse(f, config_groups, filename); 2868b9b0cc2SKevin Wolf if (ret < 0) { 2878b9b0cc2SKevin Wolf goto fail; 2888b9b0cc2SKevin Wolf } 2898b9b0cc2SKevin Wolf 2908b9b0cc2SKevin Wolf d.s = s; 2918b9b0cc2SKevin Wolf d.action = ACTION_INJECT_ERROR; 2928b9b0cc2SKevin Wolf qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0); 2938b9b0cc2SKevin Wolf 2948b9b0cc2SKevin Wolf d.action = ACTION_SET_STATE; 2958b9b0cc2SKevin Wolf qemu_opts_foreach(&set_state_opts, add_rule, &d, 0); 2968b9b0cc2SKevin Wolf 2978b9b0cc2SKevin Wolf ret = 0; 2988b9b0cc2SKevin Wolf fail: 299698f0d52SKevin Wolf qemu_opts_reset(&inject_error_opts); 300698f0d52SKevin Wolf qemu_opts_reset(&set_state_opts); 3018b9b0cc2SKevin Wolf fclose(f); 3028b9b0cc2SKevin Wolf return ret; 3038b9b0cc2SKevin Wolf } 3048b9b0cc2SKevin Wolf 3058b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 306f4681212SKevin Wolf static void blkdebug_parse_filename(const char *filename, QDict *options, 307f4681212SKevin Wolf Error **errp) 308f4681212SKevin Wolf { 309f4681212SKevin Wolf const char *c; 310f4681212SKevin Wolf 311f4681212SKevin Wolf /* Parse the blkdebug: prefix */ 312f4681212SKevin Wolf if (!strstart(filename, "blkdebug:", &filename)) { 313f4681212SKevin Wolf error_setg(errp, "File name string must start with 'blkdebug:'"); 314f4681212SKevin Wolf return; 315f4681212SKevin Wolf } 316f4681212SKevin Wolf 317f4681212SKevin Wolf /* Parse config file path */ 318f4681212SKevin Wolf c = strchr(filename, ':'); 319f4681212SKevin Wolf if (c == NULL) { 320f4681212SKevin Wolf error_setg(errp, "blkdebug requires both config file and image path"); 321f4681212SKevin Wolf return; 322f4681212SKevin Wolf } 323f4681212SKevin Wolf 324f4681212SKevin Wolf if (c != filename) { 325f4681212SKevin Wolf QString *config_path; 326f4681212SKevin Wolf config_path = qstring_from_substr(filename, 0, c - filename - 1); 327f4681212SKevin Wolf qdict_put(options, "config", config_path); 328f4681212SKevin Wolf } 329f4681212SKevin Wolf 330f4681212SKevin Wolf /* TODO Allow multi-level nesting and set file.filename here */ 331f4681212SKevin Wolf filename = c + 1; 332f4681212SKevin Wolf qdict_put(options, "x-image", qstring_from_str(filename)); 333f4681212SKevin Wolf } 334f4681212SKevin Wolf 335f4681212SKevin Wolf static QemuOptsList runtime_opts = { 336f4681212SKevin Wolf .name = "blkdebug", 337f4681212SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 338f4681212SKevin Wolf .desc = { 339f4681212SKevin Wolf { 340f4681212SKevin Wolf .name = "config", 341f4681212SKevin Wolf .type = QEMU_OPT_STRING, 342f4681212SKevin Wolf .help = "Path to the configuration file", 343f4681212SKevin Wolf }, 344f4681212SKevin Wolf { 345f4681212SKevin Wolf .name = "x-image", 346f4681212SKevin Wolf .type = QEMU_OPT_STRING, 347f4681212SKevin Wolf .help = "[internal use only, will be removed]", 348f4681212SKevin Wolf }, 349f4681212SKevin Wolf { /* end of list */ } 350f4681212SKevin Wolf }, 351f4681212SKevin Wolf }; 352f4681212SKevin Wolf 353015a1036SMax Reitz static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, 354015a1036SMax Reitz Error **errp) 3556a143727SKevin Wolf { 3566a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 357f4681212SKevin Wolf QemuOpts *opts; 358f4681212SKevin Wolf Error *local_err = NULL; 359f4681212SKevin Wolf const char *filename, *config; 3608b9b0cc2SKevin Wolf int ret; 3616a143727SKevin Wolf 362f4681212SKevin Wolf opts = qemu_opts_create_nofail(&runtime_opts); 363f4681212SKevin Wolf qemu_opts_absorb_qdict(opts, options, &local_err); 364f4681212SKevin Wolf if (error_is_set(&local_err)) { 365*10ffa72fSMax Reitz error_propagate(errp, local_err); 366f4681212SKevin Wolf ret = -EINVAL; 367f4681212SKevin Wolf goto fail; 3686a143727SKevin Wolf } 3696a143727SKevin Wolf 3708b9b0cc2SKevin Wolf /* Read rules from config file */ 371f4681212SKevin Wolf config = qemu_opt_get(opts, "config"); 372f4681212SKevin Wolf if (config) { 3738b9b0cc2SKevin Wolf ret = read_config(s, config); 3748b9b0cc2SKevin Wolf if (ret < 0) { 375*10ffa72fSMax Reitz error_setg_errno(errp, -ret, "Could not read blkdebug config file"); 376f4681212SKevin Wolf goto fail; 3778b9b0cc2SKevin Wolf } 378f4681212SKevin Wolf } 3798b9b0cc2SKevin Wolf 3808db520ceSKevin Wolf /* Set initial state */ 381571cd43eSPaolo Bonzini s->state = 1; 3828db520ceSKevin Wolf 3838b9b0cc2SKevin Wolf /* Open the backing file */ 384f4681212SKevin Wolf filename = qemu_opt_get(opts, "x-image"); 385f4681212SKevin Wolf if (filename == NULL) { 386*10ffa72fSMax Reitz error_setg(errp, "Could not retrieve image file name"); 387f4681212SKevin Wolf ret = -EINVAL; 388f4681212SKevin Wolf goto fail; 3898b9b0cc2SKevin Wolf } 3908b9b0cc2SKevin Wolf 39134b5d2c6SMax Reitz ret = bdrv_file_open(&bs->file, filename, NULL, flags, &local_err); 392f4681212SKevin Wolf if (ret < 0) { 393*10ffa72fSMax Reitz error_propagate(errp, local_err); 394f4681212SKevin Wolf goto fail; 395f4681212SKevin Wolf } 396f4681212SKevin Wolf 397f4681212SKevin Wolf ret = 0; 398f4681212SKevin Wolf fail: 399f4681212SKevin Wolf qemu_opts_del(opts); 400f4681212SKevin Wolf return ret; 4016a143727SKevin Wolf } 4026a143727SKevin Wolf 403b9f66d96SKevin Wolf static void error_callback_bh(void *opaque) 404b9f66d96SKevin Wolf { 405b9f66d96SKevin Wolf struct BlkdebugAIOCB *acb = opaque; 406b9f66d96SKevin Wolf qemu_bh_delete(acb->bh); 407b9f66d96SKevin Wolf acb->common.cb(acb->common.opaque, acb->ret); 408b9f66d96SKevin Wolf qemu_aio_release(acb); 409b9f66d96SKevin Wolf } 410b9f66d96SKevin Wolf 411b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) 412b9f66d96SKevin Wolf { 413b666d239SKevin Wolf BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); 414b9f66d96SKevin Wolf qemu_aio_release(acb); 415b9f66d96SKevin Wolf } 416b9f66d96SKevin Wolf 417b9f66d96SKevin Wolf static BlockDriverAIOCB *inject_error(BlockDriverState *bs, 418571cd43eSPaolo Bonzini BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule) 419b9f66d96SKevin Wolf { 420b9f66d96SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 421571cd43eSPaolo Bonzini int error = rule->options.inject.error; 422b9f66d96SKevin Wolf struct BlkdebugAIOCB *acb; 423b9f66d96SKevin Wolf QEMUBH *bh; 424b9f66d96SKevin Wolf 425571cd43eSPaolo Bonzini if (rule->options.inject.once) { 426571cd43eSPaolo Bonzini QSIMPLEQ_INIT(&s->active_rules); 427b9f66d96SKevin Wolf } 428b9f66d96SKevin Wolf 429571cd43eSPaolo Bonzini if (rule->options.inject.immediately) { 430b9f66d96SKevin Wolf return NULL; 431b9f66d96SKevin Wolf } 432b9f66d96SKevin Wolf 433d7331bedSStefan Hajnoczi acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); 434b9f66d96SKevin Wolf acb->ret = -error; 435b9f66d96SKevin Wolf 436b9f66d96SKevin Wolf bh = qemu_bh_new(error_callback_bh, acb); 437b9f66d96SKevin Wolf acb->bh = bh; 438b9f66d96SKevin Wolf qemu_bh_schedule(bh); 439b9f66d96SKevin Wolf 440b666d239SKevin Wolf return &acb->common; 441b9f66d96SKevin Wolf } 442b9f66d96SKevin Wolf 4436a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, 4446a143727SKevin Wolf int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 4456a143727SKevin Wolf BlockDriverCompletionFunc *cb, void *opaque) 4466a143727SKevin Wolf { 4476a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 448e4780db4SPaolo Bonzini BlkdebugRule *rule = NULL; 449e4780db4SPaolo Bonzini 450e4780db4SPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 451e4780db4SPaolo Bonzini if (rule->options.inject.sector == -1 || 452e4780db4SPaolo Bonzini (rule->options.inject.sector >= sector_num && 453e4780db4SPaolo Bonzini rule->options.inject.sector < sector_num + nb_sectors)) { 454e4780db4SPaolo Bonzini break; 455e4780db4SPaolo Bonzini } 456e4780db4SPaolo Bonzini } 457b9f66d96SKevin Wolf 458571cd43eSPaolo Bonzini if (rule && rule->options.inject.error) { 459571cd43eSPaolo Bonzini return inject_error(bs, cb, opaque, rule); 460b9f66d96SKevin Wolf } 461b9f66d96SKevin Wolf 462368e8dd1SPaolo Bonzini return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 4636a143727SKevin Wolf } 4646a143727SKevin Wolf 4656a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, 4666a143727SKevin Wolf int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 4676a143727SKevin Wolf BlockDriverCompletionFunc *cb, void *opaque) 4686a143727SKevin Wolf { 4696a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 470e4780db4SPaolo Bonzini BlkdebugRule *rule = NULL; 471e4780db4SPaolo Bonzini 472e4780db4SPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 473e4780db4SPaolo Bonzini if (rule->options.inject.sector == -1 || 474e4780db4SPaolo Bonzini (rule->options.inject.sector >= sector_num && 475e4780db4SPaolo Bonzini rule->options.inject.sector < sector_num + nb_sectors)) { 476e4780db4SPaolo Bonzini break; 477e4780db4SPaolo Bonzini } 478e4780db4SPaolo Bonzini } 479b9f66d96SKevin Wolf 480571cd43eSPaolo Bonzini if (rule && rule->options.inject.error) { 481571cd43eSPaolo Bonzini return inject_error(bs, cb, opaque, rule); 482b9f66d96SKevin Wolf } 483b9f66d96SKevin Wolf 484368e8dd1SPaolo Bonzini return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); 4856a143727SKevin Wolf } 4866a143727SKevin Wolf 4873c90c65dSKevin Wolf 4886a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs) 4896a143727SKevin Wolf { 4906a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 4918b9b0cc2SKevin Wolf BlkdebugRule *rule, *next; 4928b9b0cc2SKevin Wolf int i; 4938b9b0cc2SKevin Wolf 4948b9b0cc2SKevin Wolf for (i = 0; i < BLKDBG_EVENT_MAX; i++) { 4958b9b0cc2SKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 4969e35542bSKevin Wolf remove_rule(rule); 4978b9b0cc2SKevin Wolf } 4988b9b0cc2SKevin Wolf } 4996a143727SKevin Wolf } 5006a143727SKevin Wolf 5013c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 5023c90c65dSKevin Wolf { 5033c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5043c90c65dSKevin Wolf BlkdebugSuspendedReq r; 5053c90c65dSKevin Wolf 5063c90c65dSKevin Wolf r = (BlkdebugSuspendedReq) { 5073c90c65dSKevin Wolf .co = qemu_coroutine_self(), 5083c90c65dSKevin Wolf .tag = g_strdup(rule->options.suspend.tag), 5093c90c65dSKevin Wolf }; 5103c90c65dSKevin Wolf 5113c90c65dSKevin Wolf remove_rule(rule); 5123c90c65dSKevin Wolf QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 5133c90c65dSKevin Wolf 5143c90c65dSKevin Wolf printf("blkdebug: Suspended request '%s'\n", r.tag); 5153c90c65dSKevin Wolf qemu_coroutine_yield(); 5163c90c65dSKevin Wolf printf("blkdebug: Resuming request '%s'\n", r.tag); 5173c90c65dSKevin Wolf 5183c90c65dSKevin Wolf QLIST_REMOVE(&r, next); 5193c90c65dSKevin Wolf g_free(r.tag); 5203c90c65dSKevin Wolf } 5213c90c65dSKevin Wolf 522571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 5238f96b5beSPaolo Bonzini bool injected) 5248b9b0cc2SKevin Wolf { 5258b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5268b9b0cc2SKevin Wolf 5278b9b0cc2SKevin Wolf /* Only process rules for the current state */ 5288f96b5beSPaolo Bonzini if (rule->state && rule->state != s->state) { 529571cd43eSPaolo Bonzini return injected; 5308b9b0cc2SKevin Wolf } 5318b9b0cc2SKevin Wolf 5328b9b0cc2SKevin Wolf /* Take the action */ 5338b9b0cc2SKevin Wolf switch (rule->action) { 5348b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 535571cd43eSPaolo Bonzini if (!injected) { 536571cd43eSPaolo Bonzini QSIMPLEQ_INIT(&s->active_rules); 537571cd43eSPaolo Bonzini injected = true; 538571cd43eSPaolo Bonzini } 539571cd43eSPaolo Bonzini QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 5408b9b0cc2SKevin Wolf break; 5418b9b0cc2SKevin Wolf 5428b9b0cc2SKevin Wolf case ACTION_SET_STATE: 5438f96b5beSPaolo Bonzini s->new_state = rule->options.set_state.new_state; 5448b9b0cc2SKevin Wolf break; 5453c90c65dSKevin Wolf 5463c90c65dSKevin Wolf case ACTION_SUSPEND: 5473c90c65dSKevin Wolf suspend_request(bs, rule); 5483c90c65dSKevin Wolf break; 5498b9b0cc2SKevin Wolf } 550571cd43eSPaolo Bonzini return injected; 5518b9b0cc2SKevin Wolf } 5528b9b0cc2SKevin Wolf 5538b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) 5548b9b0cc2SKevin Wolf { 5558b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5563c90c65dSKevin Wolf struct BlkdebugRule *rule, *next; 557571cd43eSPaolo Bonzini bool injected; 5588b9b0cc2SKevin Wolf 55995ee3914SBlue Swirl assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); 5608b9b0cc2SKevin Wolf 561571cd43eSPaolo Bonzini injected = false; 5628f96b5beSPaolo Bonzini s->new_state = s->state; 5633c90c65dSKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 5648f96b5beSPaolo Bonzini injected = process_rule(bs, rule, injected); 5658b9b0cc2SKevin Wolf } 5668f96b5beSPaolo Bonzini s->state = s->new_state; 5678b9b0cc2SKevin Wolf } 5688b9b0cc2SKevin Wolf 5693c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 5703c90c65dSKevin Wolf const char *tag) 5713c90c65dSKevin Wolf { 5723c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5733c90c65dSKevin Wolf struct BlkdebugRule *rule; 5743c90c65dSKevin Wolf BlkDebugEvent blkdebug_event; 5753c90c65dSKevin Wolf 5763c90c65dSKevin Wolf if (get_event_by_name(event, &blkdebug_event) < 0) { 5773c90c65dSKevin Wolf return -ENOENT; 5783c90c65dSKevin Wolf } 5793c90c65dSKevin Wolf 5803c90c65dSKevin Wolf 5813c90c65dSKevin Wolf rule = g_malloc(sizeof(*rule)); 5823c90c65dSKevin Wolf *rule = (struct BlkdebugRule) { 5833c90c65dSKevin Wolf .event = blkdebug_event, 5843c90c65dSKevin Wolf .action = ACTION_SUSPEND, 5853c90c65dSKevin Wolf .state = 0, 5863c90c65dSKevin Wolf .options.suspend.tag = g_strdup(tag), 5873c90c65dSKevin Wolf }; 5883c90c65dSKevin Wolf 5893c90c65dSKevin Wolf QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 5903c90c65dSKevin Wolf 5913c90c65dSKevin Wolf return 0; 5923c90c65dSKevin Wolf } 5933c90c65dSKevin Wolf 5943c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 5953c90c65dSKevin Wolf { 5963c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5973c90c65dSKevin Wolf BlkdebugSuspendedReq *r; 5983c90c65dSKevin Wolf 5993c90c65dSKevin Wolf QLIST_FOREACH(r, &s->suspended_reqs, next) { 6003c90c65dSKevin Wolf if (!strcmp(r->tag, tag)) { 6013c90c65dSKevin Wolf qemu_coroutine_enter(r->co, NULL); 6023c90c65dSKevin Wolf return 0; 6033c90c65dSKevin Wolf } 6043c90c65dSKevin Wolf } 6053c90c65dSKevin Wolf return -ENOENT; 6063c90c65dSKevin Wolf } 6073c90c65dSKevin Wolf 6083c90c65dSKevin Wolf 6093c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 6103c90c65dSKevin Wolf { 6113c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 6123c90c65dSKevin Wolf BlkdebugSuspendedReq *r; 6133c90c65dSKevin Wolf 6143c90c65dSKevin Wolf QLIST_FOREACH(r, &s->suspended_reqs, next) { 6153c90c65dSKevin Wolf if (!strcmp(r->tag, tag)) { 6163c90c65dSKevin Wolf return true; 6173c90c65dSKevin Wolf } 6183c90c65dSKevin Wolf } 6193c90c65dSKevin Wolf return false; 6203c90c65dSKevin Wolf } 6213c90c65dSKevin Wolf 622e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs) 623e1302255SPaolo Bonzini { 624e1302255SPaolo Bonzini return bdrv_getlength(bs->file); 625e1302255SPaolo Bonzini } 626e1302255SPaolo Bonzini 6276a143727SKevin Wolf static BlockDriver bdrv_blkdebug = { 6286a143727SKevin Wolf .format_name = "blkdebug", 6296a143727SKevin Wolf .protocol_name = "blkdebug", 6306a143727SKevin Wolf .instance_size = sizeof(BDRVBlkdebugState), 6316a143727SKevin Wolf 632f4681212SKevin Wolf .bdrv_parse_filename = blkdebug_parse_filename, 63366f82ceeSKevin Wolf .bdrv_file_open = blkdebug_open, 6346a143727SKevin Wolf .bdrv_close = blkdebug_close, 635e1302255SPaolo Bonzini .bdrv_getlength = blkdebug_getlength, 6366a143727SKevin Wolf 6376a143727SKevin Wolf .bdrv_aio_readv = blkdebug_aio_readv, 6386a143727SKevin Wolf .bdrv_aio_writev = blkdebug_aio_writev, 6398b9b0cc2SKevin Wolf 6408b9b0cc2SKevin Wolf .bdrv_debug_event = blkdebug_debug_event, 6413c90c65dSKevin Wolf .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 6423c90c65dSKevin Wolf .bdrv_debug_resume = blkdebug_debug_resume, 6433c90c65dSKevin Wolf .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 6446a143727SKevin Wolf }; 6456a143727SKevin Wolf 6466a143727SKevin Wolf static void bdrv_blkdebug_init(void) 6476a143727SKevin Wolf { 6486a143727SKevin Wolf bdrv_register(&bdrv_blkdebug); 6496a143727SKevin Wolf } 6506a143727SKevin Wolf 6516a143727SKevin Wolf block_init(bdrv_blkdebug_init); 652