xref: /qemu/block/blkdebug.c (revision f3930ed0)
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 */
430f67503e5SMax Reitz     assert(bs->file == NULL);
4314373593dSMax Reitz     ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
432*f3930ed0SKevin Wolf                           bs, &child_file, false, &local_err);
433f4681212SKevin Wolf     if (ret < 0) {
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:
452eaf944a4SKevin Wolf     bdrv_unref(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 
513368e8dd1SPaolo Bonzini     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
5146a143727SKevin Wolf }
5156a143727SKevin Wolf 
5167c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
5176a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
518097310b5SMarkus Armbruster     BlockCompletionFunc *cb, void *opaque)
5196a143727SKevin Wolf {
5206a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
521e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
522e4780db4SPaolo Bonzini 
523e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
524e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
525e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
526e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
527e4780db4SPaolo Bonzini             break;
528e4780db4SPaolo Bonzini         }
529e4780db4SPaolo Bonzini     }
530b9f66d96SKevin Wolf 
531571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
532571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
533b9f66d96SKevin Wolf     }
534b9f66d96SKevin Wolf 
535368e8dd1SPaolo Bonzini     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
5366a143727SKevin Wolf }
5376a143727SKevin Wolf 
5387c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
539097310b5SMarkus Armbruster     BlockCompletionFunc *cb, void *opaque)
5409e52c53bSPaolo Bonzini {
5419e52c53bSPaolo Bonzini     BDRVBlkdebugState *s = bs->opaque;
5429e52c53bSPaolo Bonzini     BlkdebugRule *rule = NULL;
5439e52c53bSPaolo Bonzini 
5449e52c53bSPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
5459e52c53bSPaolo Bonzini         if (rule->options.inject.sector == -1) {
5469e52c53bSPaolo Bonzini             break;
5479e52c53bSPaolo Bonzini         }
5489e52c53bSPaolo Bonzini     }
5499e52c53bSPaolo Bonzini 
5509e52c53bSPaolo Bonzini     if (rule && rule->options.inject.error) {
5519e52c53bSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
5529e52c53bSPaolo Bonzini     }
5539e52c53bSPaolo Bonzini 
5549e52c53bSPaolo Bonzini     return bdrv_aio_flush(bs->file, cb, opaque);
5559e52c53bSPaolo Bonzini }
5569e52c53bSPaolo Bonzini 
5573c90c65dSKevin Wolf 
5586a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs)
5596a143727SKevin Wolf {
5606a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5618b9b0cc2SKevin Wolf     BlkdebugRule *rule, *next;
5628b9b0cc2SKevin Wolf     int i;
5638b9b0cc2SKevin Wolf 
5648b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
5658b9b0cc2SKevin Wolf         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
5669e35542bSKevin Wolf             remove_rule(rule);
5678b9b0cc2SKevin Wolf         }
5688b9b0cc2SKevin Wolf     }
5696a143727SKevin Wolf }
5706a143727SKevin Wolf 
5713c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
5723c90c65dSKevin Wolf {
5733c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5743c90c65dSKevin Wolf     BlkdebugSuspendedReq r;
5753c90c65dSKevin Wolf 
5763c90c65dSKevin Wolf     r = (BlkdebugSuspendedReq) {
5773c90c65dSKevin Wolf         .co         = qemu_coroutine_self(),
5783c90c65dSKevin Wolf         .tag        = g_strdup(rule->options.suspend.tag),
5793c90c65dSKevin Wolf     };
5803c90c65dSKevin Wolf 
5813c90c65dSKevin Wolf     remove_rule(rule);
5823c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
5833c90c65dSKevin Wolf 
5843c90c65dSKevin Wolf     printf("blkdebug: Suspended request '%s'\n", r.tag);
5853c90c65dSKevin Wolf     qemu_coroutine_yield();
5863c90c65dSKevin Wolf     printf("blkdebug: Resuming request '%s'\n", r.tag);
5873c90c65dSKevin Wolf 
5883c90c65dSKevin Wolf     QLIST_REMOVE(&r, next);
5893c90c65dSKevin Wolf     g_free(r.tag);
5903c90c65dSKevin Wolf }
5913c90c65dSKevin Wolf 
592571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
5938f96b5beSPaolo Bonzini     bool injected)
5948b9b0cc2SKevin Wolf {
5958b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5968b9b0cc2SKevin Wolf 
5978b9b0cc2SKevin Wolf     /* Only process rules for the current state */
5988f96b5beSPaolo Bonzini     if (rule->state && rule->state != s->state) {
599571cd43eSPaolo Bonzini         return injected;
6008b9b0cc2SKevin Wolf     }
6018b9b0cc2SKevin Wolf 
6028b9b0cc2SKevin Wolf     /* Take the action */
6038b9b0cc2SKevin Wolf     switch (rule->action) {
6048b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
605571cd43eSPaolo Bonzini         if (!injected) {
606571cd43eSPaolo Bonzini             QSIMPLEQ_INIT(&s->active_rules);
607571cd43eSPaolo Bonzini             injected = true;
608571cd43eSPaolo Bonzini         }
609571cd43eSPaolo Bonzini         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
6108b9b0cc2SKevin Wolf         break;
6118b9b0cc2SKevin Wolf 
6128b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
6138f96b5beSPaolo Bonzini         s->new_state = rule->options.set_state.new_state;
6148b9b0cc2SKevin Wolf         break;
6153c90c65dSKevin Wolf 
6163c90c65dSKevin Wolf     case ACTION_SUSPEND:
6173c90c65dSKevin Wolf         suspend_request(bs, rule);
6183c90c65dSKevin Wolf         break;
6198b9b0cc2SKevin Wolf     }
620571cd43eSPaolo Bonzini     return injected;
6218b9b0cc2SKevin Wolf }
6228b9b0cc2SKevin Wolf 
6238b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
6248b9b0cc2SKevin Wolf {
6258b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6263c90c65dSKevin Wolf     struct BlkdebugRule *rule, *next;
627571cd43eSPaolo Bonzini     bool injected;
6288b9b0cc2SKevin Wolf 
62995ee3914SBlue Swirl     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
6308b9b0cc2SKevin Wolf 
631571cd43eSPaolo Bonzini     injected = false;
6328f96b5beSPaolo Bonzini     s->new_state = s->state;
6333c90c65dSKevin Wolf     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
6348f96b5beSPaolo Bonzini         injected = process_rule(bs, rule, injected);
6358b9b0cc2SKevin Wolf     }
6368f96b5beSPaolo Bonzini     s->state = s->new_state;
6378b9b0cc2SKevin Wolf }
6388b9b0cc2SKevin Wolf 
6393c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
6403c90c65dSKevin Wolf                                      const char *tag)
6413c90c65dSKevin Wolf {
6423c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6433c90c65dSKevin Wolf     struct BlkdebugRule *rule;
6443c90c65dSKevin Wolf     BlkDebugEvent blkdebug_event;
6453c90c65dSKevin Wolf 
6463c90c65dSKevin Wolf     if (get_event_by_name(event, &blkdebug_event) < 0) {
6473c90c65dSKevin Wolf         return -ENOENT;
6483c90c65dSKevin Wolf     }
6493c90c65dSKevin Wolf 
6503c90c65dSKevin Wolf 
6513c90c65dSKevin Wolf     rule = g_malloc(sizeof(*rule));
6523c90c65dSKevin Wolf     *rule = (struct BlkdebugRule) {
6533c90c65dSKevin Wolf         .event  = blkdebug_event,
6543c90c65dSKevin Wolf         .action = ACTION_SUSPEND,
6553c90c65dSKevin Wolf         .state  = 0,
6563c90c65dSKevin Wolf         .options.suspend.tag = g_strdup(tag),
6573c90c65dSKevin Wolf     };
6583c90c65dSKevin Wolf 
6593c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
6603c90c65dSKevin Wolf 
6613c90c65dSKevin Wolf     return 0;
6623c90c65dSKevin Wolf }
6633c90c65dSKevin Wolf 
6643c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
6653c90c65dSKevin Wolf {
6663c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
667c547e564SFam Zheng     BlkdebugSuspendedReq *r, *next;
6683c90c65dSKevin Wolf 
669c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
6703c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
6713c90c65dSKevin Wolf             qemu_coroutine_enter(r->co, NULL);
6723c90c65dSKevin Wolf             return 0;
6733c90c65dSKevin Wolf         }
6743c90c65dSKevin Wolf     }
6753c90c65dSKevin Wolf     return -ENOENT;
6763c90c65dSKevin Wolf }
6773c90c65dSKevin Wolf 
6784cc70e93SFam Zheng static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
6794cc70e93SFam Zheng                                             const char *tag)
6804cc70e93SFam Zheng {
6814cc70e93SFam Zheng     BDRVBlkdebugState *s = bs->opaque;
682c547e564SFam Zheng     BlkdebugSuspendedReq *r, *r_next;
6834cc70e93SFam Zheng     BlkdebugRule *rule, *next;
6844cc70e93SFam Zheng     int i, ret = -ENOENT;
6854cc70e93SFam Zheng 
6864cc70e93SFam Zheng     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
6874cc70e93SFam Zheng         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
6884cc70e93SFam Zheng             if (rule->action == ACTION_SUSPEND &&
6894cc70e93SFam Zheng                 !strcmp(rule->options.suspend.tag, tag)) {
6904cc70e93SFam Zheng                 remove_rule(rule);
6914cc70e93SFam Zheng                 ret = 0;
6924cc70e93SFam Zheng             }
6934cc70e93SFam Zheng         }
6944cc70e93SFam Zheng     }
695c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
6964cc70e93SFam Zheng         if (!strcmp(r->tag, tag)) {
6974cc70e93SFam Zheng             qemu_coroutine_enter(r->co, NULL);
6984cc70e93SFam Zheng             ret = 0;
6994cc70e93SFam Zheng         }
7004cc70e93SFam Zheng     }
7014cc70e93SFam Zheng     return ret;
7024cc70e93SFam Zheng }
7033c90c65dSKevin Wolf 
7043c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
7053c90c65dSKevin Wolf {
7063c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
7073c90c65dSKevin Wolf     BlkdebugSuspendedReq *r;
7083c90c65dSKevin Wolf 
7093c90c65dSKevin Wolf     QLIST_FOREACH(r, &s->suspended_reqs, next) {
7103c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
7113c90c65dSKevin Wolf             return true;
7123c90c65dSKevin Wolf         }
7133c90c65dSKevin Wolf     }
7143c90c65dSKevin Wolf     return false;
7153c90c65dSKevin Wolf }
7163c90c65dSKevin Wolf 
717e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs)
718e1302255SPaolo Bonzini {
719e1302255SPaolo Bonzini     return bdrv_getlength(bs->file);
720e1302255SPaolo Bonzini }
721e1302255SPaolo Bonzini 
7228eedfbd4SKevin Wolf static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
7238eedfbd4SKevin Wolf {
7248eedfbd4SKevin Wolf     return bdrv_truncate(bs->file, offset);
7258eedfbd4SKevin Wolf }
7268eedfbd4SKevin Wolf 
7272c31b04cSMax Reitz static void blkdebug_refresh_filename(BlockDriverState *bs)
7282c31b04cSMax Reitz {
7292c31b04cSMax Reitz     QDict *opts;
7308779441bSMax Reitz     const QDictEntry *e;
7318779441bSMax Reitz     bool force_json = false;
7322c31b04cSMax Reitz 
7338779441bSMax Reitz     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
7348779441bSMax Reitz         if (strcmp(qdict_entry_key(e), "config") &&
7358779441bSMax Reitz             strcmp(qdict_entry_key(e), "x-image") &&
7368779441bSMax Reitz             strcmp(qdict_entry_key(e), "image") &&
7378779441bSMax Reitz             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
7388779441bSMax Reitz         {
7398779441bSMax Reitz             force_json = true;
7408779441bSMax Reitz             break;
7418779441bSMax Reitz         }
7428779441bSMax Reitz     }
7438779441bSMax Reitz 
7448779441bSMax Reitz     if (force_json && !bs->file->full_open_options) {
7452c31b04cSMax Reitz         /* The config file cannot be recreated, so creating a plain filename
7462c31b04cSMax Reitz          * is impossible */
7472c31b04cSMax Reitz         return;
7482c31b04cSMax Reitz     }
7492c31b04cSMax Reitz 
7508779441bSMax Reitz     if (!force_json && bs->file->exact_filename[0]) {
7518779441bSMax Reitz         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
7528779441bSMax Reitz                  "blkdebug:%s:%s",
7538779441bSMax Reitz                  qdict_get_try_str(bs->options, "config") ?: "",
7548779441bSMax Reitz                  bs->file->exact_filename);
7558779441bSMax Reitz     }
7568779441bSMax Reitz 
7572c31b04cSMax Reitz     opts = qdict_new();
7582c31b04cSMax Reitz     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
7592c31b04cSMax Reitz 
7602c31b04cSMax Reitz     QINCREF(bs->file->full_open_options);
7612c31b04cSMax Reitz     qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
7622c31b04cSMax Reitz 
7638779441bSMax Reitz     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
7648779441bSMax Reitz         if (strcmp(qdict_entry_key(e), "x-image") &&
7658779441bSMax Reitz             strcmp(qdict_entry_key(e), "image") &&
7668779441bSMax Reitz             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
7678779441bSMax Reitz         {
7688779441bSMax Reitz             qobject_incref(qdict_entry_value(e));
7698779441bSMax Reitz             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
7702c31b04cSMax Reitz         }
7712c31b04cSMax Reitz     }
7722c31b04cSMax Reitz 
7732c31b04cSMax Reitz     bs->full_open_options = opts;
7742c31b04cSMax Reitz }
7752c31b04cSMax Reitz 
7766a143727SKevin Wolf static BlockDriver bdrv_blkdebug = {
7776a143727SKevin Wolf     .format_name            = "blkdebug",
7786a143727SKevin Wolf     .protocol_name          = "blkdebug",
7796a143727SKevin Wolf     .instance_size          = sizeof(BDRVBlkdebugState),
7806a143727SKevin Wolf 
781f4681212SKevin Wolf     .bdrv_parse_filename    = blkdebug_parse_filename,
78266f82ceeSKevin Wolf     .bdrv_file_open         = blkdebug_open,
7836a143727SKevin Wolf     .bdrv_close             = blkdebug_close,
784e1302255SPaolo Bonzini     .bdrv_getlength         = blkdebug_getlength,
7858eedfbd4SKevin Wolf     .bdrv_truncate          = blkdebug_truncate,
7862c31b04cSMax Reitz     .bdrv_refresh_filename  = blkdebug_refresh_filename,
7876a143727SKevin Wolf 
7886a143727SKevin Wolf     .bdrv_aio_readv         = blkdebug_aio_readv,
7896a143727SKevin Wolf     .bdrv_aio_writev        = blkdebug_aio_writev,
7909e52c53bSPaolo Bonzini     .bdrv_aio_flush         = blkdebug_aio_flush,
7918b9b0cc2SKevin Wolf 
7928b9b0cc2SKevin Wolf     .bdrv_debug_event           = blkdebug_debug_event,
7933c90c65dSKevin Wolf     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
7944cc70e93SFam Zheng     .bdrv_debug_remove_breakpoint
7954cc70e93SFam Zheng                                 = blkdebug_debug_remove_breakpoint,
7963c90c65dSKevin Wolf     .bdrv_debug_resume          = blkdebug_debug_resume,
7973c90c65dSKevin Wolf     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
7986a143727SKevin Wolf };
7996a143727SKevin Wolf 
8006a143727SKevin Wolf static void bdrv_blkdebug_init(void)
8016a143727SKevin Wolf {
8026a143727SKevin Wolf     bdrv_register(&bdrv_blkdebug);
8036a143727SKevin Wolf }
8046a143727SKevin Wolf 
8056a143727SKevin Wolf block_init(bdrv_blkdebug_init);
806