xref: /qemu/block/blkdebug.c (revision 10ffa72f)
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"
296a143727SKevin Wolf 
306a143727SKevin Wolf typedef struct BDRVBlkdebugState {
31571cd43eSPaolo Bonzini     int state;
328f96b5beSPaolo Bonzini     int new_state;
333c90c65dSKevin Wolf 
34571cd43eSPaolo Bonzini     QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
35571cd43eSPaolo Bonzini     QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
363c90c65dSKevin Wolf     QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
376a143727SKevin Wolf } BDRVBlkdebugState;
386a143727SKevin Wolf 
39b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB {
40b9f66d96SKevin Wolf     BlockDriverAIOCB common;
41b9f66d96SKevin Wolf     QEMUBH *bh;
42b9f66d96SKevin Wolf     int ret;
43b9f66d96SKevin Wolf } BlkdebugAIOCB;
44b9f66d96SKevin Wolf 
453c90c65dSKevin Wolf typedef struct BlkdebugSuspendedReq {
463c90c65dSKevin Wolf     Coroutine *co;
473c90c65dSKevin Wolf     char *tag;
483c90c65dSKevin Wolf     QLIST_ENTRY(BlkdebugSuspendedReq) next;
493c90c65dSKevin Wolf } BlkdebugSuspendedReq;
503c90c65dSKevin Wolf 
51b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
52b9f66d96SKevin Wolf 
53d7331bedSStefan Hajnoczi static const AIOCBInfo blkdebug_aiocb_info = {
54b9f66d96SKevin Wolf     .aiocb_size = sizeof(BlkdebugAIOCB),
55b9f66d96SKevin Wolf     .cancel     = blkdebug_aio_cancel,
56b9f66d96SKevin Wolf };
57b9f66d96SKevin Wolf 
588b9b0cc2SKevin Wolf enum {
598b9b0cc2SKevin Wolf     ACTION_INJECT_ERROR,
608b9b0cc2SKevin Wolf     ACTION_SET_STATE,
613c90c65dSKevin Wolf     ACTION_SUSPEND,
628b9b0cc2SKevin Wolf };
638b9b0cc2SKevin Wolf 
648b9b0cc2SKevin Wolf typedef struct BlkdebugRule {
658b9b0cc2SKevin Wolf     BlkDebugEvent event;
668b9b0cc2SKevin Wolf     int action;
678b9b0cc2SKevin Wolf     int state;
688b9b0cc2SKevin Wolf     union {
698b9b0cc2SKevin Wolf         struct {
708b9b0cc2SKevin Wolf             int error;
718b9b0cc2SKevin Wolf             int immediately;
728b9b0cc2SKevin Wolf             int once;
73e4780db4SPaolo Bonzini             int64_t sector;
748b9b0cc2SKevin Wolf         } inject;
758b9b0cc2SKevin Wolf         struct {
768b9b0cc2SKevin Wolf             int new_state;
778b9b0cc2SKevin Wolf         } set_state;
783c90c65dSKevin Wolf         struct {
793c90c65dSKevin Wolf             char *tag;
803c90c65dSKevin Wolf         } suspend;
818b9b0cc2SKevin Wolf     } options;
828b9b0cc2SKevin Wolf     QLIST_ENTRY(BlkdebugRule) next;
83571cd43eSPaolo Bonzini     QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
848b9b0cc2SKevin Wolf } BlkdebugRule;
858b9b0cc2SKevin Wolf 
868b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = {
878b9b0cc2SKevin Wolf     .name = "inject-error",
888b9b0cc2SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
898b9b0cc2SKevin Wolf     .desc = {
908b9b0cc2SKevin Wolf         {
918b9b0cc2SKevin Wolf             .name = "event",
928b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
938b9b0cc2SKevin Wolf         },
948b9b0cc2SKevin Wolf         {
958b9b0cc2SKevin Wolf             .name = "state",
968b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
978b9b0cc2SKevin Wolf         },
988b9b0cc2SKevin Wolf         {
998b9b0cc2SKevin Wolf             .name = "errno",
1008b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1018b9b0cc2SKevin Wolf         },
1028b9b0cc2SKevin Wolf         {
103e4780db4SPaolo Bonzini             .name = "sector",
104e4780db4SPaolo Bonzini             .type = QEMU_OPT_NUMBER,
105e4780db4SPaolo Bonzini         },
106e4780db4SPaolo Bonzini         {
1078b9b0cc2SKevin Wolf             .name = "once",
1088b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
1098b9b0cc2SKevin Wolf         },
1108b9b0cc2SKevin Wolf         {
1118b9b0cc2SKevin Wolf             .name = "immediately",
1128b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
1138b9b0cc2SKevin Wolf         },
1148b9b0cc2SKevin Wolf         { /* end of list */ }
1158b9b0cc2SKevin Wolf     },
1168b9b0cc2SKevin Wolf };
1178b9b0cc2SKevin Wolf 
1188b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = {
1198b9b0cc2SKevin Wolf     .name = "set-state",
120327cdad4SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
1218b9b0cc2SKevin Wolf     .desc = {
1228b9b0cc2SKevin Wolf         {
1238b9b0cc2SKevin Wolf             .name = "event",
1248b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
1258b9b0cc2SKevin Wolf         },
1268b9b0cc2SKevin Wolf         {
1278b9b0cc2SKevin Wolf             .name = "state",
1288b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1298b9b0cc2SKevin Wolf         },
1308b9b0cc2SKevin Wolf         {
1318b9b0cc2SKevin Wolf             .name = "new_state",
1328b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1338b9b0cc2SKevin Wolf         },
1348b9b0cc2SKevin Wolf         { /* end of list */ }
1358b9b0cc2SKevin Wolf     },
1368b9b0cc2SKevin Wolf };
1378b9b0cc2SKevin Wolf 
1388b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = {
1398b9b0cc2SKevin Wolf     &inject_error_opts,
1408b9b0cc2SKevin Wolf     &set_state_opts,
1418b9b0cc2SKevin Wolf     NULL
1428b9b0cc2SKevin Wolf };
1438b9b0cc2SKevin Wolf 
1448b9b0cc2SKevin Wolf static const char *event_names[BLKDBG_EVENT_MAX] = {
1458252278aSKevin Wolf     [BLKDBG_L1_UPDATE]                      = "l1_update",
1468252278aSKevin Wolf     [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
1478252278aSKevin Wolf     [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
1488252278aSKevin Wolf     [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
1498252278aSKevin Wolf 
1508252278aSKevin Wolf     [BLKDBG_L2_LOAD]                        = "l2_load",
1518252278aSKevin Wolf     [BLKDBG_L2_UPDATE]                      = "l2_update",
1528252278aSKevin Wolf     [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
1538252278aSKevin Wolf     [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
1548252278aSKevin Wolf     [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
1558252278aSKevin Wolf 
1568252278aSKevin Wolf     [BLKDBG_READ_AIO]                       = "read_aio",
1578252278aSKevin Wolf     [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
1588252278aSKevin Wolf     [BLKDBG_READ_COMPRESSED]                = "read_compressed",
1598252278aSKevin Wolf 
1608252278aSKevin Wolf     [BLKDBG_WRITE_AIO]                      = "write_aio",
1618252278aSKevin Wolf     [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
1628252278aSKevin Wolf 
1638252278aSKevin Wolf     [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
1648252278aSKevin Wolf     [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
1658252278aSKevin Wolf 
1668252278aSKevin Wolf     [BLKDBG_COW_READ]                       = "cow_read",
1678252278aSKevin Wolf     [BLKDBG_COW_WRITE]                      = "cow_write",
1688252278aSKevin Wolf 
1698252278aSKevin Wolf     [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
1708252278aSKevin Wolf     [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
171afa50193SMax Reitz     [BLKDBG_REFTABLE_UPDATE]                = "reftable_update",
1728252278aSKevin Wolf 
1738252278aSKevin Wolf     [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
1748252278aSKevin Wolf     [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
1758252278aSKevin Wolf     [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
1768252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
1778252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
1788252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
1798252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
1808252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
1818252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
1828252278aSKevin Wolf 
1838252278aSKevin Wolf     [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
1848252278aSKevin Wolf     [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
1858252278aSKevin Wolf     [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
186bf736fe3SKevin Wolf 
187bf736fe3SKevin Wolf     [BLKDBG_FLUSH_TO_OS]                    = "flush_to_os",
188bf736fe3SKevin Wolf     [BLKDBG_FLUSH_TO_DISK]                  = "flush_to_disk",
1898b9b0cc2SKevin Wolf };
1908b9b0cc2SKevin Wolf 
1918b9b0cc2SKevin Wolf static int get_event_by_name(const char *name, BlkDebugEvent *event)
1928b9b0cc2SKevin Wolf {
1938b9b0cc2SKevin Wolf     int i;
1948b9b0cc2SKevin Wolf 
1958b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
1968b9b0cc2SKevin Wolf         if (!strcmp(event_names[i], name)) {
1978b9b0cc2SKevin Wolf             *event = i;
1988b9b0cc2SKevin Wolf             return 0;
1998b9b0cc2SKevin Wolf         }
2008b9b0cc2SKevin Wolf     }
2018b9b0cc2SKevin Wolf 
2028b9b0cc2SKevin Wolf     return -1;
2038b9b0cc2SKevin Wolf }
2048b9b0cc2SKevin Wolf 
2058b9b0cc2SKevin Wolf struct add_rule_data {
2068b9b0cc2SKevin Wolf     BDRVBlkdebugState *s;
2078b9b0cc2SKevin Wolf     int action;
2088b9b0cc2SKevin Wolf };
2098b9b0cc2SKevin Wolf 
2108b9b0cc2SKevin Wolf static int add_rule(QemuOpts *opts, void *opaque)
2118b9b0cc2SKevin Wolf {
2128b9b0cc2SKevin Wolf     struct add_rule_data *d = opaque;
2138b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = d->s;
2148b9b0cc2SKevin Wolf     const char* event_name;
2158b9b0cc2SKevin Wolf     BlkDebugEvent event;
2168b9b0cc2SKevin Wolf     struct BlkdebugRule *rule;
2178b9b0cc2SKevin Wolf 
2188b9b0cc2SKevin Wolf     /* Find the right event for the rule */
2198b9b0cc2SKevin Wolf     event_name = qemu_opt_get(opts, "event");
2208b9b0cc2SKevin Wolf     if (!event_name || get_event_by_name(event_name, &event) < 0) {
2218b9b0cc2SKevin Wolf         return -1;
2228b9b0cc2SKevin Wolf     }
2238b9b0cc2SKevin Wolf 
2248b9b0cc2SKevin Wolf     /* Set attributes common for all actions */
2257267c094SAnthony Liguori     rule = g_malloc0(sizeof(*rule));
2268b9b0cc2SKevin Wolf     *rule = (struct BlkdebugRule) {
2278b9b0cc2SKevin Wolf         .event  = event,
2288b9b0cc2SKevin Wolf         .action = d->action,
2298b9b0cc2SKevin Wolf         .state  = qemu_opt_get_number(opts, "state", 0),
2308b9b0cc2SKevin Wolf     };
2318b9b0cc2SKevin Wolf 
2328b9b0cc2SKevin Wolf     /* Parse action-specific options */
2338b9b0cc2SKevin Wolf     switch (d->action) {
2348b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
2358b9b0cc2SKevin Wolf         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
2368b9b0cc2SKevin Wolf         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
2378b9b0cc2SKevin Wolf         rule->options.inject.immediately =
2388b9b0cc2SKevin Wolf             qemu_opt_get_bool(opts, "immediately", 0);
239e4780db4SPaolo Bonzini         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
2408b9b0cc2SKevin Wolf         break;
2418b9b0cc2SKevin Wolf 
2428b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
2438b9b0cc2SKevin Wolf         rule->options.set_state.new_state =
2448b9b0cc2SKevin Wolf             qemu_opt_get_number(opts, "new_state", 0);
2458b9b0cc2SKevin Wolf         break;
2463c90c65dSKevin Wolf 
2473c90c65dSKevin Wolf     case ACTION_SUSPEND:
2483c90c65dSKevin Wolf         rule->options.suspend.tag =
2493c90c65dSKevin Wolf             g_strdup(qemu_opt_get(opts, "tag"));
2503c90c65dSKevin Wolf         break;
2518b9b0cc2SKevin Wolf     };
2528b9b0cc2SKevin Wolf 
2538b9b0cc2SKevin Wolf     /* Add the rule */
2548b9b0cc2SKevin Wolf     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
2558b9b0cc2SKevin Wolf 
2568b9b0cc2SKevin Wolf     return 0;
2578b9b0cc2SKevin Wolf }
2588b9b0cc2SKevin Wolf 
2599e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule)
2609e35542bSKevin Wolf {
2619e35542bSKevin Wolf     switch (rule->action) {
2629e35542bSKevin Wolf     case ACTION_INJECT_ERROR:
2639e35542bSKevin Wolf     case ACTION_SET_STATE:
2649e35542bSKevin Wolf         break;
2653c90c65dSKevin Wolf     case ACTION_SUSPEND:
2663c90c65dSKevin Wolf         g_free(rule->options.suspend.tag);
2673c90c65dSKevin Wolf         break;
2689e35542bSKevin Wolf     }
2699e35542bSKevin Wolf 
2709e35542bSKevin Wolf     QLIST_REMOVE(rule, next);
2719e35542bSKevin Wolf     g_free(rule);
2729e35542bSKevin Wolf }
2739e35542bSKevin Wolf 
2748b9b0cc2SKevin Wolf static int read_config(BDRVBlkdebugState *s, const char *filename)
2758b9b0cc2SKevin Wolf {
2768b9b0cc2SKevin Wolf     FILE *f;
2778b9b0cc2SKevin Wolf     int ret;
2788b9b0cc2SKevin Wolf     struct add_rule_data d;
2798b9b0cc2SKevin Wolf 
2808b9b0cc2SKevin Wolf     f = fopen(filename, "r");
2818b9b0cc2SKevin Wolf     if (f == NULL) {
2828b9b0cc2SKevin Wolf         return -errno;
2838b9b0cc2SKevin Wolf     }
2848b9b0cc2SKevin Wolf 
2858b9b0cc2SKevin Wolf     ret = qemu_config_parse(f, config_groups, filename);
2868b9b0cc2SKevin Wolf     if (ret < 0) {
2878b9b0cc2SKevin Wolf         goto fail;
2888b9b0cc2SKevin Wolf     }
2898b9b0cc2SKevin Wolf 
2908b9b0cc2SKevin Wolf     d.s = s;
2918b9b0cc2SKevin Wolf     d.action = ACTION_INJECT_ERROR;
2928b9b0cc2SKevin Wolf     qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
2938b9b0cc2SKevin Wolf 
2948b9b0cc2SKevin Wolf     d.action = ACTION_SET_STATE;
2958b9b0cc2SKevin Wolf     qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
2968b9b0cc2SKevin Wolf 
2978b9b0cc2SKevin Wolf     ret = 0;
2988b9b0cc2SKevin Wolf fail:
299698f0d52SKevin Wolf     qemu_opts_reset(&inject_error_opts);
300698f0d52SKevin Wolf     qemu_opts_reset(&set_state_opts);
3018b9b0cc2SKevin Wolf     fclose(f);
3028b9b0cc2SKevin Wolf     return ret;
3038b9b0cc2SKevin Wolf }
3048b9b0cc2SKevin Wolf 
3058b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
306f4681212SKevin Wolf static void blkdebug_parse_filename(const char *filename, QDict *options,
307f4681212SKevin Wolf                                     Error **errp)
308f4681212SKevin Wolf {
309f4681212SKevin Wolf     const char *c;
310f4681212SKevin Wolf 
311f4681212SKevin Wolf     /* Parse the blkdebug: prefix */
312f4681212SKevin Wolf     if (!strstart(filename, "blkdebug:", &filename)) {
313f4681212SKevin Wolf         error_setg(errp, "File name string must start with 'blkdebug:'");
314f4681212SKevin Wolf         return;
315f4681212SKevin Wolf     }
316f4681212SKevin Wolf 
317f4681212SKevin Wolf     /* Parse config file path */
318f4681212SKevin Wolf     c = strchr(filename, ':');
319f4681212SKevin Wolf     if (c == NULL) {
320f4681212SKevin Wolf         error_setg(errp, "blkdebug requires both config file and image path");
321f4681212SKevin Wolf         return;
322f4681212SKevin Wolf     }
323f4681212SKevin Wolf 
324f4681212SKevin Wolf     if (c != filename) {
325f4681212SKevin Wolf         QString *config_path;
326f4681212SKevin Wolf         config_path = qstring_from_substr(filename, 0, c - filename - 1);
327f4681212SKevin Wolf         qdict_put(options, "config", config_path);
328f4681212SKevin Wolf     }
329f4681212SKevin Wolf 
330f4681212SKevin Wolf     /* TODO Allow multi-level nesting and set file.filename here */
331f4681212SKevin Wolf     filename = c + 1;
332f4681212SKevin Wolf     qdict_put(options, "x-image", qstring_from_str(filename));
333f4681212SKevin Wolf }
334f4681212SKevin Wolf 
335f4681212SKevin Wolf static QemuOptsList runtime_opts = {
336f4681212SKevin Wolf     .name = "blkdebug",
337f4681212SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
338f4681212SKevin Wolf     .desc = {
339f4681212SKevin Wolf         {
340f4681212SKevin Wolf             .name = "config",
341f4681212SKevin Wolf             .type = QEMU_OPT_STRING,
342f4681212SKevin Wolf             .help = "Path to the configuration file",
343f4681212SKevin Wolf         },
344f4681212SKevin Wolf         {
345f4681212SKevin Wolf             .name = "x-image",
346f4681212SKevin Wolf             .type = QEMU_OPT_STRING,
347f4681212SKevin Wolf             .help = "[internal use only, will be removed]",
348f4681212SKevin Wolf         },
349f4681212SKevin Wolf         { /* end of list */ }
350f4681212SKevin Wolf     },
351f4681212SKevin Wolf };
352f4681212SKevin Wolf 
353015a1036SMax Reitz static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
354015a1036SMax Reitz                          Error **errp)
3556a143727SKevin Wolf {
3566a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
357f4681212SKevin Wolf     QemuOpts *opts;
358f4681212SKevin Wolf     Error *local_err = NULL;
359f4681212SKevin Wolf     const char *filename, *config;
3608b9b0cc2SKevin Wolf     int ret;
3616a143727SKevin Wolf 
362f4681212SKevin Wolf     opts = qemu_opts_create_nofail(&runtime_opts);
363f4681212SKevin Wolf     qemu_opts_absorb_qdict(opts, options, &local_err);
364f4681212SKevin Wolf     if (error_is_set(&local_err)) {
365*10ffa72fSMax Reitz         error_propagate(errp, local_err);
366f4681212SKevin Wolf         ret = -EINVAL;
367f4681212SKevin Wolf         goto fail;
3686a143727SKevin Wolf     }
3696a143727SKevin Wolf 
3708b9b0cc2SKevin Wolf     /* Read rules from config file */
371f4681212SKevin Wolf     config = qemu_opt_get(opts, "config");
372f4681212SKevin Wolf     if (config) {
3738b9b0cc2SKevin Wolf         ret = read_config(s, config);
3748b9b0cc2SKevin Wolf         if (ret < 0) {
375*10ffa72fSMax Reitz             error_setg_errno(errp, -ret, "Could not read blkdebug config file");
376f4681212SKevin Wolf             goto fail;
3778b9b0cc2SKevin Wolf         }
378f4681212SKevin Wolf     }
3798b9b0cc2SKevin Wolf 
3808db520ceSKevin Wolf     /* Set initial state */
381571cd43eSPaolo Bonzini     s->state = 1;
3828db520ceSKevin Wolf 
3838b9b0cc2SKevin Wolf     /* Open the backing file */
384f4681212SKevin Wolf     filename = qemu_opt_get(opts, "x-image");
385f4681212SKevin Wolf     if (filename == NULL) {
386*10ffa72fSMax Reitz         error_setg(errp, "Could not retrieve image file name");
387f4681212SKevin Wolf         ret = -EINVAL;
388f4681212SKevin Wolf         goto fail;
3898b9b0cc2SKevin Wolf     }
3908b9b0cc2SKevin Wolf 
39134b5d2c6SMax Reitz     ret = bdrv_file_open(&bs->file, filename, NULL, flags, &local_err);
392f4681212SKevin Wolf     if (ret < 0) {
393*10ffa72fSMax Reitz         error_propagate(errp, local_err);
394f4681212SKevin Wolf         goto fail;
395f4681212SKevin Wolf     }
396f4681212SKevin Wolf 
397f4681212SKevin Wolf     ret = 0;
398f4681212SKevin Wolf fail:
399f4681212SKevin Wolf     qemu_opts_del(opts);
400f4681212SKevin Wolf     return ret;
4016a143727SKevin Wolf }
4026a143727SKevin Wolf 
403b9f66d96SKevin Wolf static void error_callback_bh(void *opaque)
404b9f66d96SKevin Wolf {
405b9f66d96SKevin Wolf     struct BlkdebugAIOCB *acb = opaque;
406b9f66d96SKevin Wolf     qemu_bh_delete(acb->bh);
407b9f66d96SKevin Wolf     acb->common.cb(acb->common.opaque, acb->ret);
408b9f66d96SKevin Wolf     qemu_aio_release(acb);
409b9f66d96SKevin Wolf }
410b9f66d96SKevin Wolf 
411b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
412b9f66d96SKevin Wolf {
413b666d239SKevin Wolf     BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
414b9f66d96SKevin Wolf     qemu_aio_release(acb);
415b9f66d96SKevin Wolf }
416b9f66d96SKevin Wolf 
417b9f66d96SKevin Wolf static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
418571cd43eSPaolo Bonzini     BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
419b9f66d96SKevin Wolf {
420b9f66d96SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
421571cd43eSPaolo Bonzini     int error = rule->options.inject.error;
422b9f66d96SKevin Wolf     struct BlkdebugAIOCB *acb;
423b9f66d96SKevin Wolf     QEMUBH *bh;
424b9f66d96SKevin Wolf 
425571cd43eSPaolo Bonzini     if (rule->options.inject.once) {
426571cd43eSPaolo Bonzini         QSIMPLEQ_INIT(&s->active_rules);
427b9f66d96SKevin Wolf     }
428b9f66d96SKevin Wolf 
429571cd43eSPaolo Bonzini     if (rule->options.inject.immediately) {
430b9f66d96SKevin Wolf         return NULL;
431b9f66d96SKevin Wolf     }
432b9f66d96SKevin Wolf 
433d7331bedSStefan Hajnoczi     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
434b9f66d96SKevin Wolf     acb->ret = -error;
435b9f66d96SKevin Wolf 
436b9f66d96SKevin Wolf     bh = qemu_bh_new(error_callback_bh, acb);
437b9f66d96SKevin Wolf     acb->bh = bh;
438b9f66d96SKevin Wolf     qemu_bh_schedule(bh);
439b9f66d96SKevin Wolf 
440b666d239SKevin Wolf     return &acb->common;
441b9f66d96SKevin Wolf }
442b9f66d96SKevin Wolf 
4436a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
4446a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
4456a143727SKevin Wolf     BlockDriverCompletionFunc *cb, void *opaque)
4466a143727SKevin Wolf {
4476a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
448e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
449e4780db4SPaolo Bonzini 
450e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
451e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
452e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
453e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
454e4780db4SPaolo Bonzini             break;
455e4780db4SPaolo Bonzini         }
456e4780db4SPaolo Bonzini     }
457b9f66d96SKevin Wolf 
458571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
459571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
460b9f66d96SKevin Wolf     }
461b9f66d96SKevin Wolf 
462368e8dd1SPaolo Bonzini     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
4636a143727SKevin Wolf }
4646a143727SKevin Wolf 
4656a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
4666a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
4676a143727SKevin Wolf     BlockDriverCompletionFunc *cb, void *opaque)
4686a143727SKevin Wolf {
4696a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
470e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
471e4780db4SPaolo Bonzini 
472e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
473e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
474e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
475e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
476e4780db4SPaolo Bonzini             break;
477e4780db4SPaolo Bonzini         }
478e4780db4SPaolo Bonzini     }
479b9f66d96SKevin Wolf 
480571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
481571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
482b9f66d96SKevin Wolf     }
483b9f66d96SKevin Wolf 
484368e8dd1SPaolo Bonzini     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
4856a143727SKevin Wolf }
4866a143727SKevin Wolf 
4873c90c65dSKevin Wolf 
4886a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs)
4896a143727SKevin Wolf {
4906a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
4918b9b0cc2SKevin Wolf     BlkdebugRule *rule, *next;
4928b9b0cc2SKevin Wolf     int i;
4938b9b0cc2SKevin Wolf 
4948b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
4958b9b0cc2SKevin Wolf         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
4969e35542bSKevin Wolf             remove_rule(rule);
4978b9b0cc2SKevin Wolf         }
4988b9b0cc2SKevin Wolf     }
4996a143727SKevin Wolf }
5006a143727SKevin Wolf 
5013c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
5023c90c65dSKevin Wolf {
5033c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5043c90c65dSKevin Wolf     BlkdebugSuspendedReq r;
5053c90c65dSKevin Wolf 
5063c90c65dSKevin Wolf     r = (BlkdebugSuspendedReq) {
5073c90c65dSKevin Wolf         .co         = qemu_coroutine_self(),
5083c90c65dSKevin Wolf         .tag        = g_strdup(rule->options.suspend.tag),
5093c90c65dSKevin Wolf     };
5103c90c65dSKevin Wolf 
5113c90c65dSKevin Wolf     remove_rule(rule);
5123c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
5133c90c65dSKevin Wolf 
5143c90c65dSKevin Wolf     printf("blkdebug: Suspended request '%s'\n", r.tag);
5153c90c65dSKevin Wolf     qemu_coroutine_yield();
5163c90c65dSKevin Wolf     printf("blkdebug: Resuming request '%s'\n", r.tag);
5173c90c65dSKevin Wolf 
5183c90c65dSKevin Wolf     QLIST_REMOVE(&r, next);
5193c90c65dSKevin Wolf     g_free(r.tag);
5203c90c65dSKevin Wolf }
5213c90c65dSKevin Wolf 
522571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
5238f96b5beSPaolo Bonzini     bool injected)
5248b9b0cc2SKevin Wolf {
5258b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5268b9b0cc2SKevin Wolf 
5278b9b0cc2SKevin Wolf     /* Only process rules for the current state */
5288f96b5beSPaolo Bonzini     if (rule->state && rule->state != s->state) {
529571cd43eSPaolo Bonzini         return injected;
5308b9b0cc2SKevin Wolf     }
5318b9b0cc2SKevin Wolf 
5328b9b0cc2SKevin Wolf     /* Take the action */
5338b9b0cc2SKevin Wolf     switch (rule->action) {
5348b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
535571cd43eSPaolo Bonzini         if (!injected) {
536571cd43eSPaolo Bonzini             QSIMPLEQ_INIT(&s->active_rules);
537571cd43eSPaolo Bonzini             injected = true;
538571cd43eSPaolo Bonzini         }
539571cd43eSPaolo Bonzini         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
5408b9b0cc2SKevin Wolf         break;
5418b9b0cc2SKevin Wolf 
5428b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
5438f96b5beSPaolo Bonzini         s->new_state = rule->options.set_state.new_state;
5448b9b0cc2SKevin Wolf         break;
5453c90c65dSKevin Wolf 
5463c90c65dSKevin Wolf     case ACTION_SUSPEND:
5473c90c65dSKevin Wolf         suspend_request(bs, rule);
5483c90c65dSKevin Wolf         break;
5498b9b0cc2SKevin Wolf     }
550571cd43eSPaolo Bonzini     return injected;
5518b9b0cc2SKevin Wolf }
5528b9b0cc2SKevin Wolf 
5538b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
5548b9b0cc2SKevin Wolf {
5558b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5563c90c65dSKevin Wolf     struct BlkdebugRule *rule, *next;
557571cd43eSPaolo Bonzini     bool injected;
5588b9b0cc2SKevin Wolf 
55995ee3914SBlue Swirl     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
5608b9b0cc2SKevin Wolf 
561571cd43eSPaolo Bonzini     injected = false;
5628f96b5beSPaolo Bonzini     s->new_state = s->state;
5633c90c65dSKevin Wolf     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
5648f96b5beSPaolo Bonzini         injected = process_rule(bs, rule, injected);
5658b9b0cc2SKevin Wolf     }
5668f96b5beSPaolo Bonzini     s->state = s->new_state;
5678b9b0cc2SKevin Wolf }
5688b9b0cc2SKevin Wolf 
5693c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
5703c90c65dSKevin Wolf                                      const char *tag)
5713c90c65dSKevin Wolf {
5723c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5733c90c65dSKevin Wolf     struct BlkdebugRule *rule;
5743c90c65dSKevin Wolf     BlkDebugEvent blkdebug_event;
5753c90c65dSKevin Wolf 
5763c90c65dSKevin Wolf     if (get_event_by_name(event, &blkdebug_event) < 0) {
5773c90c65dSKevin Wolf         return -ENOENT;
5783c90c65dSKevin Wolf     }
5793c90c65dSKevin Wolf 
5803c90c65dSKevin Wolf 
5813c90c65dSKevin Wolf     rule = g_malloc(sizeof(*rule));
5823c90c65dSKevin Wolf     *rule = (struct BlkdebugRule) {
5833c90c65dSKevin Wolf         .event  = blkdebug_event,
5843c90c65dSKevin Wolf         .action = ACTION_SUSPEND,
5853c90c65dSKevin Wolf         .state  = 0,
5863c90c65dSKevin Wolf         .options.suspend.tag = g_strdup(tag),
5873c90c65dSKevin Wolf     };
5883c90c65dSKevin Wolf 
5893c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
5903c90c65dSKevin Wolf 
5913c90c65dSKevin Wolf     return 0;
5923c90c65dSKevin Wolf }
5933c90c65dSKevin Wolf 
5943c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
5953c90c65dSKevin Wolf {
5963c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
5973c90c65dSKevin Wolf     BlkdebugSuspendedReq *r;
5983c90c65dSKevin Wolf 
5993c90c65dSKevin Wolf     QLIST_FOREACH(r, &s->suspended_reqs, next) {
6003c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
6013c90c65dSKevin Wolf             qemu_coroutine_enter(r->co, NULL);
6023c90c65dSKevin Wolf             return 0;
6033c90c65dSKevin Wolf         }
6043c90c65dSKevin Wolf     }
6053c90c65dSKevin Wolf     return -ENOENT;
6063c90c65dSKevin Wolf }
6073c90c65dSKevin Wolf 
6083c90c65dSKevin Wolf 
6093c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
6103c90c65dSKevin Wolf {
6113c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6123c90c65dSKevin Wolf     BlkdebugSuspendedReq *r;
6133c90c65dSKevin Wolf 
6143c90c65dSKevin Wolf     QLIST_FOREACH(r, &s->suspended_reqs, next) {
6153c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
6163c90c65dSKevin Wolf             return true;
6173c90c65dSKevin Wolf         }
6183c90c65dSKevin Wolf     }
6193c90c65dSKevin Wolf     return false;
6203c90c65dSKevin Wolf }
6213c90c65dSKevin Wolf 
622e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs)
623e1302255SPaolo Bonzini {
624e1302255SPaolo Bonzini     return bdrv_getlength(bs->file);
625e1302255SPaolo Bonzini }
626e1302255SPaolo Bonzini 
6276a143727SKevin Wolf static BlockDriver bdrv_blkdebug = {
6286a143727SKevin Wolf     .format_name            = "blkdebug",
6296a143727SKevin Wolf     .protocol_name          = "blkdebug",
6306a143727SKevin Wolf     .instance_size          = sizeof(BDRVBlkdebugState),
6316a143727SKevin Wolf 
632f4681212SKevin Wolf     .bdrv_parse_filename    = blkdebug_parse_filename,
63366f82ceeSKevin Wolf     .bdrv_file_open         = blkdebug_open,
6346a143727SKevin Wolf     .bdrv_close             = blkdebug_close,
635e1302255SPaolo Bonzini     .bdrv_getlength         = blkdebug_getlength,
6366a143727SKevin Wolf 
6376a143727SKevin Wolf     .bdrv_aio_readv         = blkdebug_aio_readv,
6386a143727SKevin Wolf     .bdrv_aio_writev        = blkdebug_aio_writev,
6398b9b0cc2SKevin Wolf 
6408b9b0cc2SKevin Wolf     .bdrv_debug_event           = blkdebug_debug_event,
6413c90c65dSKevin Wolf     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
6423c90c65dSKevin Wolf     .bdrv_debug_resume          = blkdebug_debug_resume,
6433c90c65dSKevin Wolf     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
6446a143727SKevin Wolf };
6456a143727SKevin Wolf 
6466a143727SKevin Wolf static void bdrv_blkdebug_init(void)
6476a143727SKevin Wolf {
6486a143727SKevin Wolf     bdrv_register(&bdrv_blkdebug);
6496a143727SKevin Wolf }
6506a143727SKevin Wolf 
6516a143727SKevin Wolf block_init(bdrv_blkdebug_init);
652