xref: /qemu/block/blkdebug.c (revision 7c84b1b8)
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 {
44*7c84b1b8SMarkus 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",
1988b9b0cc2SKevin Wolf };
1998b9b0cc2SKevin Wolf 
2008b9b0cc2SKevin Wolf static int get_event_by_name(const char *name, BlkDebugEvent *event)
2018b9b0cc2SKevin Wolf {
2028b9b0cc2SKevin Wolf     int i;
2038b9b0cc2SKevin Wolf 
2048b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
2058b9b0cc2SKevin Wolf         if (!strcmp(event_names[i], name)) {
2068b9b0cc2SKevin Wolf             *event = i;
2078b9b0cc2SKevin Wolf             return 0;
2088b9b0cc2SKevin Wolf         }
2098b9b0cc2SKevin Wolf     }
2108b9b0cc2SKevin Wolf 
2118b9b0cc2SKevin Wolf     return -1;
2128b9b0cc2SKevin Wolf }
2138b9b0cc2SKevin Wolf 
2148b9b0cc2SKevin Wolf struct add_rule_data {
2158b9b0cc2SKevin Wolf     BDRVBlkdebugState *s;
2168b9b0cc2SKevin Wolf     int action;
217d4362d64SStefan Hajnoczi     Error **errp;
2188b9b0cc2SKevin Wolf };
2198b9b0cc2SKevin Wolf 
2208b9b0cc2SKevin Wolf static int add_rule(QemuOpts *opts, void *opaque)
2218b9b0cc2SKevin Wolf {
2228b9b0cc2SKevin Wolf     struct add_rule_data *d = opaque;
2238b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = d->s;
2248b9b0cc2SKevin Wolf     const char* event_name;
2258b9b0cc2SKevin Wolf     BlkDebugEvent event;
2268b9b0cc2SKevin Wolf     struct BlkdebugRule *rule;
2278b9b0cc2SKevin Wolf 
2288b9b0cc2SKevin Wolf     /* Find the right event for the rule */
2298b9b0cc2SKevin Wolf     event_name = qemu_opt_get(opts, "event");
230d4362d64SStefan Hajnoczi     if (!event_name) {
231d4362d64SStefan Hajnoczi         error_setg(d->errp, "Missing event name for rule");
232d4362d64SStefan Hajnoczi         return -1;
233d4362d64SStefan Hajnoczi     } else if (get_event_by_name(event_name, &event) < 0) {
234d4362d64SStefan Hajnoczi         error_setg(d->errp, "Invalid event name \"%s\"", event_name);
2358b9b0cc2SKevin Wolf         return -1;
2368b9b0cc2SKevin Wolf     }
2378b9b0cc2SKevin Wolf 
2388b9b0cc2SKevin Wolf     /* Set attributes common for all actions */
2397267c094SAnthony Liguori     rule = g_malloc0(sizeof(*rule));
2408b9b0cc2SKevin Wolf     *rule = (struct BlkdebugRule) {
2418b9b0cc2SKevin Wolf         .event  = event,
2428b9b0cc2SKevin Wolf         .action = d->action,
2438b9b0cc2SKevin Wolf         .state  = qemu_opt_get_number(opts, "state", 0),
2448b9b0cc2SKevin Wolf     };
2458b9b0cc2SKevin Wolf 
2468b9b0cc2SKevin Wolf     /* Parse action-specific options */
2478b9b0cc2SKevin Wolf     switch (d->action) {
2488b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
2498b9b0cc2SKevin Wolf         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
2508b9b0cc2SKevin Wolf         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
2518b9b0cc2SKevin Wolf         rule->options.inject.immediately =
2528b9b0cc2SKevin Wolf             qemu_opt_get_bool(opts, "immediately", 0);
253e4780db4SPaolo Bonzini         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
2548b9b0cc2SKevin Wolf         break;
2558b9b0cc2SKevin Wolf 
2568b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
2578b9b0cc2SKevin Wolf         rule->options.set_state.new_state =
2588b9b0cc2SKevin Wolf             qemu_opt_get_number(opts, "new_state", 0);
2598b9b0cc2SKevin Wolf         break;
2603c90c65dSKevin Wolf 
2613c90c65dSKevin Wolf     case ACTION_SUSPEND:
2623c90c65dSKevin Wolf         rule->options.suspend.tag =
2633c90c65dSKevin Wolf             g_strdup(qemu_opt_get(opts, "tag"));
2643c90c65dSKevin Wolf         break;
2658b9b0cc2SKevin Wolf     };
2668b9b0cc2SKevin Wolf 
2678b9b0cc2SKevin Wolf     /* Add the rule */
2688b9b0cc2SKevin Wolf     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
2698b9b0cc2SKevin Wolf 
2708b9b0cc2SKevin Wolf     return 0;
2718b9b0cc2SKevin Wolf }
2728b9b0cc2SKevin Wolf 
2739e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule)
2749e35542bSKevin Wolf {
2759e35542bSKevin Wolf     switch (rule->action) {
2769e35542bSKevin Wolf     case ACTION_INJECT_ERROR:
2779e35542bSKevin Wolf     case ACTION_SET_STATE:
2789e35542bSKevin Wolf         break;
2793c90c65dSKevin Wolf     case ACTION_SUSPEND:
2803c90c65dSKevin Wolf         g_free(rule->options.suspend.tag);
2813c90c65dSKevin Wolf         break;
2829e35542bSKevin Wolf     }
2839e35542bSKevin Wolf 
2849e35542bSKevin Wolf     QLIST_REMOVE(rule, next);
2859e35542bSKevin Wolf     g_free(rule);
2869e35542bSKevin Wolf }
2879e35542bSKevin Wolf 
28889f2b21eSMax Reitz static int read_config(BDRVBlkdebugState *s, const char *filename,
28989f2b21eSMax Reitz                        QDict *options, Error **errp)
2908b9b0cc2SKevin Wolf {
29185a040e5SMax Reitz     FILE *f = NULL;
2928b9b0cc2SKevin Wolf     int ret;
2938b9b0cc2SKevin Wolf     struct add_rule_data d;
29489f2b21eSMax Reitz     Error *local_err = NULL;
2958b9b0cc2SKevin Wolf 
29685a040e5SMax Reitz     if (filename) {
2978b9b0cc2SKevin Wolf         f = fopen(filename, "r");
2988b9b0cc2SKevin Wolf         if (f == NULL) {
299466b49f2SMax Reitz             error_setg_errno(errp, errno, "Could not read blkdebug config file");
3008b9b0cc2SKevin Wolf             return -errno;
3018b9b0cc2SKevin Wolf         }
3028b9b0cc2SKevin Wolf 
3038b9b0cc2SKevin Wolf         ret = qemu_config_parse(f, config_groups, filename);
3048b9b0cc2SKevin Wolf         if (ret < 0) {
305466b49f2SMax Reitz             error_setg(errp, "Could not parse blkdebug config file");
306466b49f2SMax Reitz             ret = -EINVAL;
3078b9b0cc2SKevin Wolf             goto fail;
3088b9b0cc2SKevin Wolf         }
30985a040e5SMax Reitz     }
3108b9b0cc2SKevin Wolf 
31189f2b21eSMax Reitz     qemu_config_parse_qdict(options, config_groups, &local_err);
31284d18f06SMarkus Armbruster     if (local_err) {
31389f2b21eSMax Reitz         error_propagate(errp, local_err);
31489f2b21eSMax Reitz         ret = -EINVAL;
31589f2b21eSMax Reitz         goto fail;
31689f2b21eSMax Reitz     }
31789f2b21eSMax Reitz 
3188b9b0cc2SKevin Wolf     d.s = s;
3198b9b0cc2SKevin Wolf     d.action = ACTION_INJECT_ERROR;
320d4362d64SStefan Hajnoczi     d.errp = &local_err;
321d4362d64SStefan Hajnoczi     qemu_opts_foreach(&inject_error_opts, add_rule, &d, 1);
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;
329d4362d64SStefan Hajnoczi     qemu_opts_foreach(&set_state_opts, add_rule, &d, 1);
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",
432f7d9fd8cSMax Reitz                           flags | BDRV_O_PROTOCOL, 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 
466*7c84b1b8SMarkus Armbruster static BlockAIOCB *inject_error(BlockDriverState *bs,
467571cd43eSPaolo Bonzini     BlockDriverCompletionFunc *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;
473b9f66d96SKevin Wolf 
474571cd43eSPaolo Bonzini     if (rule->options.inject.once) {
475571cd43eSPaolo Bonzini         QSIMPLEQ_INIT(&s->active_rules);
476b9f66d96SKevin Wolf     }
477b9f66d96SKevin Wolf 
478571cd43eSPaolo Bonzini     if (rule->options.inject.immediately) {
479b9f66d96SKevin Wolf         return NULL;
480b9f66d96SKevin Wolf     }
481b9f66d96SKevin Wolf 
482d7331bedSStefan Hajnoczi     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
483b9f66d96SKevin Wolf     acb->ret = -error;
484b9f66d96SKevin Wolf 
4857e1efdf0SStefan Hajnoczi     bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
486b9f66d96SKevin Wolf     acb->bh = bh;
487b9f66d96SKevin Wolf     qemu_bh_schedule(bh);
488b9f66d96SKevin Wolf 
489b666d239SKevin Wolf     return &acb->common;
490b9f66d96SKevin Wolf }
491b9f66d96SKevin Wolf 
492*7c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
4936a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
4946a143727SKevin Wolf     BlockDriverCompletionFunc *cb, void *opaque)
4956a143727SKevin Wolf {
4966a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
497e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
498e4780db4SPaolo Bonzini 
499e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
500e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
501e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
502e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
503e4780db4SPaolo Bonzini             break;
504e4780db4SPaolo Bonzini         }
505e4780db4SPaolo Bonzini     }
506b9f66d96SKevin Wolf 
507571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
508571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
509b9f66d96SKevin Wolf     }
510b9f66d96SKevin Wolf 
511368e8dd1SPaolo Bonzini     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
5126a143727SKevin Wolf }
5136a143727SKevin Wolf 
514*7c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
5156a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
5166a143727SKevin Wolf     BlockDriverCompletionFunc *cb, void *opaque)
5176a143727SKevin Wolf {
5186a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
519e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
520e4780db4SPaolo Bonzini 
521e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
522e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
523e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
524e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
525e4780db4SPaolo Bonzini             break;
526e4780db4SPaolo Bonzini         }
527e4780db4SPaolo Bonzini     }
528b9f66d96SKevin Wolf 
529571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
530571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
531b9f66d96SKevin Wolf     }
532b9f66d96SKevin Wolf 
533368e8dd1SPaolo Bonzini     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
5346a143727SKevin Wolf }
5356a143727SKevin Wolf 
536*7c84b1b8SMarkus Armbruster static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
5379e52c53bSPaolo Bonzini     BlockDriverCompletionFunc *cb, void *opaque)
5389e52c53bSPaolo Bonzini {
5399e52c53bSPaolo Bonzini     BDRVBlkdebugState *s = bs->opaque;
5409e52c53bSPaolo Bonzini     BlkdebugRule *rule = NULL;
5419e52c53bSPaolo Bonzini 
5429e52c53bSPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
5439e52c53bSPaolo Bonzini         if (rule->options.inject.sector == -1) {
5449e52c53bSPaolo Bonzini             break;
5459e52c53bSPaolo Bonzini         }
5469e52c53bSPaolo Bonzini     }
5479e52c53bSPaolo Bonzini 
5489e52c53bSPaolo Bonzini     if (rule && rule->options.inject.error) {
5499e52c53bSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
5509e52c53bSPaolo Bonzini     }
5519e52c53bSPaolo Bonzini 
5529e52c53bSPaolo Bonzini     return bdrv_aio_flush(bs->file, cb, opaque);
5539e52c53bSPaolo Bonzini }
5549e52c53bSPaolo Bonzini 
5553c90c65dSKevin Wolf 
5566a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs)
5576a143727SKevin Wolf {
5586a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5598b9b0cc2SKevin Wolf     BlkdebugRule *rule, *next;
5608b9b0cc2SKevin Wolf     int i;
5618b9b0cc2SKevin Wolf 
5628b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
5638b9b0cc2SKevin Wolf         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
5649e35542bSKevin Wolf             remove_rule(rule);
5658b9b0cc2SKevin Wolf         }
5668b9b0cc2SKevin Wolf     }
5676a143727SKevin Wolf }
5686a143727SKevin Wolf 
5693c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
5703c90c65dSKevin Wolf {
5713c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5723c90c65dSKevin Wolf     BlkdebugSuspendedReq r;
5733c90c65dSKevin Wolf 
5743c90c65dSKevin Wolf     r = (BlkdebugSuspendedReq) {
5753c90c65dSKevin Wolf         .co         = qemu_coroutine_self(),
5763c90c65dSKevin Wolf         .tag        = g_strdup(rule->options.suspend.tag),
5773c90c65dSKevin Wolf     };
5783c90c65dSKevin Wolf 
5793c90c65dSKevin Wolf     remove_rule(rule);
5803c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
5813c90c65dSKevin Wolf 
5823c90c65dSKevin Wolf     printf("blkdebug: Suspended request '%s'\n", r.tag);
5833c90c65dSKevin Wolf     qemu_coroutine_yield();
5843c90c65dSKevin Wolf     printf("blkdebug: Resuming request '%s'\n", r.tag);
5853c90c65dSKevin Wolf 
5863c90c65dSKevin Wolf     QLIST_REMOVE(&r, next);
5873c90c65dSKevin Wolf     g_free(r.tag);
5883c90c65dSKevin Wolf }
5893c90c65dSKevin Wolf 
590571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
5918f96b5beSPaolo Bonzini     bool injected)
5928b9b0cc2SKevin Wolf {
5938b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5948b9b0cc2SKevin Wolf 
5958b9b0cc2SKevin Wolf     /* Only process rules for the current state */
5968f96b5beSPaolo Bonzini     if (rule->state && rule->state != s->state) {
597571cd43eSPaolo Bonzini         return injected;
5988b9b0cc2SKevin Wolf     }
5998b9b0cc2SKevin Wolf 
6008b9b0cc2SKevin Wolf     /* Take the action */
6018b9b0cc2SKevin Wolf     switch (rule->action) {
6028b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
603571cd43eSPaolo Bonzini         if (!injected) {
604571cd43eSPaolo Bonzini             QSIMPLEQ_INIT(&s->active_rules);
605571cd43eSPaolo Bonzini             injected = true;
606571cd43eSPaolo Bonzini         }
607571cd43eSPaolo Bonzini         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
6088b9b0cc2SKevin Wolf         break;
6098b9b0cc2SKevin Wolf 
6108b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
6118f96b5beSPaolo Bonzini         s->new_state = rule->options.set_state.new_state;
6128b9b0cc2SKevin Wolf         break;
6133c90c65dSKevin Wolf 
6143c90c65dSKevin Wolf     case ACTION_SUSPEND:
6153c90c65dSKevin Wolf         suspend_request(bs, rule);
6163c90c65dSKevin Wolf         break;
6178b9b0cc2SKevin Wolf     }
618571cd43eSPaolo Bonzini     return injected;
6198b9b0cc2SKevin Wolf }
6208b9b0cc2SKevin Wolf 
6218b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
6228b9b0cc2SKevin Wolf {
6238b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6243c90c65dSKevin Wolf     struct BlkdebugRule *rule, *next;
625571cd43eSPaolo Bonzini     bool injected;
6268b9b0cc2SKevin Wolf 
62795ee3914SBlue Swirl     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
6288b9b0cc2SKevin Wolf 
629571cd43eSPaolo Bonzini     injected = false;
6308f96b5beSPaolo Bonzini     s->new_state = s->state;
6313c90c65dSKevin Wolf     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
6328f96b5beSPaolo Bonzini         injected = process_rule(bs, rule, injected);
6338b9b0cc2SKevin Wolf     }
6348f96b5beSPaolo Bonzini     s->state = s->new_state;
6358b9b0cc2SKevin Wolf }
6368b9b0cc2SKevin Wolf 
6373c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
6383c90c65dSKevin Wolf                                      const char *tag)
6393c90c65dSKevin Wolf {
6403c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6413c90c65dSKevin Wolf     struct BlkdebugRule *rule;
6423c90c65dSKevin Wolf     BlkDebugEvent blkdebug_event;
6433c90c65dSKevin Wolf 
6443c90c65dSKevin Wolf     if (get_event_by_name(event, &blkdebug_event) < 0) {
6453c90c65dSKevin Wolf         return -ENOENT;
6463c90c65dSKevin Wolf     }
6473c90c65dSKevin Wolf 
6483c90c65dSKevin Wolf 
6493c90c65dSKevin Wolf     rule = g_malloc(sizeof(*rule));
6503c90c65dSKevin Wolf     *rule = (struct BlkdebugRule) {
6513c90c65dSKevin Wolf         .event  = blkdebug_event,
6523c90c65dSKevin Wolf         .action = ACTION_SUSPEND,
6533c90c65dSKevin Wolf         .state  = 0,
6543c90c65dSKevin Wolf         .options.suspend.tag = g_strdup(tag),
6553c90c65dSKevin Wolf     };
6563c90c65dSKevin Wolf 
6573c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
6583c90c65dSKevin Wolf 
6593c90c65dSKevin Wolf     return 0;
6603c90c65dSKevin Wolf }
6613c90c65dSKevin Wolf 
6623c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
6633c90c65dSKevin Wolf {
6643c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
665c547e564SFam Zheng     BlkdebugSuspendedReq *r, *next;
6663c90c65dSKevin Wolf 
667c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
6683c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
6693c90c65dSKevin Wolf             qemu_coroutine_enter(r->co, NULL);
6703c90c65dSKevin Wolf             return 0;
6713c90c65dSKevin Wolf         }
6723c90c65dSKevin Wolf     }
6733c90c65dSKevin Wolf     return -ENOENT;
6743c90c65dSKevin Wolf }
6753c90c65dSKevin Wolf 
6764cc70e93SFam Zheng static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
6774cc70e93SFam Zheng                                             const char *tag)
6784cc70e93SFam Zheng {
6794cc70e93SFam Zheng     BDRVBlkdebugState *s = bs->opaque;
680c547e564SFam Zheng     BlkdebugSuspendedReq *r, *r_next;
6814cc70e93SFam Zheng     BlkdebugRule *rule, *next;
6824cc70e93SFam Zheng     int i, ret = -ENOENT;
6834cc70e93SFam Zheng 
6844cc70e93SFam Zheng     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
6854cc70e93SFam Zheng         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
6864cc70e93SFam Zheng             if (rule->action == ACTION_SUSPEND &&
6874cc70e93SFam Zheng                 !strcmp(rule->options.suspend.tag, tag)) {
6884cc70e93SFam Zheng                 remove_rule(rule);
6894cc70e93SFam Zheng                 ret = 0;
6904cc70e93SFam Zheng             }
6914cc70e93SFam Zheng         }
6924cc70e93SFam Zheng     }
693c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
6944cc70e93SFam Zheng         if (!strcmp(r->tag, tag)) {
6954cc70e93SFam Zheng             qemu_coroutine_enter(r->co, NULL);
6964cc70e93SFam Zheng             ret = 0;
6974cc70e93SFam Zheng         }
6984cc70e93SFam Zheng     }
6994cc70e93SFam Zheng     return ret;
7004cc70e93SFam Zheng }
7013c90c65dSKevin Wolf 
7023c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
7033c90c65dSKevin Wolf {
7043c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
7053c90c65dSKevin Wolf     BlkdebugSuspendedReq *r;
7063c90c65dSKevin Wolf 
7073c90c65dSKevin Wolf     QLIST_FOREACH(r, &s->suspended_reqs, next) {
7083c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
7093c90c65dSKevin Wolf             return true;
7103c90c65dSKevin Wolf         }
7113c90c65dSKevin Wolf     }
7123c90c65dSKevin Wolf     return false;
7133c90c65dSKevin Wolf }
7143c90c65dSKevin Wolf 
715e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs)
716e1302255SPaolo Bonzini {
717e1302255SPaolo Bonzini     return bdrv_getlength(bs->file);
718e1302255SPaolo Bonzini }
719e1302255SPaolo Bonzini 
7202c31b04cSMax Reitz static void blkdebug_refresh_filename(BlockDriverState *bs)
7212c31b04cSMax Reitz {
7222c31b04cSMax Reitz     BDRVBlkdebugState *s = bs->opaque;
7232c31b04cSMax Reitz     struct BlkdebugRule *rule;
7242c31b04cSMax Reitz     QDict *opts;
7252c31b04cSMax Reitz     QList *inject_error_list = NULL, *set_state_list = NULL;
7262c31b04cSMax Reitz     QList *suspend_list = NULL;
7272c31b04cSMax Reitz     int event;
7282c31b04cSMax Reitz 
7292c31b04cSMax Reitz     if (!bs->file->full_open_options) {
7302c31b04cSMax Reitz         /* The config file cannot be recreated, so creating a plain filename
7312c31b04cSMax Reitz          * is impossible */
7322c31b04cSMax Reitz         return;
7332c31b04cSMax Reitz     }
7342c31b04cSMax Reitz 
7352c31b04cSMax Reitz     opts = qdict_new();
7362c31b04cSMax Reitz     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
7372c31b04cSMax Reitz 
7382c31b04cSMax Reitz     QINCREF(bs->file->full_open_options);
7392c31b04cSMax Reitz     qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
7402c31b04cSMax Reitz 
7412c31b04cSMax Reitz     for (event = 0; event < BLKDBG_EVENT_MAX; event++) {
7422c31b04cSMax Reitz         QLIST_FOREACH(rule, &s->rules[event], next) {
7432c31b04cSMax Reitz             if (rule->action == ACTION_INJECT_ERROR) {
7442c31b04cSMax Reitz                 QDict *inject_error = qdict_new();
7452c31b04cSMax Reitz 
7462c31b04cSMax Reitz                 qdict_put_obj(inject_error, "event", QOBJECT(qstring_from_str(
7472c31b04cSMax Reitz                               BlkdebugEvent_lookup[rule->event])));
7482c31b04cSMax Reitz                 qdict_put_obj(inject_error, "state",
7492c31b04cSMax Reitz                               QOBJECT(qint_from_int(rule->state)));
7502c31b04cSMax Reitz                 qdict_put_obj(inject_error, "errno", QOBJECT(qint_from_int(
7512c31b04cSMax Reitz                               rule->options.inject.error)));
7522c31b04cSMax Reitz                 qdict_put_obj(inject_error, "sector", QOBJECT(qint_from_int(
7532c31b04cSMax Reitz                               rule->options.inject.sector)));
7542c31b04cSMax Reitz                 qdict_put_obj(inject_error, "once", QOBJECT(qbool_from_int(
7552c31b04cSMax Reitz                               rule->options.inject.once)));
7562c31b04cSMax Reitz                 qdict_put_obj(inject_error, "immediately",
7572c31b04cSMax Reitz                               QOBJECT(qbool_from_int(
7582c31b04cSMax Reitz                               rule->options.inject.immediately)));
7592c31b04cSMax Reitz 
7602c31b04cSMax Reitz                 if (!inject_error_list) {
7612c31b04cSMax Reitz                     inject_error_list = qlist_new();
7622c31b04cSMax Reitz                 }
7632c31b04cSMax Reitz 
7642c31b04cSMax Reitz                 qlist_append_obj(inject_error_list, QOBJECT(inject_error));
7652c31b04cSMax Reitz             } else if (rule->action == ACTION_SET_STATE) {
7662c31b04cSMax Reitz                 QDict *set_state = qdict_new();
7672c31b04cSMax Reitz 
7682c31b04cSMax Reitz                 qdict_put_obj(set_state, "event", QOBJECT(qstring_from_str(
7692c31b04cSMax Reitz                               BlkdebugEvent_lookup[rule->event])));
7702c31b04cSMax Reitz                 qdict_put_obj(set_state, "state",
7712c31b04cSMax Reitz                               QOBJECT(qint_from_int(rule->state)));
7722c31b04cSMax Reitz                 qdict_put_obj(set_state, "new_state", QOBJECT(qint_from_int(
7732c31b04cSMax Reitz                               rule->options.set_state.new_state)));
7742c31b04cSMax Reitz 
7752c31b04cSMax Reitz                 if (!set_state_list) {
7762c31b04cSMax Reitz                     set_state_list = qlist_new();
7772c31b04cSMax Reitz                 }
7782c31b04cSMax Reitz 
7792c31b04cSMax Reitz                 qlist_append_obj(set_state_list, QOBJECT(set_state));
7802c31b04cSMax Reitz             } else if (rule->action == ACTION_SUSPEND) {
7812c31b04cSMax Reitz                 QDict *suspend = qdict_new();
7822c31b04cSMax Reitz 
7832c31b04cSMax Reitz                 qdict_put_obj(suspend, "event", QOBJECT(qstring_from_str(
7842c31b04cSMax Reitz                               BlkdebugEvent_lookup[rule->event])));
7852c31b04cSMax Reitz                 qdict_put_obj(suspend, "state",
7862c31b04cSMax Reitz                               QOBJECT(qint_from_int(rule->state)));
7872c31b04cSMax Reitz                 qdict_put_obj(suspend, "tag", QOBJECT(qstring_from_str(
7882c31b04cSMax Reitz                               rule->options.suspend.tag)));
7892c31b04cSMax Reitz 
7902c31b04cSMax Reitz                 if (!suspend_list) {
7912c31b04cSMax Reitz                     suspend_list = qlist_new();
7922c31b04cSMax Reitz                 }
7932c31b04cSMax Reitz 
7942c31b04cSMax Reitz                 qlist_append_obj(suspend_list, QOBJECT(suspend));
7952c31b04cSMax Reitz             }
7962c31b04cSMax Reitz         }
7972c31b04cSMax Reitz     }
7982c31b04cSMax Reitz 
7992c31b04cSMax Reitz     if (inject_error_list) {
8002c31b04cSMax Reitz         qdict_put_obj(opts, "inject-error", QOBJECT(inject_error_list));
8012c31b04cSMax Reitz     }
8022c31b04cSMax Reitz     if (set_state_list) {
8032c31b04cSMax Reitz         qdict_put_obj(opts, "set-state", QOBJECT(set_state_list));
8042c31b04cSMax Reitz     }
8052c31b04cSMax Reitz     if (suspend_list) {
8062c31b04cSMax Reitz         qdict_put_obj(opts, "suspend", QOBJECT(suspend_list));
8072c31b04cSMax Reitz     }
8082c31b04cSMax Reitz 
8092c31b04cSMax Reitz     bs->full_open_options = opts;
8102c31b04cSMax Reitz }
8112c31b04cSMax Reitz 
8126a143727SKevin Wolf static BlockDriver bdrv_blkdebug = {
8136a143727SKevin Wolf     .format_name            = "blkdebug",
8146a143727SKevin Wolf     .protocol_name          = "blkdebug",
8156a143727SKevin Wolf     .instance_size          = sizeof(BDRVBlkdebugState),
8166a143727SKevin Wolf 
817f4681212SKevin Wolf     .bdrv_parse_filename    = blkdebug_parse_filename,
81866f82ceeSKevin Wolf     .bdrv_file_open         = blkdebug_open,
8196a143727SKevin Wolf     .bdrv_close             = blkdebug_close,
820e1302255SPaolo Bonzini     .bdrv_getlength         = blkdebug_getlength,
8212c31b04cSMax Reitz     .bdrv_refresh_filename  = blkdebug_refresh_filename,
8226a143727SKevin Wolf 
8236a143727SKevin Wolf     .bdrv_aio_readv         = blkdebug_aio_readv,
8246a143727SKevin Wolf     .bdrv_aio_writev        = blkdebug_aio_writev,
8259e52c53bSPaolo Bonzini     .bdrv_aio_flush         = blkdebug_aio_flush,
8268b9b0cc2SKevin Wolf 
8278b9b0cc2SKevin Wolf     .bdrv_debug_event           = blkdebug_debug_event,
8283c90c65dSKevin Wolf     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
8294cc70e93SFam Zheng     .bdrv_debug_remove_breakpoint
8304cc70e93SFam Zheng                                 = blkdebug_debug_remove_breakpoint,
8313c90c65dSKevin Wolf     .bdrv_debug_resume          = blkdebug_debug_resume,
8323c90c65dSKevin Wolf     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
8336a143727SKevin Wolf };
8346a143727SKevin Wolf 
8356a143727SKevin Wolf static void bdrv_blkdebug_init(void)
8366a143727SKevin Wolf {
8376a143727SKevin Wolf     bdrv_register(&bdrv_blkdebug);
8386a143727SKevin Wolf }
8396a143727SKevin Wolf 
8406a143727SKevin Wolf block_init(bdrv_blkdebug_init);
841