xref: /qemu/block/blkdebug.c (revision 9a4f4c31)
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"
292c31b04cSMax Reitz #include "qapi/qmp/qbool.h"
302c31b04cSMax Reitz #include "qapi/qmp/qdict.h"
312c31b04cSMax Reitz #include "qapi/qmp/qint.h"
322c31b04cSMax Reitz #include "qapi/qmp/qstring.h"
336a143727SKevin Wolf 
346a143727SKevin Wolf typedef struct BDRVBlkdebugState {
35571cd43eSPaolo Bonzini     int state;
368f96b5beSPaolo Bonzini     int new_state;
373c90c65dSKevin Wolf 
38571cd43eSPaolo Bonzini     QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
39571cd43eSPaolo Bonzini     QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
403c90c65dSKevin Wolf     QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
416a143727SKevin Wolf } BDRVBlkdebugState;
426a143727SKevin Wolf 
43b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB {
447c84b1b8SMarkus Armbruster     BlockAIOCB common;
45b9f66d96SKevin Wolf     QEMUBH *bh;
46b9f66d96SKevin Wolf     int ret;
47b9f66d96SKevin Wolf } BlkdebugAIOCB;
48b9f66d96SKevin Wolf 
493c90c65dSKevin Wolf typedef struct BlkdebugSuspendedReq {
503c90c65dSKevin Wolf     Coroutine *co;
513c90c65dSKevin Wolf     char *tag;
523c90c65dSKevin Wolf     QLIST_ENTRY(BlkdebugSuspendedReq) next;
533c90c65dSKevin Wolf } BlkdebugSuspendedReq;
543c90c65dSKevin Wolf 
55d7331bedSStefan Hajnoczi static const AIOCBInfo blkdebug_aiocb_info = {
56b9f66d96SKevin Wolf     .aiocb_size    = sizeof(BlkdebugAIOCB),
57b9f66d96SKevin Wolf };
58b9f66d96SKevin Wolf 
598b9b0cc2SKevin Wolf enum {
608b9b0cc2SKevin Wolf     ACTION_INJECT_ERROR,
618b9b0cc2SKevin Wolf     ACTION_SET_STATE,
623c90c65dSKevin Wolf     ACTION_SUSPEND,
638b9b0cc2SKevin Wolf };
648b9b0cc2SKevin Wolf 
658b9b0cc2SKevin Wolf typedef struct BlkdebugRule {
668b9b0cc2SKevin Wolf     BlkDebugEvent event;
678b9b0cc2SKevin Wolf     int action;
688b9b0cc2SKevin Wolf     int state;
698b9b0cc2SKevin Wolf     union {
708b9b0cc2SKevin Wolf         struct {
718b9b0cc2SKevin Wolf             int error;
728b9b0cc2SKevin Wolf             int immediately;
738b9b0cc2SKevin Wolf             int once;
74e4780db4SPaolo Bonzini             int64_t sector;
758b9b0cc2SKevin Wolf         } inject;
768b9b0cc2SKevin Wolf         struct {
778b9b0cc2SKevin Wolf             int new_state;
788b9b0cc2SKevin Wolf         } set_state;
793c90c65dSKevin Wolf         struct {
803c90c65dSKevin Wolf             char *tag;
813c90c65dSKevin Wolf         } suspend;
828b9b0cc2SKevin Wolf     } options;
838b9b0cc2SKevin Wolf     QLIST_ENTRY(BlkdebugRule) next;
84571cd43eSPaolo Bonzini     QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
858b9b0cc2SKevin Wolf } BlkdebugRule;
868b9b0cc2SKevin Wolf 
878b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = {
888b9b0cc2SKevin Wolf     .name = "inject-error",
898b9b0cc2SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
908b9b0cc2SKevin Wolf     .desc = {
918b9b0cc2SKevin Wolf         {
928b9b0cc2SKevin Wolf             .name = "event",
938b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
948b9b0cc2SKevin Wolf         },
958b9b0cc2SKevin Wolf         {
968b9b0cc2SKevin Wolf             .name = "state",
978b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
988b9b0cc2SKevin Wolf         },
998b9b0cc2SKevin Wolf         {
1008b9b0cc2SKevin Wolf             .name = "errno",
1018b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1028b9b0cc2SKevin Wolf         },
1038b9b0cc2SKevin Wolf         {
104e4780db4SPaolo Bonzini             .name = "sector",
105e4780db4SPaolo Bonzini             .type = QEMU_OPT_NUMBER,
106e4780db4SPaolo Bonzini         },
107e4780db4SPaolo Bonzini         {
1088b9b0cc2SKevin Wolf             .name = "once",
1098b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
1108b9b0cc2SKevin Wolf         },
1118b9b0cc2SKevin Wolf         {
1128b9b0cc2SKevin Wolf             .name = "immediately",
1138b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
1148b9b0cc2SKevin Wolf         },
1158b9b0cc2SKevin Wolf         { /* end of list */ }
1168b9b0cc2SKevin Wolf     },
1178b9b0cc2SKevin Wolf };
1188b9b0cc2SKevin Wolf 
1198b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = {
1208b9b0cc2SKevin Wolf     .name = "set-state",
121327cdad4SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
1228b9b0cc2SKevin Wolf     .desc = {
1238b9b0cc2SKevin Wolf         {
1248b9b0cc2SKevin Wolf             .name = "event",
1258b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
1268b9b0cc2SKevin Wolf         },
1278b9b0cc2SKevin Wolf         {
1288b9b0cc2SKevin Wolf             .name = "state",
1298b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1308b9b0cc2SKevin Wolf         },
1318b9b0cc2SKevin Wolf         {
1328b9b0cc2SKevin Wolf             .name = "new_state",
1338b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1348b9b0cc2SKevin Wolf         },
1358b9b0cc2SKevin Wolf         { /* end of list */ }
1368b9b0cc2SKevin Wolf     },
1378b9b0cc2SKevin Wolf };
1388b9b0cc2SKevin Wolf 
1398b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = {
1408b9b0cc2SKevin Wolf     &inject_error_opts,
1418b9b0cc2SKevin Wolf     &set_state_opts,
1428b9b0cc2SKevin Wolf     NULL
1438b9b0cc2SKevin Wolf };
1448b9b0cc2SKevin Wolf 
1458b9b0cc2SKevin Wolf static const char *event_names[BLKDBG_EVENT_MAX] = {
1468252278aSKevin Wolf     [BLKDBG_L1_UPDATE]                      = "l1_update",
1478252278aSKevin Wolf     [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
1488252278aSKevin Wolf     [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
1498252278aSKevin Wolf     [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
1508252278aSKevin Wolf 
1518252278aSKevin Wolf     [BLKDBG_L2_LOAD]                        = "l2_load",
1528252278aSKevin Wolf     [BLKDBG_L2_UPDATE]                      = "l2_update",
1538252278aSKevin Wolf     [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
1548252278aSKevin Wolf     [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
1558252278aSKevin Wolf     [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
1568252278aSKevin Wolf 
1578252278aSKevin Wolf     [BLKDBG_READ_AIO]                       = "read_aio",
1588252278aSKevin Wolf     [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
1598252278aSKevin Wolf     [BLKDBG_READ_COMPRESSED]                = "read_compressed",
1608252278aSKevin Wolf 
1618252278aSKevin Wolf     [BLKDBG_WRITE_AIO]                      = "write_aio",
1628252278aSKevin Wolf     [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
1638252278aSKevin Wolf 
1648252278aSKevin Wolf     [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
1658252278aSKevin Wolf     [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
1668252278aSKevin Wolf 
1678252278aSKevin Wolf     [BLKDBG_COW_READ]                       = "cow_read",
1688252278aSKevin Wolf     [BLKDBG_COW_WRITE]                      = "cow_write",
1698252278aSKevin Wolf 
1708252278aSKevin Wolf     [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
1718252278aSKevin Wolf     [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
172afa50193SMax Reitz     [BLKDBG_REFTABLE_UPDATE]                = "reftable_update",
1738252278aSKevin Wolf 
1748252278aSKevin Wolf     [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
1758252278aSKevin Wolf     [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
1768252278aSKevin Wolf     [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
1778252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
1788252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
1798252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
1808252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
1818252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
1828252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
1838252278aSKevin Wolf 
1848252278aSKevin Wolf     [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
1858252278aSKevin Wolf     [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
1868252278aSKevin Wolf     [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
187bf736fe3SKevin Wolf 
188bf736fe3SKevin Wolf     [BLKDBG_FLUSH_TO_OS]                    = "flush_to_os",
189bf736fe3SKevin Wolf     [BLKDBG_FLUSH_TO_DISK]                  = "flush_to_disk",
1909e1cb96dSKevin Wolf 
1919e1cb96dSKevin Wolf     [BLKDBG_PWRITEV_RMW_HEAD]               = "pwritev_rmw.head",
1929e1cb96dSKevin Wolf     [BLKDBG_PWRITEV_RMW_AFTER_HEAD]         = "pwritev_rmw.after_head",
1939e1cb96dSKevin Wolf     [BLKDBG_PWRITEV_RMW_TAIL]               = "pwritev_rmw.tail",
1949e1cb96dSKevin Wolf     [BLKDBG_PWRITEV_RMW_AFTER_TAIL]         = "pwritev_rmw.after_tail",
1959e1cb96dSKevin Wolf     [BLKDBG_PWRITEV]                        = "pwritev",
1969e1cb96dSKevin Wolf     [BLKDBG_PWRITEV_ZERO]                   = "pwritev_zero",
1979e1cb96dSKevin Wolf     [BLKDBG_PWRITEV_DONE]                   = "pwritev_done",
19894054183SMax Reitz 
19994054183SMax Reitz     [BLKDBG_EMPTY_IMAGE_PREPARE]            = "empty_image_prepare",
2008b9b0cc2SKevin Wolf };
2018b9b0cc2SKevin Wolf 
2028b9b0cc2SKevin Wolf static int get_event_by_name(const char *name, BlkDebugEvent *event)
2038b9b0cc2SKevin Wolf {
2048b9b0cc2SKevin Wolf     int i;
2058b9b0cc2SKevin Wolf 
2068b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
2078b9b0cc2SKevin Wolf         if (!strcmp(event_names[i], name)) {
2088b9b0cc2SKevin Wolf             *event = i;
2098b9b0cc2SKevin Wolf             return 0;
2108b9b0cc2SKevin Wolf         }
2118b9b0cc2SKevin Wolf     }
2128b9b0cc2SKevin Wolf 
2138b9b0cc2SKevin Wolf     return -1;
2148b9b0cc2SKevin Wolf }
2158b9b0cc2SKevin Wolf 
2168b9b0cc2SKevin Wolf struct add_rule_data {
2178b9b0cc2SKevin Wolf     BDRVBlkdebugState *s;
2188b9b0cc2SKevin Wolf     int action;
2198b9b0cc2SKevin Wolf };
2208b9b0cc2SKevin Wolf 
22128d0de7aSMarkus Armbruster static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
2228b9b0cc2SKevin Wolf {
2238b9b0cc2SKevin Wolf     struct add_rule_data *d = opaque;
2248b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = d->s;
2258b9b0cc2SKevin Wolf     const char* event_name;
2268b9b0cc2SKevin Wolf     BlkDebugEvent event;
2278b9b0cc2SKevin Wolf     struct BlkdebugRule *rule;
2288b9b0cc2SKevin Wolf 
2298b9b0cc2SKevin Wolf     /* Find the right event for the rule */
2308b9b0cc2SKevin Wolf     event_name = qemu_opt_get(opts, "event");
231d4362d64SStefan Hajnoczi     if (!event_name) {
2328809cfc3SMarkus Armbruster         error_setg(errp, "Missing event name for rule");
233d4362d64SStefan Hajnoczi         return -1;
234d4362d64SStefan Hajnoczi     } else if (get_event_by_name(event_name, &event) < 0) {
2358809cfc3SMarkus Armbruster         error_setg(errp, "Invalid event name \"%s\"", event_name);
2368b9b0cc2SKevin Wolf         return -1;
2378b9b0cc2SKevin Wolf     }
2388b9b0cc2SKevin Wolf 
2398b9b0cc2SKevin Wolf     /* Set attributes common for all actions */
2407267c094SAnthony Liguori     rule = g_malloc0(sizeof(*rule));
2418b9b0cc2SKevin Wolf     *rule = (struct BlkdebugRule) {
2428b9b0cc2SKevin Wolf         .event  = event,
2438b9b0cc2SKevin Wolf         .action = d->action,
2448b9b0cc2SKevin Wolf         .state  = qemu_opt_get_number(opts, "state", 0),
2458b9b0cc2SKevin Wolf     };
2468b9b0cc2SKevin Wolf 
2478b9b0cc2SKevin Wolf     /* Parse action-specific options */
2488b9b0cc2SKevin Wolf     switch (d->action) {
2498b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
2508b9b0cc2SKevin Wolf         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
2518b9b0cc2SKevin Wolf         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
2528b9b0cc2SKevin Wolf         rule->options.inject.immediately =
2538b9b0cc2SKevin Wolf             qemu_opt_get_bool(opts, "immediately", 0);
254e4780db4SPaolo Bonzini         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
2558b9b0cc2SKevin Wolf         break;
2568b9b0cc2SKevin Wolf 
2578b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
2588b9b0cc2SKevin Wolf         rule->options.set_state.new_state =
2598b9b0cc2SKevin Wolf             qemu_opt_get_number(opts, "new_state", 0);
2608b9b0cc2SKevin Wolf         break;
2613c90c65dSKevin Wolf 
2623c90c65dSKevin Wolf     case ACTION_SUSPEND:
2633c90c65dSKevin Wolf         rule->options.suspend.tag =
2643c90c65dSKevin Wolf             g_strdup(qemu_opt_get(opts, "tag"));
2653c90c65dSKevin Wolf         break;
2668b9b0cc2SKevin Wolf     };
2678b9b0cc2SKevin Wolf 
2688b9b0cc2SKevin Wolf     /* Add the rule */
2698b9b0cc2SKevin Wolf     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
2708b9b0cc2SKevin Wolf 
2718b9b0cc2SKevin Wolf     return 0;
2728b9b0cc2SKevin Wolf }
2738b9b0cc2SKevin Wolf 
2749e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule)
2759e35542bSKevin Wolf {
2769e35542bSKevin Wolf     switch (rule->action) {
2779e35542bSKevin Wolf     case ACTION_INJECT_ERROR:
2789e35542bSKevin Wolf     case ACTION_SET_STATE:
2799e35542bSKevin Wolf         break;
2803c90c65dSKevin Wolf     case ACTION_SUSPEND:
2813c90c65dSKevin Wolf         g_free(rule->options.suspend.tag);
2823c90c65dSKevin Wolf         break;
2839e35542bSKevin Wolf     }
2849e35542bSKevin Wolf 
2859e35542bSKevin Wolf     QLIST_REMOVE(rule, next);
2869e35542bSKevin Wolf     g_free(rule);
2879e35542bSKevin Wolf }
2889e35542bSKevin Wolf 
28989f2b21eSMax Reitz static int read_config(BDRVBlkdebugState *s, const char *filename,
29089f2b21eSMax Reitz                        QDict *options, Error **errp)
2918b9b0cc2SKevin Wolf {
29285a040e5SMax Reitz     FILE *f = NULL;
2938b9b0cc2SKevin Wolf     int ret;
2948b9b0cc2SKevin Wolf     struct add_rule_data d;
29589f2b21eSMax Reitz     Error *local_err = NULL;
2968b9b0cc2SKevin Wolf 
29785a040e5SMax Reitz     if (filename) {
2988b9b0cc2SKevin Wolf         f = fopen(filename, "r");
2998b9b0cc2SKevin Wolf         if (f == NULL) {
300466b49f2SMax Reitz             error_setg_errno(errp, errno, "Could not read blkdebug config file");
3018b9b0cc2SKevin Wolf             return -errno;
3028b9b0cc2SKevin Wolf         }
3038b9b0cc2SKevin Wolf 
3048b9b0cc2SKevin Wolf         ret = qemu_config_parse(f, config_groups, filename);
3058b9b0cc2SKevin Wolf         if (ret < 0) {
306466b49f2SMax Reitz             error_setg(errp, "Could not parse blkdebug config file");
307466b49f2SMax Reitz             ret = -EINVAL;
3088b9b0cc2SKevin Wolf             goto fail;
3098b9b0cc2SKevin Wolf         }
31085a040e5SMax Reitz     }
3118b9b0cc2SKevin Wolf 
31289f2b21eSMax Reitz     qemu_config_parse_qdict(options, config_groups, &local_err);
31384d18f06SMarkus Armbruster     if (local_err) {
31489f2b21eSMax Reitz         error_propagate(errp, local_err);
31589f2b21eSMax Reitz         ret = -EINVAL;
31689f2b21eSMax Reitz         goto fail;
31789f2b21eSMax Reitz     }
31889f2b21eSMax Reitz 
3198b9b0cc2SKevin Wolf     d.s = s;
3208b9b0cc2SKevin Wolf     d.action = ACTION_INJECT_ERROR;
3218809cfc3SMarkus Armbruster     qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
322d4362d64SStefan Hajnoczi     if (local_err) {
323d4362d64SStefan Hajnoczi         error_propagate(errp, local_err);
324d4362d64SStefan Hajnoczi         ret = -EINVAL;
325d4362d64SStefan Hajnoczi         goto fail;
326d4362d64SStefan Hajnoczi     }
3278b9b0cc2SKevin Wolf 
3288b9b0cc2SKevin Wolf     d.action = ACTION_SET_STATE;
3298809cfc3SMarkus Armbruster     qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
330d4362d64SStefan Hajnoczi     if (local_err) {
331d4362d64SStefan Hajnoczi         error_propagate(errp, local_err);
332d4362d64SStefan Hajnoczi         ret = -EINVAL;
333d4362d64SStefan Hajnoczi         goto fail;
334d4362d64SStefan Hajnoczi     }
3358b9b0cc2SKevin Wolf 
3368b9b0cc2SKevin Wolf     ret = 0;
3378b9b0cc2SKevin Wolf fail:
338698f0d52SKevin Wolf     qemu_opts_reset(&inject_error_opts);
339698f0d52SKevin Wolf     qemu_opts_reset(&set_state_opts);
34085a040e5SMax Reitz     if (f) {
3418b9b0cc2SKevin Wolf         fclose(f);
34285a040e5SMax Reitz     }
3438b9b0cc2SKevin Wolf     return ret;
3448b9b0cc2SKevin Wolf }
3458b9b0cc2SKevin Wolf 
3468b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
347f4681212SKevin Wolf static void blkdebug_parse_filename(const char *filename, QDict *options,
348f4681212SKevin Wolf                                     Error **errp)
349f4681212SKevin Wolf {
350f4681212SKevin Wolf     const char *c;
351f4681212SKevin Wolf 
352f4681212SKevin Wolf     /* Parse the blkdebug: prefix */
353f4681212SKevin Wolf     if (!strstart(filename, "blkdebug:", &filename)) {
354d4881b9bSMax Reitz         /* There was no prefix; therefore, all options have to be already
355d4881b9bSMax Reitz            present in the QDict (except for the filename) */
356d4881b9bSMax Reitz         qdict_put(options, "x-image", qstring_from_str(filename));
357f4681212SKevin Wolf         return;
358f4681212SKevin Wolf     }
359f4681212SKevin Wolf 
360f4681212SKevin Wolf     /* Parse config file path */
361f4681212SKevin Wolf     c = strchr(filename, ':');
362f4681212SKevin Wolf     if (c == NULL) {
363f4681212SKevin Wolf         error_setg(errp, "blkdebug requires both config file and image path");
364f4681212SKevin Wolf         return;
365f4681212SKevin Wolf     }
366f4681212SKevin Wolf 
367f4681212SKevin Wolf     if (c != filename) {
368f4681212SKevin Wolf         QString *config_path;
369f4681212SKevin Wolf         config_path = qstring_from_substr(filename, 0, c - filename - 1);
370f4681212SKevin Wolf         qdict_put(options, "config", config_path);
371f4681212SKevin Wolf     }
372f4681212SKevin Wolf 
373f4681212SKevin Wolf     /* TODO Allow multi-level nesting and set file.filename here */
374f4681212SKevin Wolf     filename = c + 1;
375f4681212SKevin Wolf     qdict_put(options, "x-image", qstring_from_str(filename));
376f4681212SKevin Wolf }
377f4681212SKevin Wolf 
378f4681212SKevin Wolf static QemuOptsList runtime_opts = {
379f4681212SKevin Wolf     .name = "blkdebug",
380f4681212SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
381f4681212SKevin Wolf     .desc = {
382f4681212SKevin Wolf         {
383f4681212SKevin Wolf             .name = "config",
384f4681212SKevin Wolf             .type = QEMU_OPT_STRING,
385f4681212SKevin Wolf             .help = "Path to the configuration file",
386f4681212SKevin Wolf         },
387f4681212SKevin Wolf         {
388f4681212SKevin Wolf             .name = "x-image",
389f4681212SKevin Wolf             .type = QEMU_OPT_STRING,
390f4681212SKevin Wolf             .help = "[internal use only, will be removed]",
391f4681212SKevin Wolf         },
392b35ee7fbSKevin Wolf         {
393b35ee7fbSKevin Wolf             .name = "align",
394b35ee7fbSKevin Wolf             .type = QEMU_OPT_SIZE,
395b35ee7fbSKevin Wolf             .help = "Required alignment in bytes",
396b35ee7fbSKevin Wolf         },
397f4681212SKevin Wolf         { /* end of list */ }
398f4681212SKevin Wolf     },
399f4681212SKevin Wolf };
400f4681212SKevin Wolf 
401015a1036SMax Reitz static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
402015a1036SMax Reitz                          Error **errp)
4036a143727SKevin Wolf {
4046a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
405f4681212SKevin Wolf     QemuOpts *opts;
406f4681212SKevin Wolf     Error *local_err = NULL;
4074373593dSMax Reitz     const char *config;
408b35ee7fbSKevin Wolf     uint64_t align;
4098b9b0cc2SKevin Wolf     int ret;
4106a143727SKevin Wolf 
41187ea75d5SPeter Crosthwaite     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
412f4681212SKevin Wolf     qemu_opts_absorb_qdict(opts, options, &local_err);
41384d18f06SMarkus Armbruster     if (local_err) {
41410ffa72fSMax Reitz         error_propagate(errp, local_err);
415f4681212SKevin Wolf         ret = -EINVAL;
416eaf944a4SKevin Wolf         goto out;
4176a143727SKevin Wolf     }
4186a143727SKevin Wolf 
41989f2b21eSMax Reitz     /* Read rules from config file or command line options */
420f4681212SKevin Wolf     config = qemu_opt_get(opts, "config");
42189f2b21eSMax Reitz     ret = read_config(s, config, options, errp);
422466b49f2SMax Reitz     if (ret) {
423eaf944a4SKevin Wolf         goto out;
4248b9b0cc2SKevin Wolf     }
4258b9b0cc2SKevin Wolf 
4268db520ceSKevin Wolf     /* Set initial state */
427571cd43eSPaolo Bonzini     s->state = 1;
4288db520ceSKevin Wolf 
4298b9b0cc2SKevin Wolf     /* Open the backing file */
430*9a4f4c31SKevin Wolf     bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
431f3930ed0SKevin Wolf                                bs, &child_file, false, &local_err);
432*9a4f4c31SKevin Wolf     if (local_err) {
433*9a4f4c31SKevin Wolf         ret = -EINVAL;
43410ffa72fSMax Reitz         error_propagate(errp, local_err);
435eaf944a4SKevin Wolf         goto out;
436f4681212SKevin Wolf     }
437f4681212SKevin Wolf 
438b35ee7fbSKevin Wolf     /* Set request alignment */
439b35ee7fbSKevin Wolf     align = qemu_opt_get_size(opts, "align", bs->request_alignment);
440b35ee7fbSKevin Wolf     if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
441b35ee7fbSKevin Wolf         bs->request_alignment = align;
442b35ee7fbSKevin Wolf     } else {
443b35ee7fbSKevin Wolf         error_setg(errp, "Invalid alignment");
444b35ee7fbSKevin Wolf         ret = -EINVAL;
445eaf944a4SKevin Wolf         goto fail_unref;
446b35ee7fbSKevin Wolf     }
447b35ee7fbSKevin Wolf 
448f4681212SKevin Wolf     ret = 0;
449eaf944a4SKevin Wolf     goto out;
450eaf944a4SKevin Wolf 
451eaf944a4SKevin Wolf fail_unref:
452*9a4f4c31SKevin Wolf     bdrv_unref_child(bs, bs->file);
453eaf944a4SKevin Wolf out:
454f4681212SKevin Wolf     qemu_opts_del(opts);
455f4681212SKevin Wolf     return ret;
4566a143727SKevin Wolf }
4576a143727SKevin Wolf 
458b9f66d96SKevin Wolf static void error_callback_bh(void *opaque)
459b9f66d96SKevin Wolf {
460b9f66d96SKevin Wolf     struct BlkdebugAIOCB *acb = opaque;
461b9f66d96SKevin Wolf     qemu_bh_delete(acb->bh);
462b9f66d96SKevin Wolf     acb->common.cb(acb->common.opaque, acb->ret);
4638007429aSFam Zheng     qemu_aio_unref(acb);
464b9f66d96SKevin Wolf }
465b9f66d96SKevin Wolf 
4667c84b1b8SMarkus Armbruster static BlockAIOCB *inject_error(BlockDriverState *bs,
467097310b5SMarkus Armbruster     BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
468b9f66d96SKevin Wolf {
469b9f66d96SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
470571cd43eSPaolo Bonzini     int error = rule->options.inject.error;
471b9f66d96SKevin Wolf     struct BlkdebugAIOCB *acb;
472b9f66d96SKevin Wolf     QEMUBH *bh;
473a069e2f1SJohn Snow     bool immediately = rule->options.inject.immediately;
474b9f66d96SKevin Wolf 
475571cd43eSPaolo Bonzini     if (rule->options.inject.once) {
476a069e2f1SJohn Snow         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
477a069e2f1SJohn Snow         remove_rule(rule);
478b9f66d96SKevin Wolf     }
479b9f66d96SKevin Wolf 
480a069e2f1SJohn Snow     if (immediately) {
481b9f66d96SKevin Wolf         return NULL;
482b9f66d96SKevin Wolf     }
483b9f66d96SKevin Wolf 
484d7331bedSStefan Hajnoczi     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
485b9f66d96SKevin Wolf     acb->ret = -error;
486b9f66d96SKevin Wolf 
4877e1efdf0SStefan Hajnoczi     bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
488b9f66d96SKevin Wolf     acb->bh = bh;
489b9f66d96SKevin Wolf     qemu_bh_schedule(bh);
490b9f66d96SKevin Wolf 
491b666d239SKevin Wolf     return &acb->common;
492b9f66d96SKevin Wolf }
493b9f66d96SKevin Wolf 
4947c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
4956a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
496097310b5SMarkus Armbruster     BlockCompletionFunc *cb, void *opaque)
4976a143727SKevin Wolf {
4986a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
499e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
500e4780db4SPaolo Bonzini 
501e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
502e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
503e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
504e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
505e4780db4SPaolo Bonzini             break;
506e4780db4SPaolo Bonzini         }
507e4780db4SPaolo Bonzini     }
508b9f66d96SKevin Wolf 
509571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
510571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
511b9f66d96SKevin Wolf     }
512b9f66d96SKevin Wolf 
513*9a4f4c31SKevin Wolf     return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
514*9a4f4c31SKevin Wolf                           cb, opaque);
5156a143727SKevin Wolf }
5166a143727SKevin Wolf 
5177c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
5186a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
519097310b5SMarkus Armbruster     BlockCompletionFunc *cb, void *opaque)
5206a143727SKevin Wolf {
5216a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
522e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
523e4780db4SPaolo Bonzini 
524e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
525e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
526e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
527e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
528e4780db4SPaolo Bonzini             break;
529e4780db4SPaolo Bonzini         }
530e4780db4SPaolo Bonzini     }
531b9f66d96SKevin Wolf 
532571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
533571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
534b9f66d96SKevin Wolf     }
535b9f66d96SKevin Wolf 
536*9a4f4c31SKevin Wolf     return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
537*9a4f4c31SKevin Wolf                            cb, opaque);
5386a143727SKevin Wolf }
5396a143727SKevin Wolf 
5407c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
541097310b5SMarkus Armbruster     BlockCompletionFunc *cb, void *opaque)
5429e52c53bSPaolo Bonzini {
5439e52c53bSPaolo Bonzini     BDRVBlkdebugState *s = bs->opaque;
5449e52c53bSPaolo Bonzini     BlkdebugRule *rule = NULL;
5459e52c53bSPaolo Bonzini 
5469e52c53bSPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
5479e52c53bSPaolo Bonzini         if (rule->options.inject.sector == -1) {
5489e52c53bSPaolo Bonzini             break;
5499e52c53bSPaolo Bonzini         }
5509e52c53bSPaolo Bonzini     }
5519e52c53bSPaolo Bonzini 
5529e52c53bSPaolo Bonzini     if (rule && rule->options.inject.error) {
5539e52c53bSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
5549e52c53bSPaolo Bonzini     }
5559e52c53bSPaolo Bonzini 
556*9a4f4c31SKevin Wolf     return bdrv_aio_flush(bs->file->bs, cb, opaque);
5579e52c53bSPaolo Bonzini }
5589e52c53bSPaolo Bonzini 
5593c90c65dSKevin Wolf 
5606a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs)
5616a143727SKevin Wolf {
5626a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5638b9b0cc2SKevin Wolf     BlkdebugRule *rule, *next;
5648b9b0cc2SKevin Wolf     int i;
5658b9b0cc2SKevin Wolf 
5668b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
5678b9b0cc2SKevin Wolf         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
5689e35542bSKevin Wolf             remove_rule(rule);
5698b9b0cc2SKevin Wolf         }
5708b9b0cc2SKevin Wolf     }
5716a143727SKevin Wolf }
5726a143727SKevin Wolf 
5733c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
5743c90c65dSKevin Wolf {
5753c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5763c90c65dSKevin Wolf     BlkdebugSuspendedReq r;
5773c90c65dSKevin Wolf 
5783c90c65dSKevin Wolf     r = (BlkdebugSuspendedReq) {
5793c90c65dSKevin Wolf         .co         = qemu_coroutine_self(),
5803c90c65dSKevin Wolf         .tag        = g_strdup(rule->options.suspend.tag),
5813c90c65dSKevin Wolf     };
5823c90c65dSKevin Wolf 
5833c90c65dSKevin Wolf     remove_rule(rule);
5843c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
5853c90c65dSKevin Wolf 
5863c90c65dSKevin Wolf     printf("blkdebug: Suspended request '%s'\n", r.tag);
5873c90c65dSKevin Wolf     qemu_coroutine_yield();
5883c90c65dSKevin Wolf     printf("blkdebug: Resuming request '%s'\n", r.tag);
5893c90c65dSKevin Wolf 
5903c90c65dSKevin Wolf     QLIST_REMOVE(&r, next);
5913c90c65dSKevin Wolf     g_free(r.tag);
5923c90c65dSKevin Wolf }
5933c90c65dSKevin Wolf 
594571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
5958f96b5beSPaolo Bonzini     bool injected)
5968b9b0cc2SKevin Wolf {
5978b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5988b9b0cc2SKevin Wolf 
5998b9b0cc2SKevin Wolf     /* Only process rules for the current state */
6008f96b5beSPaolo Bonzini     if (rule->state && rule->state != s->state) {
601571cd43eSPaolo Bonzini         return injected;
6028b9b0cc2SKevin Wolf     }
6038b9b0cc2SKevin Wolf 
6048b9b0cc2SKevin Wolf     /* Take the action */
6058b9b0cc2SKevin Wolf     switch (rule->action) {
6068b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
607571cd43eSPaolo Bonzini         if (!injected) {
608571cd43eSPaolo Bonzini             QSIMPLEQ_INIT(&s->active_rules);
609571cd43eSPaolo Bonzini             injected = true;
610571cd43eSPaolo Bonzini         }
611571cd43eSPaolo Bonzini         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
6128b9b0cc2SKevin Wolf         break;
6138b9b0cc2SKevin Wolf 
6148b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
6158f96b5beSPaolo Bonzini         s->new_state = rule->options.set_state.new_state;
6168b9b0cc2SKevin Wolf         break;
6173c90c65dSKevin Wolf 
6183c90c65dSKevin Wolf     case ACTION_SUSPEND:
6193c90c65dSKevin Wolf         suspend_request(bs, rule);
6203c90c65dSKevin Wolf         break;
6218b9b0cc2SKevin Wolf     }
622571cd43eSPaolo Bonzini     return injected;
6238b9b0cc2SKevin Wolf }
6248b9b0cc2SKevin Wolf 
6258b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
6268b9b0cc2SKevin Wolf {
6278b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6283c90c65dSKevin Wolf     struct BlkdebugRule *rule, *next;
629571cd43eSPaolo Bonzini     bool injected;
6308b9b0cc2SKevin Wolf 
63195ee3914SBlue Swirl     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
6328b9b0cc2SKevin Wolf 
633571cd43eSPaolo Bonzini     injected = false;
6348f96b5beSPaolo Bonzini     s->new_state = s->state;
6353c90c65dSKevin Wolf     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
6368f96b5beSPaolo Bonzini         injected = process_rule(bs, rule, injected);
6378b9b0cc2SKevin Wolf     }
6388f96b5beSPaolo Bonzini     s->state = s->new_state;
6398b9b0cc2SKevin Wolf }
6408b9b0cc2SKevin Wolf 
6413c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
6423c90c65dSKevin Wolf                                      const char *tag)
6433c90c65dSKevin Wolf {
6443c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6453c90c65dSKevin Wolf     struct BlkdebugRule *rule;
6463c90c65dSKevin Wolf     BlkDebugEvent blkdebug_event;
6473c90c65dSKevin Wolf 
6483c90c65dSKevin Wolf     if (get_event_by_name(event, &blkdebug_event) < 0) {
6493c90c65dSKevin Wolf         return -ENOENT;
6503c90c65dSKevin Wolf     }
6513c90c65dSKevin Wolf 
6523c90c65dSKevin Wolf 
6533c90c65dSKevin Wolf     rule = g_malloc(sizeof(*rule));
6543c90c65dSKevin Wolf     *rule = (struct BlkdebugRule) {
6553c90c65dSKevin Wolf         .event  = blkdebug_event,
6563c90c65dSKevin Wolf         .action = ACTION_SUSPEND,
6573c90c65dSKevin Wolf         .state  = 0,
6583c90c65dSKevin Wolf         .options.suspend.tag = g_strdup(tag),
6593c90c65dSKevin Wolf     };
6603c90c65dSKevin Wolf 
6613c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
6623c90c65dSKevin Wolf 
6633c90c65dSKevin Wolf     return 0;
6643c90c65dSKevin Wolf }
6653c90c65dSKevin Wolf 
6663c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
6673c90c65dSKevin Wolf {
6683c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
669c547e564SFam Zheng     BlkdebugSuspendedReq *r, *next;
6703c90c65dSKevin Wolf 
671c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
6723c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
6733c90c65dSKevin Wolf             qemu_coroutine_enter(r->co, NULL);
6743c90c65dSKevin Wolf             return 0;
6753c90c65dSKevin Wolf         }
6763c90c65dSKevin Wolf     }
6773c90c65dSKevin Wolf     return -ENOENT;
6783c90c65dSKevin Wolf }
6793c90c65dSKevin Wolf 
6804cc70e93SFam Zheng static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
6814cc70e93SFam Zheng                                             const char *tag)
6824cc70e93SFam Zheng {
6834cc70e93SFam Zheng     BDRVBlkdebugState *s = bs->opaque;
684c547e564SFam Zheng     BlkdebugSuspendedReq *r, *r_next;
6854cc70e93SFam Zheng     BlkdebugRule *rule, *next;
6864cc70e93SFam Zheng     int i, ret = -ENOENT;
6874cc70e93SFam Zheng 
6884cc70e93SFam Zheng     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
6894cc70e93SFam Zheng         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
6904cc70e93SFam Zheng             if (rule->action == ACTION_SUSPEND &&
6914cc70e93SFam Zheng                 !strcmp(rule->options.suspend.tag, tag)) {
6924cc70e93SFam Zheng                 remove_rule(rule);
6934cc70e93SFam Zheng                 ret = 0;
6944cc70e93SFam Zheng             }
6954cc70e93SFam Zheng         }
6964cc70e93SFam Zheng     }
697c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
6984cc70e93SFam Zheng         if (!strcmp(r->tag, tag)) {
6994cc70e93SFam Zheng             qemu_coroutine_enter(r->co, NULL);
7004cc70e93SFam Zheng             ret = 0;
7014cc70e93SFam Zheng         }
7024cc70e93SFam Zheng     }
7034cc70e93SFam Zheng     return ret;
7044cc70e93SFam Zheng }
7053c90c65dSKevin Wolf 
7063c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
7073c90c65dSKevin Wolf {
7083c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
7093c90c65dSKevin Wolf     BlkdebugSuspendedReq *r;
7103c90c65dSKevin Wolf 
7113c90c65dSKevin Wolf     QLIST_FOREACH(r, &s->suspended_reqs, next) {
7123c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
7133c90c65dSKevin Wolf             return true;
7143c90c65dSKevin Wolf         }
7153c90c65dSKevin Wolf     }
7163c90c65dSKevin Wolf     return false;
7173c90c65dSKevin Wolf }
7183c90c65dSKevin Wolf 
719e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs)
720e1302255SPaolo Bonzini {
721*9a4f4c31SKevin Wolf     return bdrv_getlength(bs->file->bs);
722e1302255SPaolo Bonzini }
723e1302255SPaolo Bonzini 
7248eedfbd4SKevin Wolf static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
7258eedfbd4SKevin Wolf {
726*9a4f4c31SKevin Wolf     return bdrv_truncate(bs->file->bs, offset);
7278eedfbd4SKevin Wolf }
7288eedfbd4SKevin Wolf 
7292c31b04cSMax Reitz static void blkdebug_refresh_filename(BlockDriverState *bs)
7302c31b04cSMax Reitz {
7312c31b04cSMax Reitz     QDict *opts;
7328779441bSMax Reitz     const QDictEntry *e;
7338779441bSMax Reitz     bool force_json = false;
7342c31b04cSMax Reitz 
7358779441bSMax Reitz     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
7368779441bSMax Reitz         if (strcmp(qdict_entry_key(e), "config") &&
7378779441bSMax Reitz             strcmp(qdict_entry_key(e), "x-image") &&
7388779441bSMax Reitz             strcmp(qdict_entry_key(e), "image") &&
7398779441bSMax Reitz             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
7408779441bSMax Reitz         {
7418779441bSMax Reitz             force_json = true;
7428779441bSMax Reitz             break;
7438779441bSMax Reitz         }
7448779441bSMax Reitz     }
7458779441bSMax Reitz 
746*9a4f4c31SKevin Wolf     if (force_json && !bs->file->bs->full_open_options) {
7472c31b04cSMax Reitz         /* The config file cannot be recreated, so creating a plain filename
7482c31b04cSMax Reitz          * is impossible */
7492c31b04cSMax Reitz         return;
7502c31b04cSMax Reitz     }
7512c31b04cSMax Reitz 
752*9a4f4c31SKevin Wolf     if (!force_json && bs->file->bs->exact_filename[0]) {
7538779441bSMax Reitz         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
7548779441bSMax Reitz                  "blkdebug:%s:%s",
7558779441bSMax Reitz                  qdict_get_try_str(bs->options, "config") ?: "",
756*9a4f4c31SKevin Wolf                  bs->file->bs->exact_filename);
7578779441bSMax Reitz     }
7588779441bSMax Reitz 
7592c31b04cSMax Reitz     opts = qdict_new();
7602c31b04cSMax Reitz     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
7612c31b04cSMax Reitz 
762*9a4f4c31SKevin Wolf     QINCREF(bs->file->bs->full_open_options);
763*9a4f4c31SKevin Wolf     qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
7642c31b04cSMax Reitz 
7658779441bSMax Reitz     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
7668779441bSMax Reitz         if (strcmp(qdict_entry_key(e), "x-image") &&
7678779441bSMax Reitz             strcmp(qdict_entry_key(e), "image") &&
7688779441bSMax Reitz             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
7698779441bSMax Reitz         {
7708779441bSMax Reitz             qobject_incref(qdict_entry_value(e));
7718779441bSMax Reitz             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
7722c31b04cSMax Reitz         }
7732c31b04cSMax Reitz     }
7742c31b04cSMax Reitz 
7752c31b04cSMax Reitz     bs->full_open_options = opts;
7762c31b04cSMax Reitz }
7772c31b04cSMax Reitz 
7786a143727SKevin Wolf static BlockDriver bdrv_blkdebug = {
7796a143727SKevin Wolf     .format_name            = "blkdebug",
7806a143727SKevin Wolf     .protocol_name          = "blkdebug",
7816a143727SKevin Wolf     .instance_size          = sizeof(BDRVBlkdebugState),
7826a143727SKevin Wolf 
783f4681212SKevin Wolf     .bdrv_parse_filename    = blkdebug_parse_filename,
78466f82ceeSKevin Wolf     .bdrv_file_open         = blkdebug_open,
7856a143727SKevin Wolf     .bdrv_close             = blkdebug_close,
786e1302255SPaolo Bonzini     .bdrv_getlength         = blkdebug_getlength,
7878eedfbd4SKevin Wolf     .bdrv_truncate          = blkdebug_truncate,
7882c31b04cSMax Reitz     .bdrv_refresh_filename  = blkdebug_refresh_filename,
7896a143727SKevin Wolf 
7906a143727SKevin Wolf     .bdrv_aio_readv         = blkdebug_aio_readv,
7916a143727SKevin Wolf     .bdrv_aio_writev        = blkdebug_aio_writev,
7929e52c53bSPaolo Bonzini     .bdrv_aio_flush         = blkdebug_aio_flush,
7938b9b0cc2SKevin Wolf 
7948b9b0cc2SKevin Wolf     .bdrv_debug_event           = blkdebug_debug_event,
7953c90c65dSKevin Wolf     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
7964cc70e93SFam Zheng     .bdrv_debug_remove_breakpoint
7974cc70e93SFam Zheng                                 = blkdebug_debug_remove_breakpoint,
7983c90c65dSKevin Wolf     .bdrv_debug_resume          = blkdebug_debug_resume,
7993c90c65dSKevin Wolf     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
8006a143727SKevin Wolf };
8016a143727SKevin Wolf 
8026a143727SKevin Wolf static void bdrv_blkdebug_init(void)
8036a143727SKevin Wolf {
8046a143727SKevin Wolf     bdrv_register(&bdrv_blkdebug);
8056a143727SKevin Wolf }
8066a143727SKevin Wolf 
8076a143727SKevin Wolf block_init(bdrv_blkdebug_init);
808