16a143727SKevin Wolf /* 26a143727SKevin Wolf * Block protocol for I/O error injection 36a143727SKevin Wolf * 463188c24SEric Blake * Copyright (C) 2016-2017 Red Hat, Inc. 56a143727SKevin Wolf * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com> 66a143727SKevin Wolf * 76a143727SKevin Wolf * Permission is hereby granted, free of charge, to any person obtaining a copy 86a143727SKevin Wolf * of this software and associated documentation files (the "Software"), to deal 96a143727SKevin Wolf * in the Software without restriction, including without limitation the rights 106a143727SKevin Wolf * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 116a143727SKevin Wolf * copies of the Software, and to permit persons to whom the Software is 126a143727SKevin Wolf * furnished to do so, subject to the following conditions: 136a143727SKevin Wolf * 146a143727SKevin Wolf * The above copyright notice and this permission notice shall be included in 156a143727SKevin Wolf * all copies or substantial portions of the Software. 166a143727SKevin Wolf * 176a143727SKevin Wolf * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 186a143727SKevin Wolf * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 196a143727SKevin Wolf * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 206a143727SKevin Wolf * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 216a143727SKevin Wolf * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 226a143727SKevin Wolf * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 236a143727SKevin Wolf * THE SOFTWARE. 246a143727SKevin Wolf */ 256a143727SKevin Wolf 2680c71a24SPeter Maydell #include "qemu/osdep.h" 27da34e65cSMarkus Armbruster #include "qapi/error.h" 28f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 291de7afc9SPaolo Bonzini #include "qemu/config-file.h" 30737e150eSPaolo Bonzini #include "block/block_int.h" 311de7afc9SPaolo Bonzini #include "qemu/module.h" 322c31b04cSMax Reitz #include "qapi/qmp/qbool.h" 332c31b04cSMax Reitz #include "qapi/qmp/qdict.h" 342c31b04cSMax Reitz #include "qapi/qmp/qstring.h" 3520873526SMichael S. Tsirkin #include "sysemu/qtest.h" 366a143727SKevin Wolf 376a143727SKevin Wolf typedef struct BDRVBlkdebugState { 38571cd43eSPaolo Bonzini int state; 398f96b5beSPaolo Bonzini int new_state; 403dc834f8SEric Blake uint64_t align; 41430b26a8SEric Blake uint64_t max_transfer; 42430b26a8SEric Blake uint64_t opt_write_zero; 43430b26a8SEric Blake uint64_t max_write_zero; 44430b26a8SEric Blake uint64_t opt_discard; 45430b26a8SEric Blake uint64_t max_discard; 463c90c65dSKevin Wolf 47036990d7SMax Reitz /* For blkdebug_refresh_filename() */ 48036990d7SMax Reitz char *config_file; 49036990d7SMax Reitz 507fb1cf16SEric Blake QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX]; 51571cd43eSPaolo Bonzini QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 523c90c65dSKevin Wolf QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 536a143727SKevin Wolf } BDRVBlkdebugState; 546a143727SKevin Wolf 55b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB { 567c84b1b8SMarkus Armbruster BlockAIOCB common; 57b9f66d96SKevin Wolf int ret; 58b9f66d96SKevin Wolf } BlkdebugAIOCB; 59b9f66d96SKevin Wolf 603c90c65dSKevin Wolf typedef struct BlkdebugSuspendedReq { 613c90c65dSKevin Wolf Coroutine *co; 623c90c65dSKevin Wolf char *tag; 633c90c65dSKevin Wolf QLIST_ENTRY(BlkdebugSuspendedReq) next; 643c90c65dSKevin Wolf } BlkdebugSuspendedReq; 653c90c65dSKevin Wolf 668b9b0cc2SKevin Wolf enum { 678b9b0cc2SKevin Wolf ACTION_INJECT_ERROR, 688b9b0cc2SKevin Wolf ACTION_SET_STATE, 693c90c65dSKevin Wolf ACTION_SUSPEND, 708b9b0cc2SKevin Wolf }; 718b9b0cc2SKevin Wolf 728b9b0cc2SKevin Wolf typedef struct BlkdebugRule { 73a31939e6SEric Blake BlkdebugEvent event; 748b9b0cc2SKevin Wolf int action; 758b9b0cc2SKevin Wolf int state; 768b9b0cc2SKevin Wolf union { 778b9b0cc2SKevin Wolf struct { 788b9b0cc2SKevin Wolf int error; 798b9b0cc2SKevin Wolf int immediately; 808b9b0cc2SKevin Wolf int once; 817c3a9985SKevin Wolf int64_t offset; 828b9b0cc2SKevin Wolf } inject; 838b9b0cc2SKevin Wolf struct { 848b9b0cc2SKevin Wolf int new_state; 858b9b0cc2SKevin Wolf } set_state; 863c90c65dSKevin Wolf struct { 873c90c65dSKevin Wolf char *tag; 883c90c65dSKevin Wolf } suspend; 898b9b0cc2SKevin Wolf } options; 908b9b0cc2SKevin Wolf QLIST_ENTRY(BlkdebugRule) next; 91571cd43eSPaolo Bonzini QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 928b9b0cc2SKevin Wolf } BlkdebugRule; 938b9b0cc2SKevin Wolf 948b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = { 958b9b0cc2SKevin Wolf .name = "inject-error", 968b9b0cc2SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 978b9b0cc2SKevin Wolf .desc = { 988b9b0cc2SKevin Wolf { 998b9b0cc2SKevin Wolf .name = "event", 1008b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 1018b9b0cc2SKevin Wolf }, 1028b9b0cc2SKevin Wolf { 1038b9b0cc2SKevin Wolf .name = "state", 1048b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1058b9b0cc2SKevin Wolf }, 1068b9b0cc2SKevin Wolf { 1078b9b0cc2SKevin Wolf .name = "errno", 1088b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1098b9b0cc2SKevin Wolf }, 1108b9b0cc2SKevin Wolf { 111e4780db4SPaolo Bonzini .name = "sector", 112e4780db4SPaolo Bonzini .type = QEMU_OPT_NUMBER, 113e4780db4SPaolo Bonzini }, 114e4780db4SPaolo Bonzini { 1158b9b0cc2SKevin Wolf .name = "once", 1168b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 1178b9b0cc2SKevin Wolf }, 1188b9b0cc2SKevin Wolf { 1198b9b0cc2SKevin Wolf .name = "immediately", 1208b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 1218b9b0cc2SKevin Wolf }, 1228b9b0cc2SKevin Wolf { /* end of list */ } 1238b9b0cc2SKevin Wolf }, 1248b9b0cc2SKevin Wolf }; 1258b9b0cc2SKevin Wolf 1268b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = { 1278b9b0cc2SKevin Wolf .name = "set-state", 128327cdad4SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 1298b9b0cc2SKevin Wolf .desc = { 1308b9b0cc2SKevin Wolf { 1318b9b0cc2SKevin Wolf .name = "event", 1328b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 1338b9b0cc2SKevin Wolf }, 1348b9b0cc2SKevin Wolf { 1358b9b0cc2SKevin Wolf .name = "state", 1368b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1378b9b0cc2SKevin Wolf }, 1388b9b0cc2SKevin Wolf { 1398b9b0cc2SKevin Wolf .name = "new_state", 1408b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1418b9b0cc2SKevin Wolf }, 1428b9b0cc2SKevin Wolf { /* end of list */ } 1438b9b0cc2SKevin Wolf }, 1448b9b0cc2SKevin Wolf }; 1458b9b0cc2SKevin Wolf 1468b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = { 1478b9b0cc2SKevin Wolf &inject_error_opts, 1488b9b0cc2SKevin Wolf &set_state_opts, 1498b9b0cc2SKevin Wolf NULL 1508b9b0cc2SKevin Wolf }; 1518b9b0cc2SKevin Wolf 152a31939e6SEric Blake static int get_event_by_name(const char *name, BlkdebugEvent *event) 1538b9b0cc2SKevin Wolf { 1548b9b0cc2SKevin Wolf int i; 1558b9b0cc2SKevin Wolf 1567fb1cf16SEric Blake for (i = 0; i < BLKDBG__MAX; i++) { 157a31939e6SEric Blake if (!strcmp(BlkdebugEvent_lookup[i], name)) { 1588b9b0cc2SKevin Wolf *event = i; 1598b9b0cc2SKevin Wolf return 0; 1608b9b0cc2SKevin Wolf } 1618b9b0cc2SKevin Wolf } 1628b9b0cc2SKevin Wolf 1638b9b0cc2SKevin Wolf return -1; 1648b9b0cc2SKevin Wolf } 1658b9b0cc2SKevin Wolf 1668b9b0cc2SKevin Wolf struct add_rule_data { 1678b9b0cc2SKevin Wolf BDRVBlkdebugState *s; 1688b9b0cc2SKevin Wolf int action; 1698b9b0cc2SKevin Wolf }; 1708b9b0cc2SKevin Wolf 17128d0de7aSMarkus Armbruster static int add_rule(void *opaque, QemuOpts *opts, Error **errp) 1728b9b0cc2SKevin Wolf { 1738b9b0cc2SKevin Wolf struct add_rule_data *d = opaque; 1748b9b0cc2SKevin Wolf BDRVBlkdebugState *s = d->s; 1758b9b0cc2SKevin Wolf const char* event_name; 176a31939e6SEric Blake BlkdebugEvent event; 1778b9b0cc2SKevin Wolf struct BlkdebugRule *rule; 1787c3a9985SKevin Wolf int64_t sector; 1798b9b0cc2SKevin Wolf 1808b9b0cc2SKevin Wolf /* Find the right event for the rule */ 1818b9b0cc2SKevin Wolf event_name = qemu_opt_get(opts, "event"); 182d4362d64SStefan Hajnoczi if (!event_name) { 1838809cfc3SMarkus Armbruster error_setg(errp, "Missing event name for rule"); 184d4362d64SStefan Hajnoczi return -1; 185d4362d64SStefan Hajnoczi } else if (get_event_by_name(event_name, &event) < 0) { 1868809cfc3SMarkus Armbruster error_setg(errp, "Invalid event name \"%s\"", event_name); 1878b9b0cc2SKevin Wolf return -1; 1888b9b0cc2SKevin Wolf } 1898b9b0cc2SKevin Wolf 1908b9b0cc2SKevin Wolf /* Set attributes common for all actions */ 1917267c094SAnthony Liguori rule = g_malloc0(sizeof(*rule)); 1928b9b0cc2SKevin Wolf *rule = (struct BlkdebugRule) { 1938b9b0cc2SKevin Wolf .event = event, 1948b9b0cc2SKevin Wolf .action = d->action, 1958b9b0cc2SKevin Wolf .state = qemu_opt_get_number(opts, "state", 0), 1968b9b0cc2SKevin Wolf }; 1978b9b0cc2SKevin Wolf 1988b9b0cc2SKevin Wolf /* Parse action-specific options */ 1998b9b0cc2SKevin Wolf switch (d->action) { 2008b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 2018b9b0cc2SKevin Wolf rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 2028b9b0cc2SKevin Wolf rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 2038b9b0cc2SKevin Wolf rule->options.inject.immediately = 2048b9b0cc2SKevin Wolf qemu_opt_get_bool(opts, "immediately", 0); 2057c3a9985SKevin Wolf sector = qemu_opt_get_number(opts, "sector", -1); 2067c3a9985SKevin Wolf rule->options.inject.offset = 2077c3a9985SKevin Wolf sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; 2088b9b0cc2SKevin Wolf break; 2098b9b0cc2SKevin Wolf 2108b9b0cc2SKevin Wolf case ACTION_SET_STATE: 2118b9b0cc2SKevin Wolf rule->options.set_state.new_state = 2128b9b0cc2SKevin Wolf qemu_opt_get_number(opts, "new_state", 0); 2138b9b0cc2SKevin Wolf break; 2143c90c65dSKevin Wolf 2153c90c65dSKevin Wolf case ACTION_SUSPEND: 2163c90c65dSKevin Wolf rule->options.suspend.tag = 2173c90c65dSKevin Wolf g_strdup(qemu_opt_get(opts, "tag")); 2183c90c65dSKevin Wolf break; 2198b9b0cc2SKevin Wolf }; 2208b9b0cc2SKevin Wolf 2218b9b0cc2SKevin Wolf /* Add the rule */ 2228b9b0cc2SKevin Wolf QLIST_INSERT_HEAD(&s->rules[event], rule, next); 2238b9b0cc2SKevin Wolf 2248b9b0cc2SKevin Wolf return 0; 2258b9b0cc2SKevin Wolf } 2268b9b0cc2SKevin Wolf 2279e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule) 2289e35542bSKevin Wolf { 2299e35542bSKevin Wolf switch (rule->action) { 2309e35542bSKevin Wolf case ACTION_INJECT_ERROR: 2319e35542bSKevin Wolf case ACTION_SET_STATE: 2329e35542bSKevin Wolf break; 2333c90c65dSKevin Wolf case ACTION_SUSPEND: 2343c90c65dSKevin Wolf g_free(rule->options.suspend.tag); 2353c90c65dSKevin Wolf break; 2369e35542bSKevin Wolf } 2379e35542bSKevin Wolf 2389e35542bSKevin Wolf QLIST_REMOVE(rule, next); 2399e35542bSKevin Wolf g_free(rule); 2409e35542bSKevin Wolf } 2419e35542bSKevin Wolf 24289f2b21eSMax Reitz static int read_config(BDRVBlkdebugState *s, const char *filename, 24389f2b21eSMax Reitz QDict *options, Error **errp) 2448b9b0cc2SKevin Wolf { 24585a040e5SMax Reitz FILE *f = NULL; 2468b9b0cc2SKevin Wolf int ret; 2478b9b0cc2SKevin Wolf struct add_rule_data d; 24889f2b21eSMax Reitz Error *local_err = NULL; 2498b9b0cc2SKevin Wolf 25085a040e5SMax Reitz if (filename) { 2518b9b0cc2SKevin Wolf f = fopen(filename, "r"); 2528b9b0cc2SKevin Wolf if (f == NULL) { 253466b49f2SMax Reitz error_setg_errno(errp, errno, "Could not read blkdebug config file"); 2548b9b0cc2SKevin Wolf return -errno; 2558b9b0cc2SKevin Wolf } 2568b9b0cc2SKevin Wolf 2578b9b0cc2SKevin Wolf ret = qemu_config_parse(f, config_groups, filename); 2588b9b0cc2SKevin Wolf if (ret < 0) { 259466b49f2SMax Reitz error_setg(errp, "Could not parse blkdebug config file"); 260466b49f2SMax Reitz ret = -EINVAL; 2618b9b0cc2SKevin Wolf goto fail; 2628b9b0cc2SKevin Wolf } 26385a040e5SMax Reitz } 2648b9b0cc2SKevin Wolf 26589f2b21eSMax Reitz qemu_config_parse_qdict(options, config_groups, &local_err); 26684d18f06SMarkus Armbruster if (local_err) { 26789f2b21eSMax Reitz error_propagate(errp, local_err); 26889f2b21eSMax Reitz ret = -EINVAL; 26989f2b21eSMax Reitz goto fail; 27089f2b21eSMax Reitz } 27189f2b21eSMax Reitz 2728b9b0cc2SKevin Wolf d.s = s; 2738b9b0cc2SKevin Wolf d.action = ACTION_INJECT_ERROR; 2748809cfc3SMarkus Armbruster qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err); 275d4362d64SStefan Hajnoczi if (local_err) { 276d4362d64SStefan Hajnoczi error_propagate(errp, local_err); 277d4362d64SStefan Hajnoczi ret = -EINVAL; 278d4362d64SStefan Hajnoczi goto fail; 279d4362d64SStefan Hajnoczi } 2808b9b0cc2SKevin Wolf 2818b9b0cc2SKevin Wolf d.action = ACTION_SET_STATE; 2828809cfc3SMarkus Armbruster qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err); 283d4362d64SStefan Hajnoczi if (local_err) { 284d4362d64SStefan Hajnoczi error_propagate(errp, local_err); 285d4362d64SStefan Hajnoczi ret = -EINVAL; 286d4362d64SStefan Hajnoczi goto fail; 287d4362d64SStefan Hajnoczi } 2888b9b0cc2SKevin Wolf 2898b9b0cc2SKevin Wolf ret = 0; 2908b9b0cc2SKevin Wolf fail: 291698f0d52SKevin Wolf qemu_opts_reset(&inject_error_opts); 292698f0d52SKevin Wolf qemu_opts_reset(&set_state_opts); 29385a040e5SMax Reitz if (f) { 2948b9b0cc2SKevin Wolf fclose(f); 29585a040e5SMax Reitz } 2968b9b0cc2SKevin Wolf return ret; 2978b9b0cc2SKevin Wolf } 2988b9b0cc2SKevin Wolf 2998b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 300f4681212SKevin Wolf static void blkdebug_parse_filename(const char *filename, QDict *options, 301f4681212SKevin Wolf Error **errp) 302f4681212SKevin Wolf { 303f4681212SKevin Wolf const char *c; 304f4681212SKevin Wolf 305f4681212SKevin Wolf /* Parse the blkdebug: prefix */ 306f4681212SKevin Wolf if (!strstart(filename, "blkdebug:", &filename)) { 307d4881b9bSMax Reitz /* There was no prefix; therefore, all options have to be already 308d4881b9bSMax Reitz present in the QDict (except for the filename) */ 30946f5ac20SEric Blake qdict_put_str(options, "x-image", filename); 310f4681212SKevin Wolf return; 311f4681212SKevin Wolf } 312f4681212SKevin Wolf 313f4681212SKevin Wolf /* Parse config file path */ 314f4681212SKevin Wolf c = strchr(filename, ':'); 315f4681212SKevin Wolf if (c == NULL) { 316f4681212SKevin Wolf error_setg(errp, "blkdebug requires both config file and image path"); 317f4681212SKevin Wolf return; 318f4681212SKevin Wolf } 319f4681212SKevin Wolf 320f4681212SKevin Wolf if (c != filename) { 321f4681212SKevin Wolf QString *config_path; 322f4681212SKevin Wolf config_path = qstring_from_substr(filename, 0, c - filename - 1); 323f4681212SKevin Wolf qdict_put(options, "config", config_path); 324f4681212SKevin Wolf } 325f4681212SKevin Wolf 326f4681212SKevin Wolf /* TODO Allow multi-level nesting and set file.filename here */ 327f4681212SKevin Wolf filename = c + 1; 32846f5ac20SEric Blake qdict_put_str(options, "x-image", filename); 329f4681212SKevin Wolf } 330f4681212SKevin Wolf 331f4681212SKevin Wolf static QemuOptsList runtime_opts = { 332f4681212SKevin Wolf .name = "blkdebug", 333f4681212SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 334f4681212SKevin Wolf .desc = { 335f4681212SKevin Wolf { 336f4681212SKevin Wolf .name = "config", 337f4681212SKevin Wolf .type = QEMU_OPT_STRING, 338f4681212SKevin Wolf .help = "Path to the configuration file", 339f4681212SKevin Wolf }, 340f4681212SKevin Wolf { 341f4681212SKevin Wolf .name = "x-image", 342f4681212SKevin Wolf .type = QEMU_OPT_STRING, 343f4681212SKevin Wolf .help = "[internal use only, will be removed]", 344f4681212SKevin Wolf }, 345b35ee7fbSKevin Wolf { 346b35ee7fbSKevin Wolf .name = "align", 347b35ee7fbSKevin Wolf .type = QEMU_OPT_SIZE, 348b35ee7fbSKevin Wolf .help = "Required alignment in bytes", 349b35ee7fbSKevin Wolf }, 350430b26a8SEric Blake { 351430b26a8SEric Blake .name = "max-transfer", 352430b26a8SEric Blake .type = QEMU_OPT_SIZE, 353430b26a8SEric Blake .help = "Maximum transfer size in bytes", 354430b26a8SEric Blake }, 355430b26a8SEric Blake { 356430b26a8SEric Blake .name = "opt-write-zero", 357430b26a8SEric Blake .type = QEMU_OPT_SIZE, 358430b26a8SEric Blake .help = "Optimum write zero alignment in bytes", 359430b26a8SEric Blake }, 360430b26a8SEric Blake { 361430b26a8SEric Blake .name = "max-write-zero", 362430b26a8SEric Blake .type = QEMU_OPT_SIZE, 363430b26a8SEric Blake .help = "Maximum write zero size in bytes", 364430b26a8SEric Blake }, 365430b26a8SEric Blake { 366430b26a8SEric Blake .name = "opt-discard", 367430b26a8SEric Blake .type = QEMU_OPT_SIZE, 368430b26a8SEric Blake .help = "Optimum discard alignment in bytes", 369430b26a8SEric Blake }, 370430b26a8SEric Blake { 371430b26a8SEric Blake .name = "max-discard", 372430b26a8SEric Blake .type = QEMU_OPT_SIZE, 373430b26a8SEric Blake .help = "Maximum discard size in bytes", 374430b26a8SEric Blake }, 375f4681212SKevin Wolf { /* end of list */ } 376f4681212SKevin Wolf }, 377f4681212SKevin Wolf }; 378f4681212SKevin Wolf 379015a1036SMax Reitz static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, 380015a1036SMax Reitz Error **errp) 3816a143727SKevin Wolf { 3826a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 383f4681212SKevin Wolf QemuOpts *opts; 384f4681212SKevin Wolf Error *local_err = NULL; 3858b9b0cc2SKevin Wolf int ret; 386430b26a8SEric Blake uint64_t align; 3876a143727SKevin Wolf 38887ea75d5SPeter Crosthwaite opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 389f4681212SKevin Wolf qemu_opts_absorb_qdict(opts, options, &local_err); 39084d18f06SMarkus Armbruster if (local_err) { 39110ffa72fSMax Reitz error_propagate(errp, local_err); 392f4681212SKevin Wolf ret = -EINVAL; 393eaf944a4SKevin Wolf goto out; 3946a143727SKevin Wolf } 3956a143727SKevin Wolf 39689f2b21eSMax Reitz /* Read rules from config file or command line options */ 397036990d7SMax Reitz s->config_file = g_strdup(qemu_opt_get(opts, "config")); 398036990d7SMax Reitz ret = read_config(s, s->config_file, options, errp); 399466b49f2SMax Reitz if (ret) { 400eaf944a4SKevin Wolf goto out; 4018b9b0cc2SKevin Wolf } 4028b9b0cc2SKevin Wolf 4038db520ceSKevin Wolf /* Set initial state */ 404571cd43eSPaolo Bonzini s->state = 1; 4058db520ceSKevin Wolf 4066b826af7SFam Zheng /* Open the image file */ 4079a4f4c31SKevin Wolf bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", 408f3930ed0SKevin Wolf bs, &child_file, false, &local_err); 4099a4f4c31SKevin Wolf if (local_err) { 4109a4f4c31SKevin Wolf ret = -EINVAL; 41110ffa72fSMax Reitz error_propagate(errp, local_err); 412eaf944a4SKevin Wolf goto out; 413f4681212SKevin Wolf } 414f4681212SKevin Wolf 41563188c24SEric Blake bs->supported_write_flags = BDRV_REQ_FUA & 41663188c24SEric Blake bs->file->bs->supported_write_flags; 41763188c24SEric Blake bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & 41863188c24SEric Blake bs->file->bs->supported_zero_flags; 4193dc834f8SEric Blake ret = -EINVAL; 42063188c24SEric Blake 421430b26a8SEric Blake /* Set alignment overrides */ 4223dc834f8SEric Blake s->align = qemu_opt_get_size(opts, "align", 0); 4233dc834f8SEric Blake if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) { 4243dc834f8SEric Blake error_setg(errp, "Cannot meet constraints with align %" PRIu64, 4253dc834f8SEric Blake s->align); 426de234897SMax Reitz goto out; 427b35ee7fbSKevin Wolf } 428430b26a8SEric Blake align = MAX(s->align, bs->file->bs->bl.request_alignment); 429430b26a8SEric Blake 430430b26a8SEric Blake s->max_transfer = qemu_opt_get_size(opts, "max-transfer", 0); 431430b26a8SEric Blake if (s->max_transfer && 432430b26a8SEric Blake (s->max_transfer >= INT_MAX || 433430b26a8SEric Blake !QEMU_IS_ALIGNED(s->max_transfer, align))) { 434430b26a8SEric Blake error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64, 435430b26a8SEric Blake s->max_transfer); 436430b26a8SEric Blake goto out; 437430b26a8SEric Blake } 438430b26a8SEric Blake 439430b26a8SEric Blake s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0); 440430b26a8SEric Blake if (s->opt_write_zero && 441430b26a8SEric Blake (s->opt_write_zero >= INT_MAX || 442430b26a8SEric Blake !QEMU_IS_ALIGNED(s->opt_write_zero, align))) { 443430b26a8SEric Blake error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64, 444430b26a8SEric Blake s->opt_write_zero); 445430b26a8SEric Blake goto out; 446430b26a8SEric Blake } 447430b26a8SEric Blake 448430b26a8SEric Blake s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0); 449430b26a8SEric Blake if (s->max_write_zero && 450430b26a8SEric Blake (s->max_write_zero >= INT_MAX || 451430b26a8SEric Blake !QEMU_IS_ALIGNED(s->max_write_zero, 452430b26a8SEric Blake MAX(s->opt_write_zero, align)))) { 453430b26a8SEric Blake error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64, 454430b26a8SEric Blake s->max_write_zero); 455430b26a8SEric Blake goto out; 456430b26a8SEric Blake } 457430b26a8SEric Blake 458430b26a8SEric Blake s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0); 459430b26a8SEric Blake if (s->opt_discard && 460430b26a8SEric Blake (s->opt_discard >= INT_MAX || 461430b26a8SEric Blake !QEMU_IS_ALIGNED(s->opt_discard, align))) { 462430b26a8SEric Blake error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64, 463430b26a8SEric Blake s->opt_discard); 464430b26a8SEric Blake goto out; 465430b26a8SEric Blake } 466430b26a8SEric Blake 467430b26a8SEric Blake s->max_discard = qemu_opt_get_size(opts, "max-discard", 0); 468430b26a8SEric Blake if (s->max_discard && 469430b26a8SEric Blake (s->max_discard >= INT_MAX || 470430b26a8SEric Blake !QEMU_IS_ALIGNED(s->max_discard, 471430b26a8SEric Blake MAX(s->opt_discard, align)))) { 472430b26a8SEric Blake error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64, 473430b26a8SEric Blake s->max_discard); 474430b26a8SEric Blake goto out; 475430b26a8SEric Blake } 476b35ee7fbSKevin Wolf 477f4681212SKevin Wolf ret = 0; 478eaf944a4SKevin Wolf out: 479036990d7SMax Reitz if (ret < 0) { 480036990d7SMax Reitz g_free(s->config_file); 481036990d7SMax Reitz } 482f4681212SKevin Wolf qemu_opts_del(opts); 483f4681212SKevin Wolf return ret; 4846a143727SKevin Wolf } 4856a143727SKevin Wolf 486d157ed5fSEric Blake static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes) 487b9f66d96SKevin Wolf { 488b9f66d96SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 489d157ed5fSEric Blake BlkdebugRule *rule = NULL; 490d157ed5fSEric Blake int error; 491d157ed5fSEric Blake bool immediately; 492d157ed5fSEric Blake 493d157ed5fSEric Blake QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 494d157ed5fSEric Blake uint64_t inject_offset = rule->options.inject.offset; 495d157ed5fSEric Blake 496d157ed5fSEric Blake if (inject_offset == -1 || 497d157ed5fSEric Blake (bytes && inject_offset >= offset && 498d157ed5fSEric Blake inject_offset < offset + bytes)) 499d157ed5fSEric Blake { 500d157ed5fSEric Blake break; 501d157ed5fSEric Blake } 502d157ed5fSEric Blake } 503d157ed5fSEric Blake 504d157ed5fSEric Blake if (!rule || !rule->options.inject.error) { 505d157ed5fSEric Blake return 0; 506d157ed5fSEric Blake } 507d157ed5fSEric Blake 508d157ed5fSEric Blake immediately = rule->options.inject.immediately; 509d157ed5fSEric Blake error = rule->options.inject.error; 510b9f66d96SKevin Wolf 511571cd43eSPaolo Bonzini if (rule->options.inject.once) { 512a069e2f1SJohn Snow QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next); 513a069e2f1SJohn Snow remove_rule(rule); 514b9f66d96SKevin Wolf } 515b9f66d96SKevin Wolf 5167c3a9985SKevin Wolf if (!immediately) { 517e5c67ab5SPaolo Bonzini aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); 5187c3a9985SKevin Wolf qemu_coroutine_yield(); 519b9f66d96SKevin Wolf } 520b9f66d96SKevin Wolf 5217c3a9985SKevin Wolf return -error; 522b9f66d96SKevin Wolf } 523b9f66d96SKevin Wolf 5247c3a9985SKevin Wolf static int coroutine_fn 5257c3a9985SKevin Wolf blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 5267c3a9985SKevin Wolf QEMUIOVector *qiov, int flags) 5276a143727SKevin Wolf { 528d157ed5fSEric Blake int err; 529e4780db4SPaolo Bonzini 530e0ef4395SEric Blake /* Sanity check block layer guarantees */ 531e0ef4395SEric Blake assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); 532e0ef4395SEric Blake assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); 533e0ef4395SEric Blake if (bs->bl.max_transfer) { 534e0ef4395SEric Blake assert(bytes <= bs->bl.max_transfer); 535e0ef4395SEric Blake } 536e0ef4395SEric Blake 537d157ed5fSEric Blake err = rule_check(bs, offset, bytes); 538d157ed5fSEric Blake if (err) { 539d157ed5fSEric Blake return err; 540b9f66d96SKevin Wolf } 541b9f66d96SKevin Wolf 5427c3a9985SKevin Wolf return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 5436a143727SKevin Wolf } 5446a143727SKevin Wolf 5457c3a9985SKevin Wolf static int coroutine_fn 5467c3a9985SKevin Wolf blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 5477c3a9985SKevin Wolf QEMUIOVector *qiov, int flags) 5486a143727SKevin Wolf { 549d157ed5fSEric Blake int err; 550e4780db4SPaolo Bonzini 551e0ef4395SEric Blake /* Sanity check block layer guarantees */ 552e0ef4395SEric Blake assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); 553e0ef4395SEric Blake assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); 554e0ef4395SEric Blake if (bs->bl.max_transfer) { 555e0ef4395SEric Blake assert(bytes <= bs->bl.max_transfer); 556e0ef4395SEric Blake } 557e0ef4395SEric Blake 558d157ed5fSEric Blake err = rule_check(bs, offset, bytes); 559d157ed5fSEric Blake if (err) { 560d157ed5fSEric Blake return err; 561b9f66d96SKevin Wolf } 562b9f66d96SKevin Wolf 5637c3a9985SKevin Wolf return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 5646a143727SKevin Wolf } 5656a143727SKevin Wolf 5667c3a9985SKevin Wolf static int blkdebug_co_flush(BlockDriverState *bs) 5679e52c53bSPaolo Bonzini { 568d157ed5fSEric Blake int err = rule_check(bs, 0, 0); 5699e52c53bSPaolo Bonzini 570d157ed5fSEric Blake if (err) { 571d157ed5fSEric Blake return err; 5729e52c53bSPaolo Bonzini } 5739e52c53bSPaolo Bonzini 5747c3a9985SKevin Wolf return bdrv_co_flush(bs->file->bs); 5759e52c53bSPaolo Bonzini } 5769e52c53bSPaolo Bonzini 57763188c24SEric Blake static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs, 578f5a5ca79SManos Pitsidianakis int64_t offset, int bytes, 57963188c24SEric Blake BdrvRequestFlags flags) 58063188c24SEric Blake { 58163188c24SEric Blake uint32_t align = MAX(bs->bl.request_alignment, 58263188c24SEric Blake bs->bl.pwrite_zeroes_alignment); 58363188c24SEric Blake int err; 58463188c24SEric Blake 58563188c24SEric Blake /* Only pass through requests that are larger than requested 58663188c24SEric Blake * preferred alignment (so that we test the fallback to writes on 58763188c24SEric Blake * unaligned portions), and check that the block layer never hands 58863188c24SEric Blake * us anything unaligned that crosses an alignment boundary. */ 589f5a5ca79SManos Pitsidianakis if (bytes < align) { 59063188c24SEric Blake assert(QEMU_IS_ALIGNED(offset, align) || 591f5a5ca79SManos Pitsidianakis QEMU_IS_ALIGNED(offset + bytes, align) || 59263188c24SEric Blake DIV_ROUND_UP(offset, align) == 593f5a5ca79SManos Pitsidianakis DIV_ROUND_UP(offset + bytes, align)); 59463188c24SEric Blake return -ENOTSUP; 59563188c24SEric Blake } 59663188c24SEric Blake assert(QEMU_IS_ALIGNED(offset, align)); 597f5a5ca79SManos Pitsidianakis assert(QEMU_IS_ALIGNED(bytes, align)); 59863188c24SEric Blake if (bs->bl.max_pwrite_zeroes) { 599f5a5ca79SManos Pitsidianakis assert(bytes <= bs->bl.max_pwrite_zeroes); 60063188c24SEric Blake } 60163188c24SEric Blake 602f5a5ca79SManos Pitsidianakis err = rule_check(bs, offset, bytes); 60363188c24SEric Blake if (err) { 60463188c24SEric Blake return err; 60563188c24SEric Blake } 60663188c24SEric Blake 607f5a5ca79SManos Pitsidianakis return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); 60863188c24SEric Blake } 60963188c24SEric Blake 61063188c24SEric Blake static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, 611f5a5ca79SManos Pitsidianakis int64_t offset, int bytes) 61263188c24SEric Blake { 61363188c24SEric Blake uint32_t align = bs->bl.pdiscard_alignment; 61463188c24SEric Blake int err; 61563188c24SEric Blake 61663188c24SEric Blake /* Only pass through requests that are larger than requested 61763188c24SEric Blake * minimum alignment, and ensure that unaligned requests do not 61863188c24SEric Blake * cross optimum discard boundaries. */ 619f5a5ca79SManos Pitsidianakis if (bytes < bs->bl.request_alignment) { 62063188c24SEric Blake assert(QEMU_IS_ALIGNED(offset, align) || 621f5a5ca79SManos Pitsidianakis QEMU_IS_ALIGNED(offset + bytes, align) || 62263188c24SEric Blake DIV_ROUND_UP(offset, align) == 623f5a5ca79SManos Pitsidianakis DIV_ROUND_UP(offset + bytes, align)); 62463188c24SEric Blake return -ENOTSUP; 62563188c24SEric Blake } 62663188c24SEric Blake assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); 627f5a5ca79SManos Pitsidianakis assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); 628f5a5ca79SManos Pitsidianakis if (align && bytes >= align) { 62963188c24SEric Blake assert(QEMU_IS_ALIGNED(offset, align)); 630f5a5ca79SManos Pitsidianakis assert(QEMU_IS_ALIGNED(bytes, align)); 63163188c24SEric Blake } 63263188c24SEric Blake if (bs->bl.max_pdiscard) { 633f5a5ca79SManos Pitsidianakis assert(bytes <= bs->bl.max_pdiscard); 63463188c24SEric Blake } 63563188c24SEric Blake 636f5a5ca79SManos Pitsidianakis err = rule_check(bs, offset, bytes); 63763188c24SEric Blake if (err) { 63863188c24SEric Blake return err; 63963188c24SEric Blake } 64063188c24SEric Blake 641f5a5ca79SManos Pitsidianakis return bdrv_co_pdiscard(bs->file->bs, offset, bytes); 64263188c24SEric Blake } 6433c90c65dSKevin Wolf 6446a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs) 6456a143727SKevin Wolf { 6466a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 6478b9b0cc2SKevin Wolf BlkdebugRule *rule, *next; 6488b9b0cc2SKevin Wolf int i; 6498b9b0cc2SKevin Wolf 6507fb1cf16SEric Blake for (i = 0; i < BLKDBG__MAX; i++) { 6518b9b0cc2SKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 6529e35542bSKevin Wolf remove_rule(rule); 6538b9b0cc2SKevin Wolf } 6548b9b0cc2SKevin Wolf } 655036990d7SMax Reitz 656036990d7SMax Reitz g_free(s->config_file); 6576a143727SKevin Wolf } 6586a143727SKevin Wolf 6593c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 6603c90c65dSKevin Wolf { 6613c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 6623c90c65dSKevin Wolf BlkdebugSuspendedReq r; 6633c90c65dSKevin Wolf 6643c90c65dSKevin Wolf r = (BlkdebugSuspendedReq) { 6653c90c65dSKevin Wolf .co = qemu_coroutine_self(), 6663c90c65dSKevin Wolf .tag = g_strdup(rule->options.suspend.tag), 6673c90c65dSKevin Wolf }; 6683c90c65dSKevin Wolf 6693c90c65dSKevin Wolf remove_rule(rule); 6703c90c65dSKevin Wolf QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 6713c90c65dSKevin Wolf 67220873526SMichael S. Tsirkin if (!qtest_enabled()) { 6733c90c65dSKevin Wolf printf("blkdebug: Suspended request '%s'\n", r.tag); 67420873526SMichael S. Tsirkin } 6753c90c65dSKevin Wolf qemu_coroutine_yield(); 67620873526SMichael S. Tsirkin if (!qtest_enabled()) { 6773c90c65dSKevin Wolf printf("blkdebug: Resuming request '%s'\n", r.tag); 67820873526SMichael S. Tsirkin } 6793c90c65dSKevin Wolf 6803c90c65dSKevin Wolf QLIST_REMOVE(&r, next); 6813c90c65dSKevin Wolf g_free(r.tag); 6823c90c65dSKevin Wolf } 6833c90c65dSKevin Wolf 684571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 6858f96b5beSPaolo Bonzini bool injected) 6868b9b0cc2SKevin Wolf { 6878b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 6888b9b0cc2SKevin Wolf 6898b9b0cc2SKevin Wolf /* Only process rules for the current state */ 6908f96b5beSPaolo Bonzini if (rule->state && rule->state != s->state) { 691571cd43eSPaolo Bonzini return injected; 6928b9b0cc2SKevin Wolf } 6938b9b0cc2SKevin Wolf 6948b9b0cc2SKevin Wolf /* Take the action */ 6958b9b0cc2SKevin Wolf switch (rule->action) { 6968b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 697571cd43eSPaolo Bonzini if (!injected) { 698571cd43eSPaolo Bonzini QSIMPLEQ_INIT(&s->active_rules); 699571cd43eSPaolo Bonzini injected = true; 700571cd43eSPaolo Bonzini } 701571cd43eSPaolo Bonzini QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 7028b9b0cc2SKevin Wolf break; 7038b9b0cc2SKevin Wolf 7048b9b0cc2SKevin Wolf case ACTION_SET_STATE: 7058f96b5beSPaolo Bonzini s->new_state = rule->options.set_state.new_state; 7068b9b0cc2SKevin Wolf break; 7073c90c65dSKevin Wolf 7083c90c65dSKevin Wolf case ACTION_SUSPEND: 7093c90c65dSKevin Wolf suspend_request(bs, rule); 7103c90c65dSKevin Wolf break; 7118b9b0cc2SKevin Wolf } 712571cd43eSPaolo Bonzini return injected; 7138b9b0cc2SKevin Wolf } 7148b9b0cc2SKevin Wolf 715a31939e6SEric Blake static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) 7168b9b0cc2SKevin Wolf { 7178b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 7183c90c65dSKevin Wolf struct BlkdebugRule *rule, *next; 719571cd43eSPaolo Bonzini bool injected; 7208b9b0cc2SKevin Wolf 7217fb1cf16SEric Blake assert((int)event >= 0 && event < BLKDBG__MAX); 7228b9b0cc2SKevin Wolf 723571cd43eSPaolo Bonzini injected = false; 7248f96b5beSPaolo Bonzini s->new_state = s->state; 7253c90c65dSKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 7268f96b5beSPaolo Bonzini injected = process_rule(bs, rule, injected); 7278b9b0cc2SKevin Wolf } 7288f96b5beSPaolo Bonzini s->state = s->new_state; 7298b9b0cc2SKevin Wolf } 7308b9b0cc2SKevin Wolf 7313c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 7323c90c65dSKevin Wolf const char *tag) 7333c90c65dSKevin Wolf { 7343c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 7353c90c65dSKevin Wolf struct BlkdebugRule *rule; 736a31939e6SEric Blake BlkdebugEvent blkdebug_event; 7373c90c65dSKevin Wolf 7383c90c65dSKevin Wolf if (get_event_by_name(event, &blkdebug_event) < 0) { 7393c90c65dSKevin Wolf return -ENOENT; 7403c90c65dSKevin Wolf } 7413c90c65dSKevin Wolf 7423c90c65dSKevin Wolf 7433c90c65dSKevin Wolf rule = g_malloc(sizeof(*rule)); 7443c90c65dSKevin Wolf *rule = (struct BlkdebugRule) { 7453c90c65dSKevin Wolf .event = blkdebug_event, 7463c90c65dSKevin Wolf .action = ACTION_SUSPEND, 7473c90c65dSKevin Wolf .state = 0, 7483c90c65dSKevin Wolf .options.suspend.tag = g_strdup(tag), 7493c90c65dSKevin Wolf }; 7503c90c65dSKevin Wolf 7513c90c65dSKevin Wolf QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 7523c90c65dSKevin Wolf 7533c90c65dSKevin Wolf return 0; 7543c90c65dSKevin Wolf } 7553c90c65dSKevin Wolf 7563c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 7573c90c65dSKevin Wolf { 7583c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 759c547e564SFam Zheng BlkdebugSuspendedReq *r, *next; 7603c90c65dSKevin Wolf 761c547e564SFam Zheng QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { 7623c90c65dSKevin Wolf if (!strcmp(r->tag, tag)) { 7630b8b8753SPaolo Bonzini qemu_coroutine_enter(r->co); 7643c90c65dSKevin Wolf return 0; 7653c90c65dSKevin Wolf } 7663c90c65dSKevin Wolf } 7673c90c65dSKevin Wolf return -ENOENT; 7683c90c65dSKevin Wolf } 7693c90c65dSKevin Wolf 7704cc70e93SFam Zheng static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, 7714cc70e93SFam Zheng const char *tag) 7724cc70e93SFam Zheng { 7734cc70e93SFam Zheng BDRVBlkdebugState *s = bs->opaque; 774c547e564SFam Zheng BlkdebugSuspendedReq *r, *r_next; 7754cc70e93SFam Zheng BlkdebugRule *rule, *next; 7764cc70e93SFam Zheng int i, ret = -ENOENT; 7774cc70e93SFam Zheng 7787fb1cf16SEric Blake for (i = 0; i < BLKDBG__MAX; i++) { 7794cc70e93SFam Zheng QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 7804cc70e93SFam Zheng if (rule->action == ACTION_SUSPEND && 7814cc70e93SFam Zheng !strcmp(rule->options.suspend.tag, tag)) { 7824cc70e93SFam Zheng remove_rule(rule); 7834cc70e93SFam Zheng ret = 0; 7844cc70e93SFam Zheng } 7854cc70e93SFam Zheng } 7864cc70e93SFam Zheng } 787c547e564SFam Zheng QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { 7884cc70e93SFam Zheng if (!strcmp(r->tag, tag)) { 7890b8b8753SPaolo Bonzini qemu_coroutine_enter(r->co); 7904cc70e93SFam Zheng ret = 0; 7914cc70e93SFam Zheng } 7924cc70e93SFam Zheng } 7934cc70e93SFam Zheng return ret; 7944cc70e93SFam Zheng } 7953c90c65dSKevin Wolf 7963c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 7973c90c65dSKevin Wolf { 7983c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 7993c90c65dSKevin Wolf BlkdebugSuspendedReq *r; 8003c90c65dSKevin Wolf 8013c90c65dSKevin Wolf QLIST_FOREACH(r, &s->suspended_reqs, next) { 8023c90c65dSKevin Wolf if (!strcmp(r->tag, tag)) { 8033c90c65dSKevin Wolf return true; 8043c90c65dSKevin Wolf } 8053c90c65dSKevin Wolf } 8063c90c65dSKevin Wolf return false; 8073c90c65dSKevin Wolf } 8083c90c65dSKevin Wolf 809e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs) 810e1302255SPaolo Bonzini { 8119a4f4c31SKevin Wolf return bdrv_getlength(bs->file->bs); 812e1302255SPaolo Bonzini } 813e1302255SPaolo Bonzini 8144bff28b8SMax Reitz static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp) 8158eedfbd4SKevin Wolf { 8164bff28b8SMax Reitz return bdrv_truncate(bs->file, offset, errp); 8178eedfbd4SKevin Wolf } 8188eedfbd4SKevin Wolf 8194cdd01d3SKevin Wolf static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) 8202c31b04cSMax Reitz { 821036990d7SMax Reitz BDRVBlkdebugState *s = bs->opaque; 8222c31b04cSMax Reitz QDict *opts; 8238779441bSMax Reitz const QDictEntry *e; 8248779441bSMax Reitz bool force_json = false; 8252c31b04cSMax Reitz 8264cdd01d3SKevin Wolf for (e = qdict_first(options); e; e = qdict_next(options, e)) { 8278779441bSMax Reitz if (strcmp(qdict_entry_key(e), "config") && 8284cdd01d3SKevin Wolf strcmp(qdict_entry_key(e), "x-image")) 8298779441bSMax Reitz { 8308779441bSMax Reitz force_json = true; 8318779441bSMax Reitz break; 8328779441bSMax Reitz } 8338779441bSMax Reitz } 8348779441bSMax Reitz 8359a4f4c31SKevin Wolf if (force_json && !bs->file->bs->full_open_options) { 8362c31b04cSMax Reitz /* The config file cannot be recreated, so creating a plain filename 8372c31b04cSMax Reitz * is impossible */ 8382c31b04cSMax Reitz return; 8392c31b04cSMax Reitz } 8402c31b04cSMax Reitz 8419a4f4c31SKevin Wolf if (!force_json && bs->file->bs->exact_filename[0]) { 842*de81d72dSMax Reitz int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), 843036990d7SMax Reitz "blkdebug:%s:%s", s->config_file ?: "", 8449a4f4c31SKevin Wolf bs->file->bs->exact_filename); 845*de81d72dSMax Reitz if (ret >= sizeof(bs->exact_filename)) { 846*de81d72dSMax Reitz /* An overflow makes the filename unusable, so do not report any */ 847*de81d72dSMax Reitz bs->exact_filename[0] = 0; 848*de81d72dSMax Reitz } 8498779441bSMax Reitz } 8508779441bSMax Reitz 8512c31b04cSMax Reitz opts = qdict_new(); 85246f5ac20SEric Blake qdict_put_str(opts, "driver", "blkdebug"); 8532c31b04cSMax Reitz 8549a4f4c31SKevin Wolf QINCREF(bs->file->bs->full_open_options); 855de6e7951SEric Blake qdict_put(opts, "image", bs->file->bs->full_open_options); 8562c31b04cSMax Reitz 8574cdd01d3SKevin Wolf for (e = qdict_first(options); e; e = qdict_next(options, e)) { 8584cdd01d3SKevin Wolf if (strcmp(qdict_entry_key(e), "x-image")) { 8598779441bSMax Reitz qobject_incref(qdict_entry_value(e)); 8608779441bSMax Reitz qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); 8612c31b04cSMax Reitz } 8622c31b04cSMax Reitz } 8632c31b04cSMax Reitz 8642c31b04cSMax Reitz bs->full_open_options = opts; 8652c31b04cSMax Reitz } 8662c31b04cSMax Reitz 867835db3eeSEric Blake static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) 868835db3eeSEric Blake { 869835db3eeSEric Blake BDRVBlkdebugState *s = bs->opaque; 870835db3eeSEric Blake 871835db3eeSEric Blake if (s->align) { 872a5b8dd2cSEric Blake bs->bl.request_alignment = s->align; 873835db3eeSEric Blake } 874430b26a8SEric Blake if (s->max_transfer) { 875430b26a8SEric Blake bs->bl.max_transfer = s->max_transfer; 876430b26a8SEric Blake } 877430b26a8SEric Blake if (s->opt_write_zero) { 878430b26a8SEric Blake bs->bl.pwrite_zeroes_alignment = s->opt_write_zero; 879430b26a8SEric Blake } 880430b26a8SEric Blake if (s->max_write_zero) { 881430b26a8SEric Blake bs->bl.max_pwrite_zeroes = s->max_write_zero; 882430b26a8SEric Blake } 883430b26a8SEric Blake if (s->opt_discard) { 884430b26a8SEric Blake bs->bl.pdiscard_alignment = s->opt_discard; 885430b26a8SEric Blake } 886430b26a8SEric Blake if (s->max_discard) { 887430b26a8SEric Blake bs->bl.max_pdiscard = s->max_discard; 888430b26a8SEric Blake } 889835db3eeSEric Blake } 890835db3eeSEric Blake 891c5e8bfb7SKevin Wolf static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, 892c5e8bfb7SKevin Wolf BlockReopenQueue *queue, Error **errp) 893c5e8bfb7SKevin Wolf { 894c5e8bfb7SKevin Wolf return 0; 895c5e8bfb7SKevin Wolf } 896c5e8bfb7SKevin Wolf 8976a143727SKevin Wolf static BlockDriver bdrv_blkdebug = { 8986a143727SKevin Wolf .format_name = "blkdebug", 8996a143727SKevin Wolf .protocol_name = "blkdebug", 9006a143727SKevin Wolf .instance_size = sizeof(BDRVBlkdebugState), 9016a143727SKevin Wolf 902f4681212SKevin Wolf .bdrv_parse_filename = blkdebug_parse_filename, 90366f82ceeSKevin Wolf .bdrv_file_open = blkdebug_open, 9046a143727SKevin Wolf .bdrv_close = blkdebug_close, 905c5e8bfb7SKevin Wolf .bdrv_reopen_prepare = blkdebug_reopen_prepare, 906d7010dfbSKevin Wolf .bdrv_child_perm = bdrv_filter_default_perms, 907d7010dfbSKevin Wolf 908e1302255SPaolo Bonzini .bdrv_getlength = blkdebug_getlength, 9098eedfbd4SKevin Wolf .bdrv_truncate = blkdebug_truncate, 9102c31b04cSMax Reitz .bdrv_refresh_filename = blkdebug_refresh_filename, 911835db3eeSEric Blake .bdrv_refresh_limits = blkdebug_refresh_limits, 9126a143727SKevin Wolf 9137c3a9985SKevin Wolf .bdrv_co_preadv = blkdebug_co_preadv, 9147c3a9985SKevin Wolf .bdrv_co_pwritev = blkdebug_co_pwritev, 9157c3a9985SKevin Wolf .bdrv_co_flush_to_disk = blkdebug_co_flush, 91663188c24SEric Blake .bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes, 91763188c24SEric Blake .bdrv_co_pdiscard = blkdebug_co_pdiscard, 9188b9b0cc2SKevin Wolf 9198b9b0cc2SKevin Wolf .bdrv_debug_event = blkdebug_debug_event, 9203c90c65dSKevin Wolf .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 9214cc70e93SFam Zheng .bdrv_debug_remove_breakpoint 9224cc70e93SFam Zheng = blkdebug_debug_remove_breakpoint, 9233c90c65dSKevin Wolf .bdrv_debug_resume = blkdebug_debug_resume, 9243c90c65dSKevin Wolf .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 9256a143727SKevin Wolf }; 9266a143727SKevin Wolf 9276a143727SKevin Wolf static void bdrv_blkdebug_init(void) 9286a143727SKevin Wolf { 9296a143727SKevin Wolf bdrv_register(&bdrv_blkdebug); 9306a143727SKevin Wolf } 9316a143727SKevin Wolf 9326a143727SKevin Wolf block_init(bdrv_blkdebug_init); 933