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 2580c71a24SPeter Maydell #include "qemu/osdep.h" 26da34e65cSMarkus Armbruster #include "qapi/error.h" 27f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 281de7afc9SPaolo Bonzini #include "qemu/config-file.h" 29737e150eSPaolo Bonzini #include "block/block_int.h" 301de7afc9SPaolo Bonzini #include "qemu/module.h" 312c31b04cSMax Reitz #include "qapi/qmp/qbool.h" 322c31b04cSMax Reitz #include "qapi/qmp/qdict.h" 332c31b04cSMax Reitz #include "qapi/qmp/qint.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; 40835db3eeSEric Blake int align; 413c90c65dSKevin Wolf 42036990d7SMax Reitz /* For blkdebug_refresh_filename() */ 43036990d7SMax Reitz char *config_file; 44036990d7SMax Reitz 457fb1cf16SEric Blake QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX]; 46571cd43eSPaolo Bonzini QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; 473c90c65dSKevin Wolf QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; 486a143727SKevin Wolf } BDRVBlkdebugState; 496a143727SKevin Wolf 50b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB { 517c84b1b8SMarkus Armbruster BlockAIOCB common; 52b9f66d96SKevin Wolf int ret; 53b9f66d96SKevin Wolf } BlkdebugAIOCB; 54b9f66d96SKevin Wolf 553c90c65dSKevin Wolf typedef struct BlkdebugSuspendedReq { 563c90c65dSKevin Wolf Coroutine *co; 573c90c65dSKevin Wolf char *tag; 583c90c65dSKevin Wolf QLIST_ENTRY(BlkdebugSuspendedReq) next; 593c90c65dSKevin Wolf } BlkdebugSuspendedReq; 603c90c65dSKevin Wolf 618b9b0cc2SKevin Wolf enum { 628b9b0cc2SKevin Wolf ACTION_INJECT_ERROR, 638b9b0cc2SKevin Wolf ACTION_SET_STATE, 643c90c65dSKevin Wolf ACTION_SUSPEND, 658b9b0cc2SKevin Wolf }; 668b9b0cc2SKevin Wolf 678b9b0cc2SKevin Wolf typedef struct BlkdebugRule { 68a31939e6SEric Blake BlkdebugEvent event; 698b9b0cc2SKevin Wolf int action; 708b9b0cc2SKevin Wolf int state; 718b9b0cc2SKevin Wolf union { 728b9b0cc2SKevin Wolf struct { 738b9b0cc2SKevin Wolf int error; 748b9b0cc2SKevin Wolf int immediately; 758b9b0cc2SKevin Wolf int once; 767c3a9985SKevin Wolf int64_t offset; 778b9b0cc2SKevin Wolf } inject; 788b9b0cc2SKevin Wolf struct { 798b9b0cc2SKevin Wolf int new_state; 808b9b0cc2SKevin Wolf } set_state; 813c90c65dSKevin Wolf struct { 823c90c65dSKevin Wolf char *tag; 833c90c65dSKevin Wolf } suspend; 848b9b0cc2SKevin Wolf } options; 858b9b0cc2SKevin Wolf QLIST_ENTRY(BlkdebugRule) next; 86571cd43eSPaolo Bonzini QSIMPLEQ_ENTRY(BlkdebugRule) active_next; 878b9b0cc2SKevin Wolf } BlkdebugRule; 888b9b0cc2SKevin Wolf 898b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = { 908b9b0cc2SKevin Wolf .name = "inject-error", 918b9b0cc2SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), 928b9b0cc2SKevin Wolf .desc = { 938b9b0cc2SKevin Wolf { 948b9b0cc2SKevin Wolf .name = "event", 958b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 968b9b0cc2SKevin Wolf }, 978b9b0cc2SKevin Wolf { 988b9b0cc2SKevin Wolf .name = "state", 998b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1008b9b0cc2SKevin Wolf }, 1018b9b0cc2SKevin Wolf { 1028b9b0cc2SKevin Wolf .name = "errno", 1038b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1048b9b0cc2SKevin Wolf }, 1058b9b0cc2SKevin Wolf { 106e4780db4SPaolo Bonzini .name = "sector", 107e4780db4SPaolo Bonzini .type = QEMU_OPT_NUMBER, 108e4780db4SPaolo Bonzini }, 109e4780db4SPaolo Bonzini { 1108b9b0cc2SKevin Wolf .name = "once", 1118b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 1128b9b0cc2SKevin Wolf }, 1138b9b0cc2SKevin Wolf { 1148b9b0cc2SKevin Wolf .name = "immediately", 1158b9b0cc2SKevin Wolf .type = QEMU_OPT_BOOL, 1168b9b0cc2SKevin Wolf }, 1178b9b0cc2SKevin Wolf { /* end of list */ } 1188b9b0cc2SKevin Wolf }, 1198b9b0cc2SKevin Wolf }; 1208b9b0cc2SKevin Wolf 1218b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = { 1228b9b0cc2SKevin Wolf .name = "set-state", 123327cdad4SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), 1248b9b0cc2SKevin Wolf .desc = { 1258b9b0cc2SKevin Wolf { 1268b9b0cc2SKevin Wolf .name = "event", 1278b9b0cc2SKevin Wolf .type = QEMU_OPT_STRING, 1288b9b0cc2SKevin Wolf }, 1298b9b0cc2SKevin Wolf { 1308b9b0cc2SKevin Wolf .name = "state", 1318b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1328b9b0cc2SKevin Wolf }, 1338b9b0cc2SKevin Wolf { 1348b9b0cc2SKevin Wolf .name = "new_state", 1358b9b0cc2SKevin Wolf .type = QEMU_OPT_NUMBER, 1368b9b0cc2SKevin Wolf }, 1378b9b0cc2SKevin Wolf { /* end of list */ } 1388b9b0cc2SKevin Wolf }, 1398b9b0cc2SKevin Wolf }; 1408b9b0cc2SKevin Wolf 1418b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = { 1428b9b0cc2SKevin Wolf &inject_error_opts, 1438b9b0cc2SKevin Wolf &set_state_opts, 1448b9b0cc2SKevin Wolf NULL 1458b9b0cc2SKevin Wolf }; 1468b9b0cc2SKevin Wolf 147a31939e6SEric Blake static int get_event_by_name(const char *name, BlkdebugEvent *event) 1488b9b0cc2SKevin Wolf { 1498b9b0cc2SKevin Wolf int i; 1508b9b0cc2SKevin Wolf 1517fb1cf16SEric Blake for (i = 0; i < BLKDBG__MAX; i++) { 152a31939e6SEric Blake if (!strcmp(BlkdebugEvent_lookup[i], name)) { 1538b9b0cc2SKevin Wolf *event = i; 1548b9b0cc2SKevin Wolf return 0; 1558b9b0cc2SKevin Wolf } 1568b9b0cc2SKevin Wolf } 1578b9b0cc2SKevin Wolf 1588b9b0cc2SKevin Wolf return -1; 1598b9b0cc2SKevin Wolf } 1608b9b0cc2SKevin Wolf 1618b9b0cc2SKevin Wolf struct add_rule_data { 1628b9b0cc2SKevin Wolf BDRVBlkdebugState *s; 1638b9b0cc2SKevin Wolf int action; 1648b9b0cc2SKevin Wolf }; 1658b9b0cc2SKevin Wolf 16628d0de7aSMarkus Armbruster static int add_rule(void *opaque, QemuOpts *opts, Error **errp) 1678b9b0cc2SKevin Wolf { 1688b9b0cc2SKevin Wolf struct add_rule_data *d = opaque; 1698b9b0cc2SKevin Wolf BDRVBlkdebugState *s = d->s; 1708b9b0cc2SKevin Wolf const char* event_name; 171a31939e6SEric Blake BlkdebugEvent event; 1728b9b0cc2SKevin Wolf struct BlkdebugRule *rule; 1737c3a9985SKevin Wolf int64_t sector; 1748b9b0cc2SKevin Wolf 1758b9b0cc2SKevin Wolf /* Find the right event for the rule */ 1768b9b0cc2SKevin Wolf event_name = qemu_opt_get(opts, "event"); 177d4362d64SStefan Hajnoczi if (!event_name) { 1788809cfc3SMarkus Armbruster error_setg(errp, "Missing event name for rule"); 179d4362d64SStefan Hajnoczi return -1; 180d4362d64SStefan Hajnoczi } else if (get_event_by_name(event_name, &event) < 0) { 1818809cfc3SMarkus Armbruster error_setg(errp, "Invalid event name \"%s\"", event_name); 1828b9b0cc2SKevin Wolf return -1; 1838b9b0cc2SKevin Wolf } 1848b9b0cc2SKevin Wolf 1858b9b0cc2SKevin Wolf /* Set attributes common for all actions */ 1867267c094SAnthony Liguori rule = g_malloc0(sizeof(*rule)); 1878b9b0cc2SKevin Wolf *rule = (struct BlkdebugRule) { 1888b9b0cc2SKevin Wolf .event = event, 1898b9b0cc2SKevin Wolf .action = d->action, 1908b9b0cc2SKevin Wolf .state = qemu_opt_get_number(opts, "state", 0), 1918b9b0cc2SKevin Wolf }; 1928b9b0cc2SKevin Wolf 1938b9b0cc2SKevin Wolf /* Parse action-specific options */ 1948b9b0cc2SKevin Wolf switch (d->action) { 1958b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 1968b9b0cc2SKevin Wolf rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO); 1978b9b0cc2SKevin Wolf rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); 1988b9b0cc2SKevin Wolf rule->options.inject.immediately = 1998b9b0cc2SKevin Wolf qemu_opt_get_bool(opts, "immediately", 0); 2007c3a9985SKevin Wolf sector = qemu_opt_get_number(opts, "sector", -1); 2017c3a9985SKevin Wolf rule->options.inject.offset = 2027c3a9985SKevin Wolf sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; 2038b9b0cc2SKevin Wolf break; 2048b9b0cc2SKevin Wolf 2058b9b0cc2SKevin Wolf case ACTION_SET_STATE: 2068b9b0cc2SKevin Wolf rule->options.set_state.new_state = 2078b9b0cc2SKevin Wolf qemu_opt_get_number(opts, "new_state", 0); 2088b9b0cc2SKevin Wolf break; 2093c90c65dSKevin Wolf 2103c90c65dSKevin Wolf case ACTION_SUSPEND: 2113c90c65dSKevin Wolf rule->options.suspend.tag = 2123c90c65dSKevin Wolf g_strdup(qemu_opt_get(opts, "tag")); 2133c90c65dSKevin Wolf break; 2148b9b0cc2SKevin Wolf }; 2158b9b0cc2SKevin Wolf 2168b9b0cc2SKevin Wolf /* Add the rule */ 2178b9b0cc2SKevin Wolf QLIST_INSERT_HEAD(&s->rules[event], rule, next); 2188b9b0cc2SKevin Wolf 2198b9b0cc2SKevin Wolf return 0; 2208b9b0cc2SKevin Wolf } 2218b9b0cc2SKevin Wolf 2229e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule) 2239e35542bSKevin Wolf { 2249e35542bSKevin Wolf switch (rule->action) { 2259e35542bSKevin Wolf case ACTION_INJECT_ERROR: 2269e35542bSKevin Wolf case ACTION_SET_STATE: 2279e35542bSKevin Wolf break; 2283c90c65dSKevin Wolf case ACTION_SUSPEND: 2293c90c65dSKevin Wolf g_free(rule->options.suspend.tag); 2303c90c65dSKevin Wolf break; 2319e35542bSKevin Wolf } 2329e35542bSKevin Wolf 2339e35542bSKevin Wolf QLIST_REMOVE(rule, next); 2349e35542bSKevin Wolf g_free(rule); 2359e35542bSKevin Wolf } 2369e35542bSKevin Wolf 23789f2b21eSMax Reitz static int read_config(BDRVBlkdebugState *s, const char *filename, 23889f2b21eSMax Reitz QDict *options, Error **errp) 2398b9b0cc2SKevin Wolf { 24085a040e5SMax Reitz FILE *f = NULL; 2418b9b0cc2SKevin Wolf int ret; 2428b9b0cc2SKevin Wolf struct add_rule_data d; 24389f2b21eSMax Reitz Error *local_err = NULL; 2448b9b0cc2SKevin Wolf 24585a040e5SMax Reitz if (filename) { 2468b9b0cc2SKevin Wolf f = fopen(filename, "r"); 2478b9b0cc2SKevin Wolf if (f == NULL) { 248466b49f2SMax Reitz error_setg_errno(errp, errno, "Could not read blkdebug config file"); 2498b9b0cc2SKevin Wolf return -errno; 2508b9b0cc2SKevin Wolf } 2518b9b0cc2SKevin Wolf 2528b9b0cc2SKevin Wolf ret = qemu_config_parse(f, config_groups, filename); 2538b9b0cc2SKevin Wolf if (ret < 0) { 254466b49f2SMax Reitz error_setg(errp, "Could not parse blkdebug config file"); 255466b49f2SMax Reitz ret = -EINVAL; 2568b9b0cc2SKevin Wolf goto fail; 2578b9b0cc2SKevin Wolf } 25885a040e5SMax Reitz } 2598b9b0cc2SKevin Wolf 26089f2b21eSMax Reitz qemu_config_parse_qdict(options, config_groups, &local_err); 26184d18f06SMarkus Armbruster if (local_err) { 26289f2b21eSMax Reitz error_propagate(errp, local_err); 26389f2b21eSMax Reitz ret = -EINVAL; 26489f2b21eSMax Reitz goto fail; 26589f2b21eSMax Reitz } 26689f2b21eSMax Reitz 2678b9b0cc2SKevin Wolf d.s = s; 2688b9b0cc2SKevin Wolf d.action = ACTION_INJECT_ERROR; 2698809cfc3SMarkus Armbruster qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err); 270d4362d64SStefan Hajnoczi if (local_err) { 271d4362d64SStefan Hajnoczi error_propagate(errp, local_err); 272d4362d64SStefan Hajnoczi ret = -EINVAL; 273d4362d64SStefan Hajnoczi goto fail; 274d4362d64SStefan Hajnoczi } 2758b9b0cc2SKevin Wolf 2768b9b0cc2SKevin Wolf d.action = ACTION_SET_STATE; 2778809cfc3SMarkus Armbruster qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err); 278d4362d64SStefan Hajnoczi if (local_err) { 279d4362d64SStefan Hajnoczi error_propagate(errp, local_err); 280d4362d64SStefan Hajnoczi ret = -EINVAL; 281d4362d64SStefan Hajnoczi goto fail; 282d4362d64SStefan Hajnoczi } 2838b9b0cc2SKevin Wolf 2848b9b0cc2SKevin Wolf ret = 0; 2858b9b0cc2SKevin Wolf fail: 286698f0d52SKevin Wolf qemu_opts_reset(&inject_error_opts); 287698f0d52SKevin Wolf qemu_opts_reset(&set_state_opts); 28885a040e5SMax Reitz if (f) { 2898b9b0cc2SKevin Wolf fclose(f); 29085a040e5SMax Reitz } 2918b9b0cc2SKevin Wolf return ret; 2928b9b0cc2SKevin Wolf } 2938b9b0cc2SKevin Wolf 2948b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ 295f4681212SKevin Wolf static void blkdebug_parse_filename(const char *filename, QDict *options, 296f4681212SKevin Wolf Error **errp) 297f4681212SKevin Wolf { 298f4681212SKevin Wolf const char *c; 299f4681212SKevin Wolf 300f4681212SKevin Wolf /* Parse the blkdebug: prefix */ 301f4681212SKevin Wolf if (!strstart(filename, "blkdebug:", &filename)) { 302d4881b9bSMax Reitz /* There was no prefix; therefore, all options have to be already 303d4881b9bSMax Reitz present in the QDict (except for the filename) */ 304d4881b9bSMax Reitz qdict_put(options, "x-image", qstring_from_str(filename)); 305f4681212SKevin Wolf return; 306f4681212SKevin Wolf } 307f4681212SKevin Wolf 308f4681212SKevin Wolf /* Parse config file path */ 309f4681212SKevin Wolf c = strchr(filename, ':'); 310f4681212SKevin Wolf if (c == NULL) { 311f4681212SKevin Wolf error_setg(errp, "blkdebug requires both config file and image path"); 312f4681212SKevin Wolf return; 313f4681212SKevin Wolf } 314f4681212SKevin Wolf 315f4681212SKevin Wolf if (c != filename) { 316f4681212SKevin Wolf QString *config_path; 317f4681212SKevin Wolf config_path = qstring_from_substr(filename, 0, c - filename - 1); 318f4681212SKevin Wolf qdict_put(options, "config", config_path); 319f4681212SKevin Wolf } 320f4681212SKevin Wolf 321f4681212SKevin Wolf /* TODO Allow multi-level nesting and set file.filename here */ 322f4681212SKevin Wolf filename = c + 1; 323f4681212SKevin Wolf qdict_put(options, "x-image", qstring_from_str(filename)); 324f4681212SKevin Wolf } 325f4681212SKevin Wolf 326f4681212SKevin Wolf static QemuOptsList runtime_opts = { 327f4681212SKevin Wolf .name = "blkdebug", 328f4681212SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 329f4681212SKevin Wolf .desc = { 330f4681212SKevin Wolf { 331f4681212SKevin Wolf .name = "config", 332f4681212SKevin Wolf .type = QEMU_OPT_STRING, 333f4681212SKevin Wolf .help = "Path to the configuration file", 334f4681212SKevin Wolf }, 335f4681212SKevin Wolf { 336f4681212SKevin Wolf .name = "x-image", 337f4681212SKevin Wolf .type = QEMU_OPT_STRING, 338f4681212SKevin Wolf .help = "[internal use only, will be removed]", 339f4681212SKevin Wolf }, 340b35ee7fbSKevin Wolf { 341b35ee7fbSKevin Wolf .name = "align", 342b35ee7fbSKevin Wolf .type = QEMU_OPT_SIZE, 343b35ee7fbSKevin Wolf .help = "Required alignment in bytes", 344b35ee7fbSKevin Wolf }, 345f4681212SKevin Wolf { /* end of list */ } 346f4681212SKevin Wolf }, 347f4681212SKevin Wolf }; 348f4681212SKevin Wolf 349015a1036SMax Reitz static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, 350015a1036SMax Reitz Error **errp) 3516a143727SKevin Wolf { 3526a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 353f4681212SKevin Wolf QemuOpts *opts; 354f4681212SKevin Wolf Error *local_err = NULL; 355b35ee7fbSKevin Wolf uint64_t align; 3568b9b0cc2SKevin Wolf int ret; 3576a143727SKevin Wolf 35887ea75d5SPeter Crosthwaite opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 359f4681212SKevin Wolf qemu_opts_absorb_qdict(opts, options, &local_err); 36084d18f06SMarkus Armbruster if (local_err) { 36110ffa72fSMax Reitz error_propagate(errp, local_err); 362f4681212SKevin Wolf ret = -EINVAL; 363eaf944a4SKevin Wolf goto out; 3646a143727SKevin Wolf } 3656a143727SKevin Wolf 36689f2b21eSMax Reitz /* Read rules from config file or command line options */ 367036990d7SMax Reitz s->config_file = g_strdup(qemu_opt_get(opts, "config")); 368036990d7SMax Reitz ret = read_config(s, s->config_file, options, errp); 369466b49f2SMax Reitz if (ret) { 370eaf944a4SKevin Wolf goto out; 3718b9b0cc2SKevin Wolf } 3728b9b0cc2SKevin Wolf 3738db520ceSKevin Wolf /* Set initial state */ 374571cd43eSPaolo Bonzini s->state = 1; 3758db520ceSKevin Wolf 3766b826af7SFam Zheng /* Open the image file */ 3779a4f4c31SKevin Wolf bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", 378f3930ed0SKevin Wolf bs, &child_file, false, &local_err); 3799a4f4c31SKevin Wolf if (local_err) { 3809a4f4c31SKevin Wolf ret = -EINVAL; 38110ffa72fSMax Reitz error_propagate(errp, local_err); 382eaf944a4SKevin Wolf goto out; 383f4681212SKevin Wolf } 384f4681212SKevin Wolf 385b35ee7fbSKevin Wolf /* Set request alignment */ 386835db3eeSEric Blake align = qemu_opt_get_size(opts, "align", 0); 387835db3eeSEric Blake if (align < INT_MAX && is_power_of_2(align)) { 388835db3eeSEric Blake s->align = align; 389835db3eeSEric Blake } else if (align) { 390b35ee7fbSKevin Wolf error_setg(errp, "Invalid alignment"); 391b35ee7fbSKevin Wolf ret = -EINVAL; 392de234897SMax Reitz goto out; 393b35ee7fbSKevin Wolf } 394b35ee7fbSKevin Wolf 395f4681212SKevin Wolf ret = 0; 396eaf944a4SKevin Wolf goto out; 397eaf944a4SKevin Wolf 398eaf944a4SKevin Wolf out: 399036990d7SMax Reitz if (ret < 0) { 400036990d7SMax Reitz g_free(s->config_file); 401036990d7SMax Reitz } 402f4681212SKevin Wolf qemu_opts_del(opts); 403f4681212SKevin Wolf return ret; 4046a143727SKevin Wolf } 4056a143727SKevin Wolf 4067c3a9985SKevin Wolf static int inject_error(BlockDriverState *bs, BlkdebugRule *rule) 407b9f66d96SKevin Wolf { 408b9f66d96SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 409571cd43eSPaolo Bonzini int error = rule->options.inject.error; 410a069e2f1SJohn Snow bool immediately = rule->options.inject.immediately; 411b9f66d96SKevin Wolf 412571cd43eSPaolo Bonzini if (rule->options.inject.once) { 413a069e2f1SJohn Snow QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next); 414a069e2f1SJohn Snow remove_rule(rule); 415b9f66d96SKevin Wolf } 416b9f66d96SKevin Wolf 4177c3a9985SKevin Wolf if (!immediately) { 418e5c67ab5SPaolo Bonzini aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); 4197c3a9985SKevin Wolf qemu_coroutine_yield(); 420b9f66d96SKevin Wolf } 421b9f66d96SKevin Wolf 4227c3a9985SKevin Wolf return -error; 423b9f66d96SKevin Wolf } 424b9f66d96SKevin Wolf 4257c3a9985SKevin Wolf static int coroutine_fn 4267c3a9985SKevin Wolf blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 4277c3a9985SKevin Wolf QEMUIOVector *qiov, int flags) 4286a143727SKevin Wolf { 4296a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 430e4780db4SPaolo Bonzini BlkdebugRule *rule = NULL; 431e4780db4SPaolo Bonzini 432e4780db4SPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 4337c3a9985SKevin Wolf uint64_t inject_offset = rule->options.inject.offset; 4347c3a9985SKevin Wolf 4357c3a9985SKevin Wolf if (inject_offset == -1 || 4367c3a9985SKevin Wolf (inject_offset >= offset && inject_offset < offset + bytes)) 4377c3a9985SKevin Wolf { 438e4780db4SPaolo Bonzini break; 439e4780db4SPaolo Bonzini } 440e4780db4SPaolo Bonzini } 441b9f66d96SKevin Wolf 442571cd43eSPaolo Bonzini if (rule && rule->options.inject.error) { 4437c3a9985SKevin Wolf return inject_error(bs, rule); 444b9f66d96SKevin Wolf } 445b9f66d96SKevin Wolf 4467c3a9985SKevin Wolf return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 4476a143727SKevin Wolf } 4486a143727SKevin Wolf 4497c3a9985SKevin Wolf static int coroutine_fn 4507c3a9985SKevin Wolf blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 4517c3a9985SKevin Wolf QEMUIOVector *qiov, int flags) 4526a143727SKevin Wolf { 4536a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 454e4780db4SPaolo Bonzini BlkdebugRule *rule = NULL; 455e4780db4SPaolo Bonzini 456e4780db4SPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 4577c3a9985SKevin Wolf uint64_t inject_offset = rule->options.inject.offset; 4587c3a9985SKevin Wolf 4597c3a9985SKevin Wolf if (inject_offset == -1 || 4607c3a9985SKevin Wolf (inject_offset >= offset && inject_offset < offset + bytes)) 4617c3a9985SKevin Wolf { 462e4780db4SPaolo Bonzini break; 463e4780db4SPaolo Bonzini } 464e4780db4SPaolo Bonzini } 465b9f66d96SKevin Wolf 466571cd43eSPaolo Bonzini if (rule && rule->options.inject.error) { 4677c3a9985SKevin Wolf return inject_error(bs, rule); 468b9f66d96SKevin Wolf } 469b9f66d96SKevin Wolf 4707c3a9985SKevin Wolf return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 4716a143727SKevin Wolf } 4726a143727SKevin Wolf 4737c3a9985SKevin Wolf static int blkdebug_co_flush(BlockDriverState *bs) 4749e52c53bSPaolo Bonzini { 4759e52c53bSPaolo Bonzini BDRVBlkdebugState *s = bs->opaque; 4769e52c53bSPaolo Bonzini BlkdebugRule *rule = NULL; 4779e52c53bSPaolo Bonzini 4789e52c53bSPaolo Bonzini QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { 4797c3a9985SKevin Wolf if (rule->options.inject.offset == -1) { 4809e52c53bSPaolo Bonzini break; 4819e52c53bSPaolo Bonzini } 4829e52c53bSPaolo Bonzini } 4839e52c53bSPaolo Bonzini 4849e52c53bSPaolo Bonzini if (rule && rule->options.inject.error) { 4857c3a9985SKevin Wolf return inject_error(bs, rule); 4869e52c53bSPaolo Bonzini } 4879e52c53bSPaolo Bonzini 4887c3a9985SKevin Wolf return bdrv_co_flush(bs->file->bs); 4899e52c53bSPaolo Bonzini } 4909e52c53bSPaolo Bonzini 4913c90c65dSKevin Wolf 4926a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs) 4936a143727SKevin Wolf { 4946a143727SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 4958b9b0cc2SKevin Wolf BlkdebugRule *rule, *next; 4968b9b0cc2SKevin Wolf int i; 4978b9b0cc2SKevin Wolf 4987fb1cf16SEric Blake for (i = 0; i < BLKDBG__MAX; i++) { 4998b9b0cc2SKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 5009e35542bSKevin Wolf remove_rule(rule); 5018b9b0cc2SKevin Wolf } 5028b9b0cc2SKevin Wolf } 503036990d7SMax Reitz 504036990d7SMax Reitz g_free(s->config_file); 5056a143727SKevin Wolf } 5066a143727SKevin Wolf 5073c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) 5083c90c65dSKevin Wolf { 5093c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5103c90c65dSKevin Wolf BlkdebugSuspendedReq r; 5113c90c65dSKevin Wolf 5123c90c65dSKevin Wolf r = (BlkdebugSuspendedReq) { 5133c90c65dSKevin Wolf .co = qemu_coroutine_self(), 5143c90c65dSKevin Wolf .tag = g_strdup(rule->options.suspend.tag), 5153c90c65dSKevin Wolf }; 5163c90c65dSKevin Wolf 5173c90c65dSKevin Wolf remove_rule(rule); 5183c90c65dSKevin Wolf QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); 5193c90c65dSKevin Wolf 52020873526SMichael S. Tsirkin if (!qtest_enabled()) { 5213c90c65dSKevin Wolf printf("blkdebug: Suspended request '%s'\n", r.tag); 52220873526SMichael S. Tsirkin } 5233c90c65dSKevin Wolf qemu_coroutine_yield(); 52420873526SMichael S. Tsirkin if (!qtest_enabled()) { 5253c90c65dSKevin Wolf printf("blkdebug: Resuming request '%s'\n", r.tag); 52620873526SMichael S. Tsirkin } 5273c90c65dSKevin Wolf 5283c90c65dSKevin Wolf QLIST_REMOVE(&r, next); 5293c90c65dSKevin Wolf g_free(r.tag); 5303c90c65dSKevin Wolf } 5313c90c65dSKevin Wolf 532571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, 5338f96b5beSPaolo Bonzini bool injected) 5348b9b0cc2SKevin Wolf { 5358b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5368b9b0cc2SKevin Wolf 5378b9b0cc2SKevin Wolf /* Only process rules for the current state */ 5388f96b5beSPaolo Bonzini if (rule->state && rule->state != s->state) { 539571cd43eSPaolo Bonzini return injected; 5408b9b0cc2SKevin Wolf } 5418b9b0cc2SKevin Wolf 5428b9b0cc2SKevin Wolf /* Take the action */ 5438b9b0cc2SKevin Wolf switch (rule->action) { 5448b9b0cc2SKevin Wolf case ACTION_INJECT_ERROR: 545571cd43eSPaolo Bonzini if (!injected) { 546571cd43eSPaolo Bonzini QSIMPLEQ_INIT(&s->active_rules); 547571cd43eSPaolo Bonzini injected = true; 548571cd43eSPaolo Bonzini } 549571cd43eSPaolo Bonzini QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); 5508b9b0cc2SKevin Wolf break; 5518b9b0cc2SKevin Wolf 5528b9b0cc2SKevin Wolf case ACTION_SET_STATE: 5538f96b5beSPaolo Bonzini s->new_state = rule->options.set_state.new_state; 5548b9b0cc2SKevin Wolf break; 5553c90c65dSKevin Wolf 5563c90c65dSKevin Wolf case ACTION_SUSPEND: 5573c90c65dSKevin Wolf suspend_request(bs, rule); 5583c90c65dSKevin Wolf break; 5598b9b0cc2SKevin Wolf } 560571cd43eSPaolo Bonzini return injected; 5618b9b0cc2SKevin Wolf } 5628b9b0cc2SKevin Wolf 563a31939e6SEric Blake static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) 5648b9b0cc2SKevin Wolf { 5658b9b0cc2SKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5663c90c65dSKevin Wolf struct BlkdebugRule *rule, *next; 567571cd43eSPaolo Bonzini bool injected; 5688b9b0cc2SKevin Wolf 5697fb1cf16SEric Blake assert((int)event >= 0 && event < BLKDBG__MAX); 5708b9b0cc2SKevin Wolf 571571cd43eSPaolo Bonzini injected = false; 5728f96b5beSPaolo Bonzini s->new_state = s->state; 5733c90c65dSKevin Wolf QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { 5748f96b5beSPaolo Bonzini injected = process_rule(bs, rule, injected); 5758b9b0cc2SKevin Wolf } 5768f96b5beSPaolo Bonzini s->state = s->new_state; 5778b9b0cc2SKevin Wolf } 5788b9b0cc2SKevin Wolf 5793c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, 5803c90c65dSKevin Wolf const char *tag) 5813c90c65dSKevin Wolf { 5823c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 5833c90c65dSKevin Wolf struct BlkdebugRule *rule; 584a31939e6SEric Blake BlkdebugEvent blkdebug_event; 5853c90c65dSKevin Wolf 5863c90c65dSKevin Wolf if (get_event_by_name(event, &blkdebug_event) < 0) { 5873c90c65dSKevin Wolf return -ENOENT; 5883c90c65dSKevin Wolf } 5893c90c65dSKevin Wolf 5903c90c65dSKevin Wolf 5913c90c65dSKevin Wolf rule = g_malloc(sizeof(*rule)); 5923c90c65dSKevin Wolf *rule = (struct BlkdebugRule) { 5933c90c65dSKevin Wolf .event = blkdebug_event, 5943c90c65dSKevin Wolf .action = ACTION_SUSPEND, 5953c90c65dSKevin Wolf .state = 0, 5963c90c65dSKevin Wolf .options.suspend.tag = g_strdup(tag), 5973c90c65dSKevin Wolf }; 5983c90c65dSKevin Wolf 5993c90c65dSKevin Wolf QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); 6003c90c65dSKevin Wolf 6013c90c65dSKevin Wolf return 0; 6023c90c65dSKevin Wolf } 6033c90c65dSKevin Wolf 6043c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) 6053c90c65dSKevin Wolf { 6063c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 607c547e564SFam Zheng BlkdebugSuspendedReq *r, *next; 6083c90c65dSKevin Wolf 609c547e564SFam Zheng QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { 6103c90c65dSKevin Wolf if (!strcmp(r->tag, tag)) { 6110b8b8753SPaolo Bonzini qemu_coroutine_enter(r->co); 6123c90c65dSKevin Wolf return 0; 6133c90c65dSKevin Wolf } 6143c90c65dSKevin Wolf } 6153c90c65dSKevin Wolf return -ENOENT; 6163c90c65dSKevin Wolf } 6173c90c65dSKevin Wolf 6184cc70e93SFam Zheng static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, 6194cc70e93SFam Zheng const char *tag) 6204cc70e93SFam Zheng { 6214cc70e93SFam Zheng BDRVBlkdebugState *s = bs->opaque; 622c547e564SFam Zheng BlkdebugSuspendedReq *r, *r_next; 6234cc70e93SFam Zheng BlkdebugRule *rule, *next; 6244cc70e93SFam Zheng int i, ret = -ENOENT; 6254cc70e93SFam Zheng 6267fb1cf16SEric Blake for (i = 0; i < BLKDBG__MAX; i++) { 6274cc70e93SFam Zheng QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { 6284cc70e93SFam Zheng if (rule->action == ACTION_SUSPEND && 6294cc70e93SFam Zheng !strcmp(rule->options.suspend.tag, tag)) { 6304cc70e93SFam Zheng remove_rule(rule); 6314cc70e93SFam Zheng ret = 0; 6324cc70e93SFam Zheng } 6334cc70e93SFam Zheng } 6344cc70e93SFam Zheng } 635c547e564SFam Zheng QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { 6364cc70e93SFam Zheng if (!strcmp(r->tag, tag)) { 6370b8b8753SPaolo Bonzini qemu_coroutine_enter(r->co); 6384cc70e93SFam Zheng ret = 0; 6394cc70e93SFam Zheng } 6404cc70e93SFam Zheng } 6414cc70e93SFam Zheng return ret; 6424cc70e93SFam Zheng } 6433c90c65dSKevin Wolf 6443c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) 6453c90c65dSKevin Wolf { 6463c90c65dSKevin Wolf BDRVBlkdebugState *s = bs->opaque; 6473c90c65dSKevin Wolf BlkdebugSuspendedReq *r; 6483c90c65dSKevin Wolf 6493c90c65dSKevin Wolf QLIST_FOREACH(r, &s->suspended_reqs, next) { 6503c90c65dSKevin Wolf if (!strcmp(r->tag, tag)) { 6513c90c65dSKevin Wolf return true; 6523c90c65dSKevin Wolf } 6533c90c65dSKevin Wolf } 6543c90c65dSKevin Wolf return false; 6553c90c65dSKevin Wolf } 6563c90c65dSKevin Wolf 657e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs) 658e1302255SPaolo Bonzini { 6599a4f4c31SKevin Wolf return bdrv_getlength(bs->file->bs); 660e1302255SPaolo Bonzini } 661e1302255SPaolo Bonzini 6624bff28b8SMax Reitz static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp) 6638eedfbd4SKevin Wolf { 6644bff28b8SMax Reitz return bdrv_truncate(bs->file, offset, errp); 6658eedfbd4SKevin Wolf } 6668eedfbd4SKevin Wolf 6674cdd01d3SKevin Wolf static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) 6682c31b04cSMax Reitz { 669036990d7SMax Reitz BDRVBlkdebugState *s = bs->opaque; 6702c31b04cSMax Reitz QDict *opts; 6718779441bSMax Reitz const QDictEntry *e; 6728779441bSMax Reitz bool force_json = false; 6732c31b04cSMax Reitz 6744cdd01d3SKevin Wolf for (e = qdict_first(options); e; e = qdict_next(options, e)) { 6758779441bSMax Reitz if (strcmp(qdict_entry_key(e), "config") && 6764cdd01d3SKevin Wolf strcmp(qdict_entry_key(e), "x-image")) 6778779441bSMax Reitz { 6788779441bSMax Reitz force_json = true; 6798779441bSMax Reitz break; 6808779441bSMax Reitz } 6818779441bSMax Reitz } 6828779441bSMax Reitz 6839a4f4c31SKevin Wolf if (force_json && !bs->file->bs->full_open_options) { 6842c31b04cSMax Reitz /* The config file cannot be recreated, so creating a plain filename 6852c31b04cSMax Reitz * is impossible */ 6862c31b04cSMax Reitz return; 6872c31b04cSMax Reitz } 6882c31b04cSMax Reitz 6899a4f4c31SKevin Wolf if (!force_json && bs->file->bs->exact_filename[0]) { 6908779441bSMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), 691036990d7SMax Reitz "blkdebug:%s:%s", s->config_file ?: "", 6929a4f4c31SKevin Wolf bs->file->bs->exact_filename); 6938779441bSMax Reitz } 6948779441bSMax Reitz 6952c31b04cSMax Reitz opts = qdict_new(); 696*de6e7951SEric Blake qdict_put(opts, "driver", qstring_from_str("blkdebug")); 6972c31b04cSMax Reitz 6989a4f4c31SKevin Wolf QINCREF(bs->file->bs->full_open_options); 699*de6e7951SEric Blake qdict_put(opts, "image", bs->file->bs->full_open_options); 7002c31b04cSMax Reitz 7014cdd01d3SKevin Wolf for (e = qdict_first(options); e; e = qdict_next(options, e)) { 7024cdd01d3SKevin Wolf if (strcmp(qdict_entry_key(e), "x-image")) { 7038779441bSMax Reitz qobject_incref(qdict_entry_value(e)); 7048779441bSMax Reitz qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); 7052c31b04cSMax Reitz } 7062c31b04cSMax Reitz } 7072c31b04cSMax Reitz 7082c31b04cSMax Reitz bs->full_open_options = opts; 7092c31b04cSMax Reitz } 7102c31b04cSMax Reitz 711835db3eeSEric Blake static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) 712835db3eeSEric Blake { 713835db3eeSEric Blake BDRVBlkdebugState *s = bs->opaque; 714835db3eeSEric Blake 715835db3eeSEric Blake if (s->align) { 716a5b8dd2cSEric Blake bs->bl.request_alignment = s->align; 717835db3eeSEric Blake } 718835db3eeSEric Blake } 719835db3eeSEric Blake 720c5e8bfb7SKevin Wolf static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, 721c5e8bfb7SKevin Wolf BlockReopenQueue *queue, Error **errp) 722c5e8bfb7SKevin Wolf { 723c5e8bfb7SKevin Wolf return 0; 724c5e8bfb7SKevin Wolf } 725c5e8bfb7SKevin Wolf 7266a143727SKevin Wolf static BlockDriver bdrv_blkdebug = { 7276a143727SKevin Wolf .format_name = "blkdebug", 7286a143727SKevin Wolf .protocol_name = "blkdebug", 7296a143727SKevin Wolf .instance_size = sizeof(BDRVBlkdebugState), 7306a143727SKevin Wolf 731f4681212SKevin Wolf .bdrv_parse_filename = blkdebug_parse_filename, 73266f82ceeSKevin Wolf .bdrv_file_open = blkdebug_open, 7336a143727SKevin Wolf .bdrv_close = blkdebug_close, 734c5e8bfb7SKevin Wolf .bdrv_reopen_prepare = blkdebug_reopen_prepare, 735d7010dfbSKevin Wolf .bdrv_child_perm = bdrv_filter_default_perms, 736d7010dfbSKevin Wolf 737e1302255SPaolo Bonzini .bdrv_getlength = blkdebug_getlength, 7388eedfbd4SKevin Wolf .bdrv_truncate = blkdebug_truncate, 7392c31b04cSMax Reitz .bdrv_refresh_filename = blkdebug_refresh_filename, 740835db3eeSEric Blake .bdrv_refresh_limits = blkdebug_refresh_limits, 7416a143727SKevin Wolf 7427c3a9985SKevin Wolf .bdrv_co_preadv = blkdebug_co_preadv, 7437c3a9985SKevin Wolf .bdrv_co_pwritev = blkdebug_co_pwritev, 7447c3a9985SKevin Wolf .bdrv_co_flush_to_disk = blkdebug_co_flush, 7458b9b0cc2SKevin Wolf 7468b9b0cc2SKevin Wolf .bdrv_debug_event = blkdebug_debug_event, 7473c90c65dSKevin Wolf .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, 7484cc70e93SFam Zheng .bdrv_debug_remove_breakpoint 7494cc70e93SFam Zheng = blkdebug_debug_remove_breakpoint, 7503c90c65dSKevin Wolf .bdrv_debug_resume = blkdebug_debug_resume, 7513c90c65dSKevin Wolf .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, 7526a143727SKevin Wolf }; 7536a143727SKevin Wolf 7546a143727SKevin Wolf static void bdrv_blkdebug_init(void) 7556a143727SKevin Wolf { 7566a143727SKevin Wolf bdrv_register(&bdrv_blkdebug); 7576a143727SKevin Wolf } 7586a143727SKevin Wolf 7596a143727SKevin Wolf block_init(bdrv_blkdebug_init); 760