xref: /qemu/block/blkdebug.c (revision e4780db4)
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"
266a143727SKevin Wolf #include "block_int.h"
276a143727SKevin Wolf #include "module.h"
286a143727SKevin Wolf 
296a143727SKevin Wolf typedef struct BDRVBlkdebugState {
30571cd43eSPaolo Bonzini     int state;
31571cd43eSPaolo Bonzini     QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
32571cd43eSPaolo Bonzini     QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
336a143727SKevin Wolf } BDRVBlkdebugState;
346a143727SKevin Wolf 
35b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB {
36b9f66d96SKevin Wolf     BlockDriverAIOCB common;
37b9f66d96SKevin Wolf     QEMUBH *bh;
38b9f66d96SKevin Wolf     int ret;
39b9f66d96SKevin Wolf } BlkdebugAIOCB;
40b9f66d96SKevin Wolf 
41b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
42b9f66d96SKevin Wolf 
43b9f66d96SKevin Wolf static AIOPool blkdebug_aio_pool = {
44b9f66d96SKevin Wolf     .aiocb_size = sizeof(BlkdebugAIOCB),
45b9f66d96SKevin Wolf     .cancel     = blkdebug_aio_cancel,
46b9f66d96SKevin Wolf };
47b9f66d96SKevin Wolf 
488b9b0cc2SKevin Wolf enum {
498b9b0cc2SKevin Wolf     ACTION_INJECT_ERROR,
508b9b0cc2SKevin Wolf     ACTION_SET_STATE,
518b9b0cc2SKevin Wolf };
528b9b0cc2SKevin Wolf 
538b9b0cc2SKevin Wolf typedef struct BlkdebugRule {
548b9b0cc2SKevin Wolf     BlkDebugEvent event;
558b9b0cc2SKevin Wolf     int action;
568b9b0cc2SKevin Wolf     int state;
578b9b0cc2SKevin Wolf     union {
588b9b0cc2SKevin Wolf         struct {
598b9b0cc2SKevin Wolf             int error;
608b9b0cc2SKevin Wolf             int immediately;
618b9b0cc2SKevin Wolf             int once;
62*e4780db4SPaolo Bonzini             int64_t sector;
638b9b0cc2SKevin Wolf         } inject;
648b9b0cc2SKevin Wolf         struct {
658b9b0cc2SKevin Wolf             int new_state;
668b9b0cc2SKevin Wolf         } set_state;
678b9b0cc2SKevin Wolf     } options;
688b9b0cc2SKevin Wolf     QLIST_ENTRY(BlkdebugRule) next;
69571cd43eSPaolo Bonzini     QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
708b9b0cc2SKevin Wolf } BlkdebugRule;
718b9b0cc2SKevin Wolf 
728b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = {
738b9b0cc2SKevin Wolf     .name = "inject-error",
748b9b0cc2SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
758b9b0cc2SKevin Wolf     .desc = {
768b9b0cc2SKevin Wolf         {
778b9b0cc2SKevin Wolf             .name = "event",
788b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
798b9b0cc2SKevin Wolf         },
808b9b0cc2SKevin Wolf         {
818b9b0cc2SKevin Wolf             .name = "state",
828b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
838b9b0cc2SKevin Wolf         },
848b9b0cc2SKevin Wolf         {
858b9b0cc2SKevin Wolf             .name = "errno",
868b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
878b9b0cc2SKevin Wolf         },
888b9b0cc2SKevin Wolf         {
89*e4780db4SPaolo Bonzini             .name = "sector",
90*e4780db4SPaolo Bonzini             .type = QEMU_OPT_NUMBER,
91*e4780db4SPaolo Bonzini         },
92*e4780db4SPaolo Bonzini         {
938b9b0cc2SKevin Wolf             .name = "once",
948b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
958b9b0cc2SKevin Wolf         },
968b9b0cc2SKevin Wolf         {
978b9b0cc2SKevin Wolf             .name = "immediately",
988b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
998b9b0cc2SKevin Wolf         },
1008b9b0cc2SKevin Wolf         { /* end of list */ }
1018b9b0cc2SKevin Wolf     },
1028b9b0cc2SKevin Wolf };
1038b9b0cc2SKevin Wolf 
1048b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = {
1058b9b0cc2SKevin Wolf     .name = "set-state",
106327cdad4SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
1078b9b0cc2SKevin Wolf     .desc = {
1088b9b0cc2SKevin Wolf         {
1098b9b0cc2SKevin Wolf             .name = "event",
1108b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
1118b9b0cc2SKevin Wolf         },
1128b9b0cc2SKevin Wolf         {
1138b9b0cc2SKevin Wolf             .name = "state",
1148b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1158b9b0cc2SKevin Wolf         },
1168b9b0cc2SKevin Wolf         {
1178b9b0cc2SKevin Wolf             .name = "new_state",
1188b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1198b9b0cc2SKevin Wolf         },
1208b9b0cc2SKevin Wolf         { /* end of list */ }
1218b9b0cc2SKevin Wolf     },
1228b9b0cc2SKevin Wolf };
1238b9b0cc2SKevin Wolf 
1248b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = {
1258b9b0cc2SKevin Wolf     &inject_error_opts,
1268b9b0cc2SKevin Wolf     &set_state_opts,
1278b9b0cc2SKevin Wolf     NULL
1288b9b0cc2SKevin Wolf };
1298b9b0cc2SKevin Wolf 
1308b9b0cc2SKevin Wolf static const char *event_names[BLKDBG_EVENT_MAX] = {
1318252278aSKevin Wolf     [BLKDBG_L1_UPDATE]                      = "l1_update",
1328252278aSKevin Wolf     [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
1338252278aSKevin Wolf     [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
1348252278aSKevin Wolf     [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
1358252278aSKevin Wolf 
1368252278aSKevin Wolf     [BLKDBG_L2_LOAD]                        = "l2_load",
1378252278aSKevin Wolf     [BLKDBG_L2_UPDATE]                      = "l2_update",
1388252278aSKevin Wolf     [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
1398252278aSKevin Wolf     [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
1408252278aSKevin Wolf     [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
1418252278aSKevin Wolf 
1428252278aSKevin Wolf     [BLKDBG_READ_AIO]                       = "read_aio",
1438252278aSKevin Wolf     [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
1448252278aSKevin Wolf     [BLKDBG_READ_COMPRESSED]                = "read_compressed",
1458252278aSKevin Wolf 
1468252278aSKevin Wolf     [BLKDBG_WRITE_AIO]                      = "write_aio",
1478252278aSKevin Wolf     [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
1488252278aSKevin Wolf 
1498252278aSKevin Wolf     [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
1508252278aSKevin Wolf     [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
1518252278aSKevin Wolf 
1528252278aSKevin Wolf     [BLKDBG_COW_READ]                       = "cow_read",
1538252278aSKevin Wolf     [BLKDBG_COW_WRITE]                      = "cow_write",
1548252278aSKevin Wolf 
1558252278aSKevin Wolf     [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
1568252278aSKevin Wolf     [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
1578252278aSKevin Wolf 
1588252278aSKevin Wolf     [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
1598252278aSKevin Wolf     [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
1608252278aSKevin Wolf     [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
1618252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
1628252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
1638252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
1648252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
1658252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
1668252278aSKevin Wolf     [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
1678252278aSKevin Wolf 
1688252278aSKevin Wolf     [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
1698252278aSKevin Wolf     [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
1708252278aSKevin Wolf     [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
1718b9b0cc2SKevin Wolf };
1728b9b0cc2SKevin Wolf 
1738b9b0cc2SKevin Wolf static int get_event_by_name(const char *name, BlkDebugEvent *event)
1748b9b0cc2SKevin Wolf {
1758b9b0cc2SKevin Wolf     int i;
1768b9b0cc2SKevin Wolf 
1778b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
1788b9b0cc2SKevin Wolf         if (!strcmp(event_names[i], name)) {
1798b9b0cc2SKevin Wolf             *event = i;
1808b9b0cc2SKevin Wolf             return 0;
1818b9b0cc2SKevin Wolf         }
1828b9b0cc2SKevin Wolf     }
1838b9b0cc2SKevin Wolf 
1848b9b0cc2SKevin Wolf     return -1;
1858b9b0cc2SKevin Wolf }
1868b9b0cc2SKevin Wolf 
1878b9b0cc2SKevin Wolf struct add_rule_data {
1888b9b0cc2SKevin Wolf     BDRVBlkdebugState *s;
1898b9b0cc2SKevin Wolf     int action;
1908b9b0cc2SKevin Wolf };
1918b9b0cc2SKevin Wolf 
1928b9b0cc2SKevin Wolf static int add_rule(QemuOpts *opts, void *opaque)
1938b9b0cc2SKevin Wolf {
1948b9b0cc2SKevin Wolf     struct add_rule_data *d = opaque;
1958b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = d->s;
1968b9b0cc2SKevin Wolf     const char* event_name;
1978b9b0cc2SKevin Wolf     BlkDebugEvent event;
1988b9b0cc2SKevin Wolf     struct BlkdebugRule *rule;
1998b9b0cc2SKevin Wolf 
2008b9b0cc2SKevin Wolf     /* Find the right event for the rule */
2018b9b0cc2SKevin Wolf     event_name = qemu_opt_get(opts, "event");
2028b9b0cc2SKevin Wolf     if (!event_name || get_event_by_name(event_name, &event) < 0) {
2038b9b0cc2SKevin Wolf         return -1;
2048b9b0cc2SKevin Wolf     }
2058b9b0cc2SKevin Wolf 
2068b9b0cc2SKevin Wolf     /* Set attributes common for all actions */
2077267c094SAnthony Liguori     rule = g_malloc0(sizeof(*rule));
2088b9b0cc2SKevin Wolf     *rule = (struct BlkdebugRule) {
2098b9b0cc2SKevin Wolf         .event  = event,
2108b9b0cc2SKevin Wolf         .action = d->action,
2118b9b0cc2SKevin Wolf         .state  = qemu_opt_get_number(opts, "state", 0),
2128b9b0cc2SKevin Wolf     };
2138b9b0cc2SKevin Wolf 
2148b9b0cc2SKevin Wolf     /* Parse action-specific options */
2158b9b0cc2SKevin Wolf     switch (d->action) {
2168b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
2178b9b0cc2SKevin Wolf         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
2188b9b0cc2SKevin Wolf         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
2198b9b0cc2SKevin Wolf         rule->options.inject.immediately =
2208b9b0cc2SKevin Wolf             qemu_opt_get_bool(opts, "immediately", 0);
221*e4780db4SPaolo Bonzini         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
2228b9b0cc2SKevin Wolf         break;
2238b9b0cc2SKevin Wolf 
2248b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
2258b9b0cc2SKevin Wolf         rule->options.set_state.new_state =
2268b9b0cc2SKevin Wolf             qemu_opt_get_number(opts, "new_state", 0);
2278b9b0cc2SKevin Wolf         break;
2288b9b0cc2SKevin Wolf     };
2298b9b0cc2SKevin Wolf 
2308b9b0cc2SKevin Wolf     /* Add the rule */
2318b9b0cc2SKevin Wolf     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
2328b9b0cc2SKevin Wolf 
2338b9b0cc2SKevin Wolf     return 0;
2348b9b0cc2SKevin Wolf }
2358b9b0cc2SKevin Wolf 
2368b9b0cc2SKevin Wolf static int read_config(BDRVBlkdebugState *s, const char *filename)
2378b9b0cc2SKevin Wolf {
2388b9b0cc2SKevin Wolf     FILE *f;
2398b9b0cc2SKevin Wolf     int ret;
2408b9b0cc2SKevin Wolf     struct add_rule_data d;
2418b9b0cc2SKevin Wolf 
2428b9b0cc2SKevin Wolf     f = fopen(filename, "r");
2438b9b0cc2SKevin Wolf     if (f == NULL) {
2448b9b0cc2SKevin Wolf         return -errno;
2458b9b0cc2SKevin Wolf     }
2468b9b0cc2SKevin Wolf 
2478b9b0cc2SKevin Wolf     ret = qemu_config_parse(f, config_groups, filename);
2488b9b0cc2SKevin Wolf     if (ret < 0) {
2498b9b0cc2SKevin Wolf         goto fail;
2508b9b0cc2SKevin Wolf     }
2518b9b0cc2SKevin Wolf 
2528b9b0cc2SKevin Wolf     d.s = s;
2538b9b0cc2SKevin Wolf     d.action = ACTION_INJECT_ERROR;
2548b9b0cc2SKevin Wolf     qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
2558b9b0cc2SKevin Wolf 
2568b9b0cc2SKevin Wolf     d.action = ACTION_SET_STATE;
2578b9b0cc2SKevin Wolf     qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
2588b9b0cc2SKevin Wolf 
2598b9b0cc2SKevin Wolf     ret = 0;
2608b9b0cc2SKevin Wolf fail:
261698f0d52SKevin Wolf     qemu_opts_reset(&inject_error_opts);
262698f0d52SKevin Wolf     qemu_opts_reset(&set_state_opts);
2638b9b0cc2SKevin Wolf     fclose(f);
2648b9b0cc2SKevin Wolf     return ret;
2658b9b0cc2SKevin Wolf }
2668b9b0cc2SKevin Wolf 
2678b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
2686a143727SKevin Wolf static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
2696a143727SKevin Wolf {
2706a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
2718b9b0cc2SKevin Wolf     int ret;
2728b9b0cc2SKevin Wolf     char *config, *c;
2736a143727SKevin Wolf 
2748b9b0cc2SKevin Wolf     /* Parse the blkdebug: prefix */
2756a143727SKevin Wolf     if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
2766a143727SKevin Wolf         return -EINVAL;
2776a143727SKevin Wolf     }
2786a143727SKevin Wolf     filename += strlen("blkdebug:");
2796a143727SKevin Wolf 
2808b9b0cc2SKevin Wolf     /* Read rules from config file */
2818b9b0cc2SKevin Wolf     c = strchr(filename, ':');
2828b9b0cc2SKevin Wolf     if (c == NULL) {
2838b9b0cc2SKevin Wolf         return -EINVAL;
2848b9b0cc2SKevin Wolf     }
2858b9b0cc2SKevin Wolf 
286031380d8SStefan Hajnoczi     config = g_strdup(filename);
2878b9b0cc2SKevin Wolf     config[c - filename] = '\0';
2888b9b0cc2SKevin Wolf     ret = read_config(s, config);
289031380d8SStefan Hajnoczi     g_free(config);
2908b9b0cc2SKevin Wolf     if (ret < 0) {
2918b9b0cc2SKevin Wolf         return ret;
2928b9b0cc2SKevin Wolf     }
2938b9b0cc2SKevin Wolf     filename = c + 1;
2948b9b0cc2SKevin Wolf 
2958db520ceSKevin Wolf     /* Set initial state */
296571cd43eSPaolo Bonzini     s->state = 1;
2978db520ceSKevin Wolf 
2988b9b0cc2SKevin Wolf     /* Open the backing file */
29966f82ceeSKevin Wolf     ret = bdrv_file_open(&bs->file, filename, flags);
3008b9b0cc2SKevin Wolf     if (ret < 0) {
3018b9b0cc2SKevin Wolf         return ret;
3028b9b0cc2SKevin Wolf     }
3038b9b0cc2SKevin Wolf 
3048b9b0cc2SKevin Wolf     return 0;
3056a143727SKevin Wolf }
3066a143727SKevin Wolf 
307b9f66d96SKevin Wolf static void error_callback_bh(void *opaque)
308b9f66d96SKevin Wolf {
309b9f66d96SKevin Wolf     struct BlkdebugAIOCB *acb = opaque;
310b9f66d96SKevin Wolf     qemu_bh_delete(acb->bh);
311b9f66d96SKevin Wolf     acb->common.cb(acb->common.opaque, acb->ret);
312b9f66d96SKevin Wolf     qemu_aio_release(acb);
313b9f66d96SKevin Wolf }
314b9f66d96SKevin Wolf 
315b9f66d96SKevin Wolf static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
316b9f66d96SKevin Wolf {
317b666d239SKevin Wolf     BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
318b9f66d96SKevin Wolf     qemu_aio_release(acb);
319b9f66d96SKevin Wolf }
320b9f66d96SKevin Wolf 
321b9f66d96SKevin Wolf static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
322571cd43eSPaolo Bonzini     BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
323b9f66d96SKevin Wolf {
324b9f66d96SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
325571cd43eSPaolo Bonzini     int error = rule->options.inject.error;
326b9f66d96SKevin Wolf     struct BlkdebugAIOCB *acb;
327b9f66d96SKevin Wolf     QEMUBH *bh;
328b9f66d96SKevin Wolf 
329571cd43eSPaolo Bonzini     if (rule->options.inject.once) {
330571cd43eSPaolo Bonzini         QSIMPLEQ_INIT(&s->active_rules);
331b9f66d96SKevin Wolf     }
332b9f66d96SKevin Wolf 
333571cd43eSPaolo Bonzini     if (rule->options.inject.immediately) {
334b9f66d96SKevin Wolf         return NULL;
335b9f66d96SKevin Wolf     }
336b9f66d96SKevin Wolf 
337b9f66d96SKevin Wolf     acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
338b9f66d96SKevin Wolf     acb->ret = -error;
339b9f66d96SKevin Wolf 
340b9f66d96SKevin Wolf     bh = qemu_bh_new(error_callback_bh, acb);
341b9f66d96SKevin Wolf     acb->bh = bh;
342b9f66d96SKevin Wolf     qemu_bh_schedule(bh);
343b9f66d96SKevin Wolf 
344b666d239SKevin Wolf     return &acb->common;
345b9f66d96SKevin Wolf }
346b9f66d96SKevin Wolf 
3476a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
3486a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
3496a143727SKevin Wolf     BlockDriverCompletionFunc *cb, void *opaque)
3506a143727SKevin Wolf {
3516a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
352*e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
353*e4780db4SPaolo Bonzini 
354*e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
355*e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
356*e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
357*e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
358*e4780db4SPaolo Bonzini             break;
359*e4780db4SPaolo Bonzini         }
360*e4780db4SPaolo Bonzini     }
361b9f66d96SKevin Wolf 
362571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
363571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
364b9f66d96SKevin Wolf     }
365b9f66d96SKevin Wolf 
366368e8dd1SPaolo Bonzini     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
3676a143727SKevin Wolf }
3686a143727SKevin Wolf 
3696a143727SKevin Wolf static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
3706a143727SKevin Wolf     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
3716a143727SKevin Wolf     BlockDriverCompletionFunc *cb, void *opaque)
3726a143727SKevin Wolf {
3736a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
374*e4780db4SPaolo Bonzini     BlkdebugRule *rule = NULL;
375*e4780db4SPaolo Bonzini 
376*e4780db4SPaolo Bonzini     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
377*e4780db4SPaolo Bonzini         if (rule->options.inject.sector == -1 ||
378*e4780db4SPaolo Bonzini             (rule->options.inject.sector >= sector_num &&
379*e4780db4SPaolo Bonzini              rule->options.inject.sector < sector_num + nb_sectors)) {
380*e4780db4SPaolo Bonzini             break;
381*e4780db4SPaolo Bonzini         }
382*e4780db4SPaolo Bonzini     }
383b9f66d96SKevin Wolf 
384571cd43eSPaolo Bonzini     if (rule && rule->options.inject.error) {
385571cd43eSPaolo Bonzini         return inject_error(bs, cb, opaque, rule);
386b9f66d96SKevin Wolf     }
387b9f66d96SKevin Wolf 
388368e8dd1SPaolo Bonzini     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
3896a143727SKevin Wolf }
3906a143727SKevin Wolf 
3916a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs)
3926a143727SKevin Wolf {
3936a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
3948b9b0cc2SKevin Wolf     BlkdebugRule *rule, *next;
3958b9b0cc2SKevin Wolf     int i;
3968b9b0cc2SKevin Wolf 
3978b9b0cc2SKevin Wolf     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
3988b9b0cc2SKevin Wolf         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
3998b9b0cc2SKevin Wolf             QLIST_REMOVE(rule, next);
4007267c094SAnthony Liguori             g_free(rule);
4018b9b0cc2SKevin Wolf         }
4028b9b0cc2SKevin Wolf     }
4036a143727SKevin Wolf }
4046a143727SKevin Wolf 
405571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
406571cd43eSPaolo Bonzini     int old_state, bool injected)
4078b9b0cc2SKevin Wolf {
4088b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
4098b9b0cc2SKevin Wolf 
4108b9b0cc2SKevin Wolf     /* Only process rules for the current state */
411571cd43eSPaolo Bonzini     if (rule->state && rule->state != old_state) {
412571cd43eSPaolo Bonzini         return injected;
4138b9b0cc2SKevin Wolf     }
4148b9b0cc2SKevin Wolf 
4158b9b0cc2SKevin Wolf     /* Take the action */
4168b9b0cc2SKevin Wolf     switch (rule->action) {
4178b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
418571cd43eSPaolo Bonzini         if (!injected) {
419571cd43eSPaolo Bonzini             QSIMPLEQ_INIT(&s->active_rules);
420571cd43eSPaolo Bonzini             injected = true;
421571cd43eSPaolo Bonzini         }
422571cd43eSPaolo Bonzini         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
4238b9b0cc2SKevin Wolf         break;
4248b9b0cc2SKevin Wolf 
4258b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
426571cd43eSPaolo Bonzini         s->state = rule->options.set_state.new_state;
4278b9b0cc2SKevin Wolf         break;
4288b9b0cc2SKevin Wolf     }
429571cd43eSPaolo Bonzini     return injected;
4308b9b0cc2SKevin Wolf }
4318b9b0cc2SKevin Wolf 
4328b9b0cc2SKevin Wolf static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
4338b9b0cc2SKevin Wolf {
4348b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
4358b9b0cc2SKevin Wolf     struct BlkdebugRule *rule;
436571cd43eSPaolo Bonzini     int old_state = s->state;
437571cd43eSPaolo Bonzini     bool injected;
4388b9b0cc2SKevin Wolf 
43995ee3914SBlue Swirl     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
4408b9b0cc2SKevin Wolf 
441571cd43eSPaolo Bonzini     injected = false;
4428b9b0cc2SKevin Wolf     QLIST_FOREACH(rule, &s->rules[event], next) {
443571cd43eSPaolo Bonzini         injected = process_rule(bs, rule, old_state, injected);
4448b9b0cc2SKevin Wolf     }
4458b9b0cc2SKevin Wolf }
4468b9b0cc2SKevin Wolf 
447e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs)
448e1302255SPaolo Bonzini {
449e1302255SPaolo Bonzini     return bdrv_getlength(bs->file);
450e1302255SPaolo Bonzini }
451e1302255SPaolo Bonzini 
4526a143727SKevin Wolf static BlockDriver bdrv_blkdebug = {
4536a143727SKevin Wolf     .format_name        = "blkdebug",
4546a143727SKevin Wolf     .protocol_name      = "blkdebug",
4556a143727SKevin Wolf 
4566a143727SKevin Wolf     .instance_size      = sizeof(BDRVBlkdebugState),
4576a143727SKevin Wolf 
45866f82ceeSKevin Wolf     .bdrv_file_open     = blkdebug_open,
4596a143727SKevin Wolf     .bdrv_close         = blkdebug_close,
460e1302255SPaolo Bonzini     .bdrv_getlength     = blkdebug_getlength,
4616a143727SKevin Wolf 
4626a143727SKevin Wolf     .bdrv_aio_readv     = blkdebug_aio_readv,
4636a143727SKevin Wolf     .bdrv_aio_writev    = blkdebug_aio_writev,
4648b9b0cc2SKevin Wolf 
4658b9b0cc2SKevin Wolf     .bdrv_debug_event   = blkdebug_debug_event,
4666a143727SKevin Wolf };
4676a143727SKevin Wolf 
4686a143727SKevin Wolf static void bdrv_blkdebug_init(void)
4696a143727SKevin Wolf {
4706a143727SKevin Wolf     bdrv_register(&bdrv_blkdebug);
4716a143727SKevin Wolf }
4726a143727SKevin Wolf 
4736a143727SKevin Wolf block_init(bdrv_blkdebug_init);
474