xref: /qemu/block/blkdebug.c (revision de81d72d)
16a143727SKevin Wolf /*
26a143727SKevin Wolf  * Block protocol for I/O error injection
36a143727SKevin Wolf  *
463188c24SEric Blake  * Copyright (C) 2016-2017 Red Hat, Inc.
56a143727SKevin Wolf  * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
66a143727SKevin Wolf  *
76a143727SKevin Wolf  * Permission is hereby granted, free of charge, to any person obtaining a copy
86a143727SKevin Wolf  * of this software and associated documentation files (the "Software"), to deal
96a143727SKevin Wolf  * in the Software without restriction, including without limitation the rights
106a143727SKevin Wolf  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
116a143727SKevin Wolf  * copies of the Software, and to permit persons to whom the Software is
126a143727SKevin Wolf  * furnished to do so, subject to the following conditions:
136a143727SKevin Wolf  *
146a143727SKevin Wolf  * The above copyright notice and this permission notice shall be included in
156a143727SKevin Wolf  * all copies or substantial portions of the Software.
166a143727SKevin Wolf  *
176a143727SKevin Wolf  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
186a143727SKevin Wolf  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
196a143727SKevin Wolf  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
206a143727SKevin Wolf  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
216a143727SKevin Wolf  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
226a143727SKevin Wolf  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
236a143727SKevin Wolf  * THE SOFTWARE.
246a143727SKevin Wolf  */
256a143727SKevin Wolf 
2680c71a24SPeter Maydell #include "qemu/osdep.h"
27da34e65cSMarkus Armbruster #include "qapi/error.h"
28f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
291de7afc9SPaolo Bonzini #include "qemu/config-file.h"
30737e150eSPaolo Bonzini #include "block/block_int.h"
311de7afc9SPaolo Bonzini #include "qemu/module.h"
322c31b04cSMax Reitz #include "qapi/qmp/qbool.h"
332c31b04cSMax Reitz #include "qapi/qmp/qdict.h"
342c31b04cSMax Reitz #include "qapi/qmp/qstring.h"
3520873526SMichael S. Tsirkin #include "sysemu/qtest.h"
366a143727SKevin Wolf 
376a143727SKevin Wolf typedef struct BDRVBlkdebugState {
38571cd43eSPaolo Bonzini     int state;
398f96b5beSPaolo Bonzini     int new_state;
403dc834f8SEric Blake     uint64_t align;
41430b26a8SEric Blake     uint64_t max_transfer;
42430b26a8SEric Blake     uint64_t opt_write_zero;
43430b26a8SEric Blake     uint64_t max_write_zero;
44430b26a8SEric Blake     uint64_t opt_discard;
45430b26a8SEric Blake     uint64_t max_discard;
463c90c65dSKevin Wolf 
47036990d7SMax Reitz     /* For blkdebug_refresh_filename() */
48036990d7SMax Reitz     char *config_file;
49036990d7SMax Reitz 
507fb1cf16SEric Blake     QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
51571cd43eSPaolo Bonzini     QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
523c90c65dSKevin Wolf     QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
536a143727SKevin Wolf } BDRVBlkdebugState;
546a143727SKevin Wolf 
55b9f66d96SKevin Wolf typedef struct BlkdebugAIOCB {
567c84b1b8SMarkus Armbruster     BlockAIOCB common;
57b9f66d96SKevin Wolf     int ret;
58b9f66d96SKevin Wolf } BlkdebugAIOCB;
59b9f66d96SKevin Wolf 
603c90c65dSKevin Wolf typedef struct BlkdebugSuspendedReq {
613c90c65dSKevin Wolf     Coroutine *co;
623c90c65dSKevin Wolf     char *tag;
633c90c65dSKevin Wolf     QLIST_ENTRY(BlkdebugSuspendedReq) next;
643c90c65dSKevin Wolf } BlkdebugSuspendedReq;
653c90c65dSKevin Wolf 
668b9b0cc2SKevin Wolf enum {
678b9b0cc2SKevin Wolf     ACTION_INJECT_ERROR,
688b9b0cc2SKevin Wolf     ACTION_SET_STATE,
693c90c65dSKevin Wolf     ACTION_SUSPEND,
708b9b0cc2SKevin Wolf };
718b9b0cc2SKevin Wolf 
728b9b0cc2SKevin Wolf typedef struct BlkdebugRule {
73a31939e6SEric Blake     BlkdebugEvent event;
748b9b0cc2SKevin Wolf     int action;
758b9b0cc2SKevin Wolf     int state;
768b9b0cc2SKevin Wolf     union {
778b9b0cc2SKevin Wolf         struct {
788b9b0cc2SKevin Wolf             int error;
798b9b0cc2SKevin Wolf             int immediately;
808b9b0cc2SKevin Wolf             int once;
817c3a9985SKevin Wolf             int64_t offset;
828b9b0cc2SKevin Wolf         } inject;
838b9b0cc2SKevin Wolf         struct {
848b9b0cc2SKevin Wolf             int new_state;
858b9b0cc2SKevin Wolf         } set_state;
863c90c65dSKevin Wolf         struct {
873c90c65dSKevin Wolf             char *tag;
883c90c65dSKevin Wolf         } suspend;
898b9b0cc2SKevin Wolf     } options;
908b9b0cc2SKevin Wolf     QLIST_ENTRY(BlkdebugRule) next;
91571cd43eSPaolo Bonzini     QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
928b9b0cc2SKevin Wolf } BlkdebugRule;
938b9b0cc2SKevin Wolf 
948b9b0cc2SKevin Wolf static QemuOptsList inject_error_opts = {
958b9b0cc2SKevin Wolf     .name = "inject-error",
968b9b0cc2SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
978b9b0cc2SKevin Wolf     .desc = {
988b9b0cc2SKevin Wolf         {
998b9b0cc2SKevin Wolf             .name = "event",
1008b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
1018b9b0cc2SKevin Wolf         },
1028b9b0cc2SKevin Wolf         {
1038b9b0cc2SKevin Wolf             .name = "state",
1048b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1058b9b0cc2SKevin Wolf         },
1068b9b0cc2SKevin Wolf         {
1078b9b0cc2SKevin Wolf             .name = "errno",
1088b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1098b9b0cc2SKevin Wolf         },
1108b9b0cc2SKevin Wolf         {
111e4780db4SPaolo Bonzini             .name = "sector",
112e4780db4SPaolo Bonzini             .type = QEMU_OPT_NUMBER,
113e4780db4SPaolo Bonzini         },
114e4780db4SPaolo Bonzini         {
1158b9b0cc2SKevin Wolf             .name = "once",
1168b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
1178b9b0cc2SKevin Wolf         },
1188b9b0cc2SKevin Wolf         {
1198b9b0cc2SKevin Wolf             .name = "immediately",
1208b9b0cc2SKevin Wolf             .type = QEMU_OPT_BOOL,
1218b9b0cc2SKevin Wolf         },
1228b9b0cc2SKevin Wolf         { /* end of list */ }
1238b9b0cc2SKevin Wolf     },
1248b9b0cc2SKevin Wolf };
1258b9b0cc2SKevin Wolf 
1268b9b0cc2SKevin Wolf static QemuOptsList set_state_opts = {
1278b9b0cc2SKevin Wolf     .name = "set-state",
128327cdad4SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
1298b9b0cc2SKevin Wolf     .desc = {
1308b9b0cc2SKevin Wolf         {
1318b9b0cc2SKevin Wolf             .name = "event",
1328b9b0cc2SKevin Wolf             .type = QEMU_OPT_STRING,
1338b9b0cc2SKevin Wolf         },
1348b9b0cc2SKevin Wolf         {
1358b9b0cc2SKevin Wolf             .name = "state",
1368b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1378b9b0cc2SKevin Wolf         },
1388b9b0cc2SKevin Wolf         {
1398b9b0cc2SKevin Wolf             .name = "new_state",
1408b9b0cc2SKevin Wolf             .type = QEMU_OPT_NUMBER,
1418b9b0cc2SKevin Wolf         },
1428b9b0cc2SKevin Wolf         { /* end of list */ }
1438b9b0cc2SKevin Wolf     },
1448b9b0cc2SKevin Wolf };
1458b9b0cc2SKevin Wolf 
1468b9b0cc2SKevin Wolf static QemuOptsList *config_groups[] = {
1478b9b0cc2SKevin Wolf     &inject_error_opts,
1488b9b0cc2SKevin Wolf     &set_state_opts,
1498b9b0cc2SKevin Wolf     NULL
1508b9b0cc2SKevin Wolf };
1518b9b0cc2SKevin Wolf 
152a31939e6SEric Blake static int get_event_by_name(const char *name, BlkdebugEvent *event)
1538b9b0cc2SKevin Wolf {
1548b9b0cc2SKevin Wolf     int i;
1558b9b0cc2SKevin Wolf 
1567fb1cf16SEric Blake     for (i = 0; i < BLKDBG__MAX; i++) {
157a31939e6SEric Blake         if (!strcmp(BlkdebugEvent_lookup[i], name)) {
1588b9b0cc2SKevin Wolf             *event = i;
1598b9b0cc2SKevin Wolf             return 0;
1608b9b0cc2SKevin Wolf         }
1618b9b0cc2SKevin Wolf     }
1628b9b0cc2SKevin Wolf 
1638b9b0cc2SKevin Wolf     return -1;
1648b9b0cc2SKevin Wolf }
1658b9b0cc2SKevin Wolf 
1668b9b0cc2SKevin Wolf struct add_rule_data {
1678b9b0cc2SKevin Wolf     BDRVBlkdebugState *s;
1688b9b0cc2SKevin Wolf     int action;
1698b9b0cc2SKevin Wolf };
1708b9b0cc2SKevin Wolf 
17128d0de7aSMarkus Armbruster static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
1728b9b0cc2SKevin Wolf {
1738b9b0cc2SKevin Wolf     struct add_rule_data *d = opaque;
1748b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = d->s;
1758b9b0cc2SKevin Wolf     const char* event_name;
176a31939e6SEric Blake     BlkdebugEvent event;
1778b9b0cc2SKevin Wolf     struct BlkdebugRule *rule;
1787c3a9985SKevin Wolf     int64_t sector;
1798b9b0cc2SKevin Wolf 
1808b9b0cc2SKevin Wolf     /* Find the right event for the rule */
1818b9b0cc2SKevin Wolf     event_name = qemu_opt_get(opts, "event");
182d4362d64SStefan Hajnoczi     if (!event_name) {
1838809cfc3SMarkus Armbruster         error_setg(errp, "Missing event name for rule");
184d4362d64SStefan Hajnoczi         return -1;
185d4362d64SStefan Hajnoczi     } else if (get_event_by_name(event_name, &event) < 0) {
1868809cfc3SMarkus Armbruster         error_setg(errp, "Invalid event name \"%s\"", event_name);
1878b9b0cc2SKevin Wolf         return -1;
1888b9b0cc2SKevin Wolf     }
1898b9b0cc2SKevin Wolf 
1908b9b0cc2SKevin Wolf     /* Set attributes common for all actions */
1917267c094SAnthony Liguori     rule = g_malloc0(sizeof(*rule));
1928b9b0cc2SKevin Wolf     *rule = (struct BlkdebugRule) {
1938b9b0cc2SKevin Wolf         .event  = event,
1948b9b0cc2SKevin Wolf         .action = d->action,
1958b9b0cc2SKevin Wolf         .state  = qemu_opt_get_number(opts, "state", 0),
1968b9b0cc2SKevin Wolf     };
1978b9b0cc2SKevin Wolf 
1988b9b0cc2SKevin Wolf     /* Parse action-specific options */
1998b9b0cc2SKevin Wolf     switch (d->action) {
2008b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
2018b9b0cc2SKevin Wolf         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
2028b9b0cc2SKevin Wolf         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
2038b9b0cc2SKevin Wolf         rule->options.inject.immediately =
2048b9b0cc2SKevin Wolf             qemu_opt_get_bool(opts, "immediately", 0);
2057c3a9985SKevin Wolf         sector = qemu_opt_get_number(opts, "sector", -1);
2067c3a9985SKevin Wolf         rule->options.inject.offset =
2077c3a9985SKevin Wolf             sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
2088b9b0cc2SKevin Wolf         break;
2098b9b0cc2SKevin Wolf 
2108b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
2118b9b0cc2SKevin Wolf         rule->options.set_state.new_state =
2128b9b0cc2SKevin Wolf             qemu_opt_get_number(opts, "new_state", 0);
2138b9b0cc2SKevin Wolf         break;
2143c90c65dSKevin Wolf 
2153c90c65dSKevin Wolf     case ACTION_SUSPEND:
2163c90c65dSKevin Wolf         rule->options.suspend.tag =
2173c90c65dSKevin Wolf             g_strdup(qemu_opt_get(opts, "tag"));
2183c90c65dSKevin Wolf         break;
2198b9b0cc2SKevin Wolf     };
2208b9b0cc2SKevin Wolf 
2218b9b0cc2SKevin Wolf     /* Add the rule */
2228b9b0cc2SKevin Wolf     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
2238b9b0cc2SKevin Wolf 
2248b9b0cc2SKevin Wolf     return 0;
2258b9b0cc2SKevin Wolf }
2268b9b0cc2SKevin Wolf 
2279e35542bSKevin Wolf static void remove_rule(BlkdebugRule *rule)
2289e35542bSKevin Wolf {
2299e35542bSKevin Wolf     switch (rule->action) {
2309e35542bSKevin Wolf     case ACTION_INJECT_ERROR:
2319e35542bSKevin Wolf     case ACTION_SET_STATE:
2329e35542bSKevin Wolf         break;
2333c90c65dSKevin Wolf     case ACTION_SUSPEND:
2343c90c65dSKevin Wolf         g_free(rule->options.suspend.tag);
2353c90c65dSKevin Wolf         break;
2369e35542bSKevin Wolf     }
2379e35542bSKevin Wolf 
2389e35542bSKevin Wolf     QLIST_REMOVE(rule, next);
2399e35542bSKevin Wolf     g_free(rule);
2409e35542bSKevin Wolf }
2419e35542bSKevin Wolf 
24289f2b21eSMax Reitz static int read_config(BDRVBlkdebugState *s, const char *filename,
24389f2b21eSMax Reitz                        QDict *options, Error **errp)
2448b9b0cc2SKevin Wolf {
24585a040e5SMax Reitz     FILE *f = NULL;
2468b9b0cc2SKevin Wolf     int ret;
2478b9b0cc2SKevin Wolf     struct add_rule_data d;
24889f2b21eSMax Reitz     Error *local_err = NULL;
2498b9b0cc2SKevin Wolf 
25085a040e5SMax Reitz     if (filename) {
2518b9b0cc2SKevin Wolf         f = fopen(filename, "r");
2528b9b0cc2SKevin Wolf         if (f == NULL) {
253466b49f2SMax Reitz             error_setg_errno(errp, errno, "Could not read blkdebug config file");
2548b9b0cc2SKevin Wolf             return -errno;
2558b9b0cc2SKevin Wolf         }
2568b9b0cc2SKevin Wolf 
2578b9b0cc2SKevin Wolf         ret = qemu_config_parse(f, config_groups, filename);
2588b9b0cc2SKevin Wolf         if (ret < 0) {
259466b49f2SMax Reitz             error_setg(errp, "Could not parse blkdebug config file");
260466b49f2SMax Reitz             ret = -EINVAL;
2618b9b0cc2SKevin Wolf             goto fail;
2628b9b0cc2SKevin Wolf         }
26385a040e5SMax Reitz     }
2648b9b0cc2SKevin Wolf 
26589f2b21eSMax Reitz     qemu_config_parse_qdict(options, config_groups, &local_err);
26684d18f06SMarkus Armbruster     if (local_err) {
26789f2b21eSMax Reitz         error_propagate(errp, local_err);
26889f2b21eSMax Reitz         ret = -EINVAL;
26989f2b21eSMax Reitz         goto fail;
27089f2b21eSMax Reitz     }
27189f2b21eSMax Reitz 
2728b9b0cc2SKevin Wolf     d.s = s;
2738b9b0cc2SKevin Wolf     d.action = ACTION_INJECT_ERROR;
2748809cfc3SMarkus Armbruster     qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
275d4362d64SStefan Hajnoczi     if (local_err) {
276d4362d64SStefan Hajnoczi         error_propagate(errp, local_err);
277d4362d64SStefan Hajnoczi         ret = -EINVAL;
278d4362d64SStefan Hajnoczi         goto fail;
279d4362d64SStefan Hajnoczi     }
2808b9b0cc2SKevin Wolf 
2818b9b0cc2SKevin Wolf     d.action = ACTION_SET_STATE;
2828809cfc3SMarkus Armbruster     qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
283d4362d64SStefan Hajnoczi     if (local_err) {
284d4362d64SStefan Hajnoczi         error_propagate(errp, local_err);
285d4362d64SStefan Hajnoczi         ret = -EINVAL;
286d4362d64SStefan Hajnoczi         goto fail;
287d4362d64SStefan Hajnoczi     }
2888b9b0cc2SKevin Wolf 
2898b9b0cc2SKevin Wolf     ret = 0;
2908b9b0cc2SKevin Wolf fail:
291698f0d52SKevin Wolf     qemu_opts_reset(&inject_error_opts);
292698f0d52SKevin Wolf     qemu_opts_reset(&set_state_opts);
29385a040e5SMax Reitz     if (f) {
2948b9b0cc2SKevin Wolf         fclose(f);
29585a040e5SMax Reitz     }
2968b9b0cc2SKevin Wolf     return ret;
2978b9b0cc2SKevin Wolf }
2988b9b0cc2SKevin Wolf 
2998b9b0cc2SKevin Wolf /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
300f4681212SKevin Wolf static void blkdebug_parse_filename(const char *filename, QDict *options,
301f4681212SKevin Wolf                                     Error **errp)
302f4681212SKevin Wolf {
303f4681212SKevin Wolf     const char *c;
304f4681212SKevin Wolf 
305f4681212SKevin Wolf     /* Parse the blkdebug: prefix */
306f4681212SKevin Wolf     if (!strstart(filename, "blkdebug:", &filename)) {
307d4881b9bSMax Reitz         /* There was no prefix; therefore, all options have to be already
308d4881b9bSMax Reitz            present in the QDict (except for the filename) */
30946f5ac20SEric Blake         qdict_put_str(options, "x-image", filename);
310f4681212SKevin Wolf         return;
311f4681212SKevin Wolf     }
312f4681212SKevin Wolf 
313f4681212SKevin Wolf     /* Parse config file path */
314f4681212SKevin Wolf     c = strchr(filename, ':');
315f4681212SKevin Wolf     if (c == NULL) {
316f4681212SKevin Wolf         error_setg(errp, "blkdebug requires both config file and image path");
317f4681212SKevin Wolf         return;
318f4681212SKevin Wolf     }
319f4681212SKevin Wolf 
320f4681212SKevin Wolf     if (c != filename) {
321f4681212SKevin Wolf         QString *config_path;
322f4681212SKevin Wolf         config_path = qstring_from_substr(filename, 0, c - filename - 1);
323f4681212SKevin Wolf         qdict_put(options, "config", config_path);
324f4681212SKevin Wolf     }
325f4681212SKevin Wolf 
326f4681212SKevin Wolf     /* TODO Allow multi-level nesting and set file.filename here */
327f4681212SKevin Wolf     filename = c + 1;
32846f5ac20SEric Blake     qdict_put_str(options, "x-image", filename);
329f4681212SKevin Wolf }
330f4681212SKevin Wolf 
331f4681212SKevin Wolf static QemuOptsList runtime_opts = {
332f4681212SKevin Wolf     .name = "blkdebug",
333f4681212SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
334f4681212SKevin Wolf     .desc = {
335f4681212SKevin Wolf         {
336f4681212SKevin Wolf             .name = "config",
337f4681212SKevin Wolf             .type = QEMU_OPT_STRING,
338f4681212SKevin Wolf             .help = "Path to the configuration file",
339f4681212SKevin Wolf         },
340f4681212SKevin Wolf         {
341f4681212SKevin Wolf             .name = "x-image",
342f4681212SKevin Wolf             .type = QEMU_OPT_STRING,
343f4681212SKevin Wolf             .help = "[internal use only, will be removed]",
344f4681212SKevin Wolf         },
345b35ee7fbSKevin Wolf         {
346b35ee7fbSKevin Wolf             .name = "align",
347b35ee7fbSKevin Wolf             .type = QEMU_OPT_SIZE,
348b35ee7fbSKevin Wolf             .help = "Required alignment in bytes",
349b35ee7fbSKevin Wolf         },
350430b26a8SEric Blake         {
351430b26a8SEric Blake             .name = "max-transfer",
352430b26a8SEric Blake             .type = QEMU_OPT_SIZE,
353430b26a8SEric Blake             .help = "Maximum transfer size in bytes",
354430b26a8SEric Blake         },
355430b26a8SEric Blake         {
356430b26a8SEric Blake             .name = "opt-write-zero",
357430b26a8SEric Blake             .type = QEMU_OPT_SIZE,
358430b26a8SEric Blake             .help = "Optimum write zero alignment in bytes",
359430b26a8SEric Blake         },
360430b26a8SEric Blake         {
361430b26a8SEric Blake             .name = "max-write-zero",
362430b26a8SEric Blake             .type = QEMU_OPT_SIZE,
363430b26a8SEric Blake             .help = "Maximum write zero size in bytes",
364430b26a8SEric Blake         },
365430b26a8SEric Blake         {
366430b26a8SEric Blake             .name = "opt-discard",
367430b26a8SEric Blake             .type = QEMU_OPT_SIZE,
368430b26a8SEric Blake             .help = "Optimum discard alignment in bytes",
369430b26a8SEric Blake         },
370430b26a8SEric Blake         {
371430b26a8SEric Blake             .name = "max-discard",
372430b26a8SEric Blake             .type = QEMU_OPT_SIZE,
373430b26a8SEric Blake             .help = "Maximum discard size in bytes",
374430b26a8SEric Blake         },
375f4681212SKevin Wolf         { /* end of list */ }
376f4681212SKevin Wolf     },
377f4681212SKevin Wolf };
378f4681212SKevin Wolf 
379015a1036SMax Reitz static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
380015a1036SMax Reitz                          Error **errp)
3816a143727SKevin Wolf {
3826a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
383f4681212SKevin Wolf     QemuOpts *opts;
384f4681212SKevin Wolf     Error *local_err = NULL;
3858b9b0cc2SKevin Wolf     int ret;
386430b26a8SEric Blake     uint64_t align;
3876a143727SKevin Wolf 
38887ea75d5SPeter Crosthwaite     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
389f4681212SKevin Wolf     qemu_opts_absorb_qdict(opts, options, &local_err);
39084d18f06SMarkus Armbruster     if (local_err) {
39110ffa72fSMax Reitz         error_propagate(errp, local_err);
392f4681212SKevin Wolf         ret = -EINVAL;
393eaf944a4SKevin Wolf         goto out;
3946a143727SKevin Wolf     }
3956a143727SKevin Wolf 
39689f2b21eSMax Reitz     /* Read rules from config file or command line options */
397036990d7SMax Reitz     s->config_file = g_strdup(qemu_opt_get(opts, "config"));
398036990d7SMax Reitz     ret = read_config(s, s->config_file, options, errp);
399466b49f2SMax Reitz     if (ret) {
400eaf944a4SKevin Wolf         goto out;
4018b9b0cc2SKevin Wolf     }
4028b9b0cc2SKevin Wolf 
4038db520ceSKevin Wolf     /* Set initial state */
404571cd43eSPaolo Bonzini     s->state = 1;
4058db520ceSKevin Wolf 
4066b826af7SFam Zheng     /* Open the image file */
4079a4f4c31SKevin Wolf     bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
408f3930ed0SKevin Wolf                                bs, &child_file, false, &local_err);
4099a4f4c31SKevin Wolf     if (local_err) {
4109a4f4c31SKevin Wolf         ret = -EINVAL;
41110ffa72fSMax Reitz         error_propagate(errp, local_err);
412eaf944a4SKevin Wolf         goto out;
413f4681212SKevin Wolf     }
414f4681212SKevin Wolf 
41563188c24SEric Blake     bs->supported_write_flags = BDRV_REQ_FUA &
41663188c24SEric Blake         bs->file->bs->supported_write_flags;
41763188c24SEric Blake     bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
41863188c24SEric Blake         bs->file->bs->supported_zero_flags;
4193dc834f8SEric Blake     ret = -EINVAL;
42063188c24SEric Blake 
421430b26a8SEric Blake     /* Set alignment overrides */
4223dc834f8SEric Blake     s->align = qemu_opt_get_size(opts, "align", 0);
4233dc834f8SEric Blake     if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
4243dc834f8SEric Blake         error_setg(errp, "Cannot meet constraints with align %" PRIu64,
4253dc834f8SEric Blake                    s->align);
426de234897SMax Reitz         goto out;
427b35ee7fbSKevin Wolf     }
428430b26a8SEric Blake     align = MAX(s->align, bs->file->bs->bl.request_alignment);
429430b26a8SEric Blake 
430430b26a8SEric Blake     s->max_transfer = qemu_opt_get_size(opts, "max-transfer", 0);
431430b26a8SEric Blake     if (s->max_transfer &&
432430b26a8SEric Blake         (s->max_transfer >= INT_MAX ||
433430b26a8SEric Blake          !QEMU_IS_ALIGNED(s->max_transfer, align))) {
434430b26a8SEric Blake         error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
435430b26a8SEric Blake                    s->max_transfer);
436430b26a8SEric Blake         goto out;
437430b26a8SEric Blake     }
438430b26a8SEric Blake 
439430b26a8SEric Blake     s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
440430b26a8SEric Blake     if (s->opt_write_zero &&
441430b26a8SEric Blake         (s->opt_write_zero >= INT_MAX ||
442430b26a8SEric Blake          !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
443430b26a8SEric Blake         error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
444430b26a8SEric Blake                    s->opt_write_zero);
445430b26a8SEric Blake         goto out;
446430b26a8SEric Blake     }
447430b26a8SEric Blake 
448430b26a8SEric Blake     s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
449430b26a8SEric Blake     if (s->max_write_zero &&
450430b26a8SEric Blake         (s->max_write_zero >= INT_MAX ||
451430b26a8SEric Blake          !QEMU_IS_ALIGNED(s->max_write_zero,
452430b26a8SEric Blake                           MAX(s->opt_write_zero, align)))) {
453430b26a8SEric Blake         error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
454430b26a8SEric Blake                    s->max_write_zero);
455430b26a8SEric Blake         goto out;
456430b26a8SEric Blake     }
457430b26a8SEric Blake 
458430b26a8SEric Blake     s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
459430b26a8SEric Blake     if (s->opt_discard &&
460430b26a8SEric Blake         (s->opt_discard >= INT_MAX ||
461430b26a8SEric Blake          !QEMU_IS_ALIGNED(s->opt_discard, align))) {
462430b26a8SEric Blake         error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
463430b26a8SEric Blake                    s->opt_discard);
464430b26a8SEric Blake         goto out;
465430b26a8SEric Blake     }
466430b26a8SEric Blake 
467430b26a8SEric Blake     s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
468430b26a8SEric Blake     if (s->max_discard &&
469430b26a8SEric Blake         (s->max_discard >= INT_MAX ||
470430b26a8SEric Blake          !QEMU_IS_ALIGNED(s->max_discard,
471430b26a8SEric Blake                           MAX(s->opt_discard, align)))) {
472430b26a8SEric Blake         error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
473430b26a8SEric Blake                    s->max_discard);
474430b26a8SEric Blake         goto out;
475430b26a8SEric Blake     }
476b35ee7fbSKevin Wolf 
477f4681212SKevin Wolf     ret = 0;
478eaf944a4SKevin Wolf out:
479036990d7SMax Reitz     if (ret < 0) {
480036990d7SMax Reitz         g_free(s->config_file);
481036990d7SMax Reitz     }
482f4681212SKevin Wolf     qemu_opts_del(opts);
483f4681212SKevin Wolf     return ret;
4846a143727SKevin Wolf }
4856a143727SKevin Wolf 
486d157ed5fSEric Blake static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
487b9f66d96SKevin Wolf {
488b9f66d96SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
489d157ed5fSEric Blake     BlkdebugRule *rule = NULL;
490d157ed5fSEric Blake     int error;
491d157ed5fSEric Blake     bool immediately;
492d157ed5fSEric Blake 
493d157ed5fSEric Blake     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
494d157ed5fSEric Blake         uint64_t inject_offset = rule->options.inject.offset;
495d157ed5fSEric Blake 
496d157ed5fSEric Blake         if (inject_offset == -1 ||
497d157ed5fSEric Blake             (bytes && inject_offset >= offset &&
498d157ed5fSEric Blake              inject_offset < offset + bytes))
499d157ed5fSEric Blake         {
500d157ed5fSEric Blake             break;
501d157ed5fSEric Blake         }
502d157ed5fSEric Blake     }
503d157ed5fSEric Blake 
504d157ed5fSEric Blake     if (!rule || !rule->options.inject.error) {
505d157ed5fSEric Blake         return 0;
506d157ed5fSEric Blake     }
507d157ed5fSEric Blake 
508d157ed5fSEric Blake     immediately = rule->options.inject.immediately;
509d157ed5fSEric Blake     error = rule->options.inject.error;
510b9f66d96SKevin Wolf 
511571cd43eSPaolo Bonzini     if (rule->options.inject.once) {
512a069e2f1SJohn Snow         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
513a069e2f1SJohn Snow         remove_rule(rule);
514b9f66d96SKevin Wolf     }
515b9f66d96SKevin Wolf 
5167c3a9985SKevin Wolf     if (!immediately) {
517e5c67ab5SPaolo Bonzini         aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
5187c3a9985SKevin Wolf         qemu_coroutine_yield();
519b9f66d96SKevin Wolf     }
520b9f66d96SKevin Wolf 
5217c3a9985SKevin Wolf     return -error;
522b9f66d96SKevin Wolf }
523b9f66d96SKevin Wolf 
5247c3a9985SKevin Wolf static int coroutine_fn
5257c3a9985SKevin Wolf blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
5267c3a9985SKevin Wolf                    QEMUIOVector *qiov, int flags)
5276a143727SKevin Wolf {
528d157ed5fSEric Blake     int err;
529e4780db4SPaolo Bonzini 
530e0ef4395SEric Blake     /* Sanity check block layer guarantees */
531e0ef4395SEric Blake     assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
532e0ef4395SEric Blake     assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
533e0ef4395SEric Blake     if (bs->bl.max_transfer) {
534e0ef4395SEric Blake         assert(bytes <= bs->bl.max_transfer);
535e0ef4395SEric Blake     }
536e0ef4395SEric Blake 
537d157ed5fSEric Blake     err = rule_check(bs, offset, bytes);
538d157ed5fSEric Blake     if (err) {
539d157ed5fSEric Blake         return err;
540b9f66d96SKevin Wolf     }
541b9f66d96SKevin Wolf 
5427c3a9985SKevin Wolf     return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
5436a143727SKevin Wolf }
5446a143727SKevin Wolf 
5457c3a9985SKevin Wolf static int coroutine_fn
5467c3a9985SKevin Wolf blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
5477c3a9985SKevin Wolf                     QEMUIOVector *qiov, int flags)
5486a143727SKevin Wolf {
549d157ed5fSEric Blake     int err;
550e4780db4SPaolo Bonzini 
551e0ef4395SEric Blake     /* Sanity check block layer guarantees */
552e0ef4395SEric Blake     assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
553e0ef4395SEric Blake     assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
554e0ef4395SEric Blake     if (bs->bl.max_transfer) {
555e0ef4395SEric Blake         assert(bytes <= bs->bl.max_transfer);
556e0ef4395SEric Blake     }
557e0ef4395SEric Blake 
558d157ed5fSEric Blake     err = rule_check(bs, offset, bytes);
559d157ed5fSEric Blake     if (err) {
560d157ed5fSEric Blake         return err;
561b9f66d96SKevin Wolf     }
562b9f66d96SKevin Wolf 
5637c3a9985SKevin Wolf     return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
5646a143727SKevin Wolf }
5656a143727SKevin Wolf 
5667c3a9985SKevin Wolf static int blkdebug_co_flush(BlockDriverState *bs)
5679e52c53bSPaolo Bonzini {
568d157ed5fSEric Blake     int err = rule_check(bs, 0, 0);
5699e52c53bSPaolo Bonzini 
570d157ed5fSEric Blake     if (err) {
571d157ed5fSEric Blake         return err;
5729e52c53bSPaolo Bonzini     }
5739e52c53bSPaolo Bonzini 
5747c3a9985SKevin Wolf     return bdrv_co_flush(bs->file->bs);
5759e52c53bSPaolo Bonzini }
5769e52c53bSPaolo Bonzini 
57763188c24SEric Blake static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
578f5a5ca79SManos Pitsidianakis                                                   int64_t offset, int bytes,
57963188c24SEric Blake                                                   BdrvRequestFlags flags)
58063188c24SEric Blake {
58163188c24SEric Blake     uint32_t align = MAX(bs->bl.request_alignment,
58263188c24SEric Blake                          bs->bl.pwrite_zeroes_alignment);
58363188c24SEric Blake     int err;
58463188c24SEric Blake 
58563188c24SEric Blake     /* Only pass through requests that are larger than requested
58663188c24SEric Blake      * preferred alignment (so that we test the fallback to writes on
58763188c24SEric Blake      * unaligned portions), and check that the block layer never hands
58863188c24SEric Blake      * us anything unaligned that crosses an alignment boundary.  */
589f5a5ca79SManos Pitsidianakis     if (bytes < align) {
59063188c24SEric Blake         assert(QEMU_IS_ALIGNED(offset, align) ||
591f5a5ca79SManos Pitsidianakis                QEMU_IS_ALIGNED(offset + bytes, align) ||
59263188c24SEric Blake                DIV_ROUND_UP(offset, align) ==
593f5a5ca79SManos Pitsidianakis                DIV_ROUND_UP(offset + bytes, align));
59463188c24SEric Blake         return -ENOTSUP;
59563188c24SEric Blake     }
59663188c24SEric Blake     assert(QEMU_IS_ALIGNED(offset, align));
597f5a5ca79SManos Pitsidianakis     assert(QEMU_IS_ALIGNED(bytes, align));
59863188c24SEric Blake     if (bs->bl.max_pwrite_zeroes) {
599f5a5ca79SManos Pitsidianakis         assert(bytes <= bs->bl.max_pwrite_zeroes);
60063188c24SEric Blake     }
60163188c24SEric Blake 
602f5a5ca79SManos Pitsidianakis     err = rule_check(bs, offset, bytes);
60363188c24SEric Blake     if (err) {
60463188c24SEric Blake         return err;
60563188c24SEric Blake     }
60663188c24SEric Blake 
607f5a5ca79SManos Pitsidianakis     return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
60863188c24SEric Blake }
60963188c24SEric Blake 
61063188c24SEric Blake static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
611f5a5ca79SManos Pitsidianakis                                              int64_t offset, int bytes)
61263188c24SEric Blake {
61363188c24SEric Blake     uint32_t align = bs->bl.pdiscard_alignment;
61463188c24SEric Blake     int err;
61563188c24SEric Blake 
61663188c24SEric Blake     /* Only pass through requests that are larger than requested
61763188c24SEric Blake      * minimum alignment, and ensure that unaligned requests do not
61863188c24SEric Blake      * cross optimum discard boundaries. */
619f5a5ca79SManos Pitsidianakis     if (bytes < bs->bl.request_alignment) {
62063188c24SEric Blake         assert(QEMU_IS_ALIGNED(offset, align) ||
621f5a5ca79SManos Pitsidianakis                QEMU_IS_ALIGNED(offset + bytes, align) ||
62263188c24SEric Blake                DIV_ROUND_UP(offset, align) ==
623f5a5ca79SManos Pitsidianakis                DIV_ROUND_UP(offset + bytes, align));
62463188c24SEric Blake         return -ENOTSUP;
62563188c24SEric Blake     }
62663188c24SEric Blake     assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
627f5a5ca79SManos Pitsidianakis     assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
628f5a5ca79SManos Pitsidianakis     if (align && bytes >= align) {
62963188c24SEric Blake         assert(QEMU_IS_ALIGNED(offset, align));
630f5a5ca79SManos Pitsidianakis         assert(QEMU_IS_ALIGNED(bytes, align));
63163188c24SEric Blake     }
63263188c24SEric Blake     if (bs->bl.max_pdiscard) {
633f5a5ca79SManos Pitsidianakis         assert(bytes <= bs->bl.max_pdiscard);
63463188c24SEric Blake     }
63563188c24SEric Blake 
636f5a5ca79SManos Pitsidianakis     err = rule_check(bs, offset, bytes);
63763188c24SEric Blake     if (err) {
63863188c24SEric Blake         return err;
63963188c24SEric Blake     }
64063188c24SEric Blake 
641f5a5ca79SManos Pitsidianakis     return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
64263188c24SEric Blake }
6433c90c65dSKevin Wolf 
6446a143727SKevin Wolf static void blkdebug_close(BlockDriverState *bs)
6456a143727SKevin Wolf {
6466a143727SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6478b9b0cc2SKevin Wolf     BlkdebugRule *rule, *next;
6488b9b0cc2SKevin Wolf     int i;
6498b9b0cc2SKevin Wolf 
6507fb1cf16SEric Blake     for (i = 0; i < BLKDBG__MAX; i++) {
6518b9b0cc2SKevin Wolf         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
6529e35542bSKevin Wolf             remove_rule(rule);
6538b9b0cc2SKevin Wolf         }
6548b9b0cc2SKevin Wolf     }
655036990d7SMax Reitz 
656036990d7SMax Reitz     g_free(s->config_file);
6576a143727SKevin Wolf }
6586a143727SKevin Wolf 
6593c90c65dSKevin Wolf static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
6603c90c65dSKevin Wolf {
6613c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6623c90c65dSKevin Wolf     BlkdebugSuspendedReq r;
6633c90c65dSKevin Wolf 
6643c90c65dSKevin Wolf     r = (BlkdebugSuspendedReq) {
6653c90c65dSKevin Wolf         .co         = qemu_coroutine_self(),
6663c90c65dSKevin Wolf         .tag        = g_strdup(rule->options.suspend.tag),
6673c90c65dSKevin Wolf     };
6683c90c65dSKevin Wolf 
6693c90c65dSKevin Wolf     remove_rule(rule);
6703c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
6713c90c65dSKevin Wolf 
67220873526SMichael S. Tsirkin     if (!qtest_enabled()) {
6733c90c65dSKevin Wolf         printf("blkdebug: Suspended request '%s'\n", r.tag);
67420873526SMichael S. Tsirkin     }
6753c90c65dSKevin Wolf     qemu_coroutine_yield();
67620873526SMichael S. Tsirkin     if (!qtest_enabled()) {
6773c90c65dSKevin Wolf         printf("blkdebug: Resuming request '%s'\n", r.tag);
67820873526SMichael S. Tsirkin     }
6793c90c65dSKevin Wolf 
6803c90c65dSKevin Wolf     QLIST_REMOVE(&r, next);
6813c90c65dSKevin Wolf     g_free(r.tag);
6823c90c65dSKevin Wolf }
6833c90c65dSKevin Wolf 
684571cd43eSPaolo Bonzini static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
6858f96b5beSPaolo Bonzini     bool injected)
6868b9b0cc2SKevin Wolf {
6878b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
6888b9b0cc2SKevin Wolf 
6898b9b0cc2SKevin Wolf     /* Only process rules for the current state */
6908f96b5beSPaolo Bonzini     if (rule->state && rule->state != s->state) {
691571cd43eSPaolo Bonzini         return injected;
6928b9b0cc2SKevin Wolf     }
6938b9b0cc2SKevin Wolf 
6948b9b0cc2SKevin Wolf     /* Take the action */
6958b9b0cc2SKevin Wolf     switch (rule->action) {
6968b9b0cc2SKevin Wolf     case ACTION_INJECT_ERROR:
697571cd43eSPaolo Bonzini         if (!injected) {
698571cd43eSPaolo Bonzini             QSIMPLEQ_INIT(&s->active_rules);
699571cd43eSPaolo Bonzini             injected = true;
700571cd43eSPaolo Bonzini         }
701571cd43eSPaolo Bonzini         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
7028b9b0cc2SKevin Wolf         break;
7038b9b0cc2SKevin Wolf 
7048b9b0cc2SKevin Wolf     case ACTION_SET_STATE:
7058f96b5beSPaolo Bonzini         s->new_state = rule->options.set_state.new_state;
7068b9b0cc2SKevin Wolf         break;
7073c90c65dSKevin Wolf 
7083c90c65dSKevin Wolf     case ACTION_SUSPEND:
7093c90c65dSKevin Wolf         suspend_request(bs, rule);
7103c90c65dSKevin Wolf         break;
7118b9b0cc2SKevin Wolf     }
712571cd43eSPaolo Bonzini     return injected;
7138b9b0cc2SKevin Wolf }
7148b9b0cc2SKevin Wolf 
715a31939e6SEric Blake static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
7168b9b0cc2SKevin Wolf {
7178b9b0cc2SKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
7183c90c65dSKevin Wolf     struct BlkdebugRule *rule, *next;
719571cd43eSPaolo Bonzini     bool injected;
7208b9b0cc2SKevin Wolf 
7217fb1cf16SEric Blake     assert((int)event >= 0 && event < BLKDBG__MAX);
7228b9b0cc2SKevin Wolf 
723571cd43eSPaolo Bonzini     injected = false;
7248f96b5beSPaolo Bonzini     s->new_state = s->state;
7253c90c65dSKevin Wolf     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
7268f96b5beSPaolo Bonzini         injected = process_rule(bs, rule, injected);
7278b9b0cc2SKevin Wolf     }
7288f96b5beSPaolo Bonzini     s->state = s->new_state;
7298b9b0cc2SKevin Wolf }
7308b9b0cc2SKevin Wolf 
7313c90c65dSKevin Wolf static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
7323c90c65dSKevin Wolf                                      const char *tag)
7333c90c65dSKevin Wolf {
7343c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
7353c90c65dSKevin Wolf     struct BlkdebugRule *rule;
736a31939e6SEric Blake     BlkdebugEvent blkdebug_event;
7373c90c65dSKevin Wolf 
7383c90c65dSKevin Wolf     if (get_event_by_name(event, &blkdebug_event) < 0) {
7393c90c65dSKevin Wolf         return -ENOENT;
7403c90c65dSKevin Wolf     }
7413c90c65dSKevin Wolf 
7423c90c65dSKevin Wolf 
7433c90c65dSKevin Wolf     rule = g_malloc(sizeof(*rule));
7443c90c65dSKevin Wolf     *rule = (struct BlkdebugRule) {
7453c90c65dSKevin Wolf         .event  = blkdebug_event,
7463c90c65dSKevin Wolf         .action = ACTION_SUSPEND,
7473c90c65dSKevin Wolf         .state  = 0,
7483c90c65dSKevin Wolf         .options.suspend.tag = g_strdup(tag),
7493c90c65dSKevin Wolf     };
7503c90c65dSKevin Wolf 
7513c90c65dSKevin Wolf     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
7523c90c65dSKevin Wolf 
7533c90c65dSKevin Wolf     return 0;
7543c90c65dSKevin Wolf }
7553c90c65dSKevin Wolf 
7563c90c65dSKevin Wolf static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
7573c90c65dSKevin Wolf {
7583c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
759c547e564SFam Zheng     BlkdebugSuspendedReq *r, *next;
7603c90c65dSKevin Wolf 
761c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
7623c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
7630b8b8753SPaolo Bonzini             qemu_coroutine_enter(r->co);
7643c90c65dSKevin Wolf             return 0;
7653c90c65dSKevin Wolf         }
7663c90c65dSKevin Wolf     }
7673c90c65dSKevin Wolf     return -ENOENT;
7683c90c65dSKevin Wolf }
7693c90c65dSKevin Wolf 
7704cc70e93SFam Zheng static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
7714cc70e93SFam Zheng                                             const char *tag)
7724cc70e93SFam Zheng {
7734cc70e93SFam Zheng     BDRVBlkdebugState *s = bs->opaque;
774c547e564SFam Zheng     BlkdebugSuspendedReq *r, *r_next;
7754cc70e93SFam Zheng     BlkdebugRule *rule, *next;
7764cc70e93SFam Zheng     int i, ret = -ENOENT;
7774cc70e93SFam Zheng 
7787fb1cf16SEric Blake     for (i = 0; i < BLKDBG__MAX; i++) {
7794cc70e93SFam Zheng         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
7804cc70e93SFam Zheng             if (rule->action == ACTION_SUSPEND &&
7814cc70e93SFam Zheng                 !strcmp(rule->options.suspend.tag, tag)) {
7824cc70e93SFam Zheng                 remove_rule(rule);
7834cc70e93SFam Zheng                 ret = 0;
7844cc70e93SFam Zheng             }
7854cc70e93SFam Zheng         }
7864cc70e93SFam Zheng     }
787c547e564SFam Zheng     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
7884cc70e93SFam Zheng         if (!strcmp(r->tag, tag)) {
7890b8b8753SPaolo Bonzini             qemu_coroutine_enter(r->co);
7904cc70e93SFam Zheng             ret = 0;
7914cc70e93SFam Zheng         }
7924cc70e93SFam Zheng     }
7934cc70e93SFam Zheng     return ret;
7944cc70e93SFam Zheng }
7953c90c65dSKevin Wolf 
7963c90c65dSKevin Wolf static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
7973c90c65dSKevin Wolf {
7983c90c65dSKevin Wolf     BDRVBlkdebugState *s = bs->opaque;
7993c90c65dSKevin Wolf     BlkdebugSuspendedReq *r;
8003c90c65dSKevin Wolf 
8013c90c65dSKevin Wolf     QLIST_FOREACH(r, &s->suspended_reqs, next) {
8023c90c65dSKevin Wolf         if (!strcmp(r->tag, tag)) {
8033c90c65dSKevin Wolf             return true;
8043c90c65dSKevin Wolf         }
8053c90c65dSKevin Wolf     }
8063c90c65dSKevin Wolf     return false;
8073c90c65dSKevin Wolf }
8083c90c65dSKevin Wolf 
809e1302255SPaolo Bonzini static int64_t blkdebug_getlength(BlockDriverState *bs)
810e1302255SPaolo Bonzini {
8119a4f4c31SKevin Wolf     return bdrv_getlength(bs->file->bs);
812e1302255SPaolo Bonzini }
813e1302255SPaolo Bonzini 
8144bff28b8SMax Reitz static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
8158eedfbd4SKevin Wolf {
8164bff28b8SMax Reitz     return bdrv_truncate(bs->file, offset, errp);
8178eedfbd4SKevin Wolf }
8188eedfbd4SKevin Wolf 
8194cdd01d3SKevin Wolf static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
8202c31b04cSMax Reitz {
821036990d7SMax Reitz     BDRVBlkdebugState *s = bs->opaque;
8222c31b04cSMax Reitz     QDict *opts;
8238779441bSMax Reitz     const QDictEntry *e;
8248779441bSMax Reitz     bool force_json = false;
8252c31b04cSMax Reitz 
8264cdd01d3SKevin Wolf     for (e = qdict_first(options); e; e = qdict_next(options, e)) {
8278779441bSMax Reitz         if (strcmp(qdict_entry_key(e), "config") &&
8284cdd01d3SKevin Wolf             strcmp(qdict_entry_key(e), "x-image"))
8298779441bSMax Reitz         {
8308779441bSMax Reitz             force_json = true;
8318779441bSMax Reitz             break;
8328779441bSMax Reitz         }
8338779441bSMax Reitz     }
8348779441bSMax Reitz 
8359a4f4c31SKevin Wolf     if (force_json && !bs->file->bs->full_open_options) {
8362c31b04cSMax Reitz         /* The config file cannot be recreated, so creating a plain filename
8372c31b04cSMax Reitz          * is impossible */
8382c31b04cSMax Reitz         return;
8392c31b04cSMax Reitz     }
8402c31b04cSMax Reitz 
8419a4f4c31SKevin Wolf     if (!force_json && bs->file->bs->exact_filename[0]) {
842*de81d72dSMax Reitz         int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
843036990d7SMax Reitz                            "blkdebug:%s:%s", s->config_file ?: "",
8449a4f4c31SKevin Wolf                            bs->file->bs->exact_filename);
845*de81d72dSMax Reitz         if (ret >= sizeof(bs->exact_filename)) {
846*de81d72dSMax Reitz             /* An overflow makes the filename unusable, so do not report any */
847*de81d72dSMax Reitz             bs->exact_filename[0] = 0;
848*de81d72dSMax Reitz         }
8498779441bSMax Reitz     }
8508779441bSMax Reitz 
8512c31b04cSMax Reitz     opts = qdict_new();
85246f5ac20SEric Blake     qdict_put_str(opts, "driver", "blkdebug");
8532c31b04cSMax Reitz 
8549a4f4c31SKevin Wolf     QINCREF(bs->file->bs->full_open_options);
855de6e7951SEric Blake     qdict_put(opts, "image", bs->file->bs->full_open_options);
8562c31b04cSMax Reitz 
8574cdd01d3SKevin Wolf     for (e = qdict_first(options); e; e = qdict_next(options, e)) {
8584cdd01d3SKevin Wolf         if (strcmp(qdict_entry_key(e), "x-image")) {
8598779441bSMax Reitz             qobject_incref(qdict_entry_value(e));
8608779441bSMax Reitz             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
8612c31b04cSMax Reitz         }
8622c31b04cSMax Reitz     }
8632c31b04cSMax Reitz 
8642c31b04cSMax Reitz     bs->full_open_options = opts;
8652c31b04cSMax Reitz }
8662c31b04cSMax Reitz 
867835db3eeSEric Blake static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
868835db3eeSEric Blake {
869835db3eeSEric Blake     BDRVBlkdebugState *s = bs->opaque;
870835db3eeSEric Blake 
871835db3eeSEric Blake     if (s->align) {
872a5b8dd2cSEric Blake         bs->bl.request_alignment = s->align;
873835db3eeSEric Blake     }
874430b26a8SEric Blake     if (s->max_transfer) {
875430b26a8SEric Blake         bs->bl.max_transfer = s->max_transfer;
876430b26a8SEric Blake     }
877430b26a8SEric Blake     if (s->opt_write_zero) {
878430b26a8SEric Blake         bs->bl.pwrite_zeroes_alignment = s->opt_write_zero;
879430b26a8SEric Blake     }
880430b26a8SEric Blake     if (s->max_write_zero) {
881430b26a8SEric Blake         bs->bl.max_pwrite_zeroes = s->max_write_zero;
882430b26a8SEric Blake     }
883430b26a8SEric Blake     if (s->opt_discard) {
884430b26a8SEric Blake         bs->bl.pdiscard_alignment = s->opt_discard;
885430b26a8SEric Blake     }
886430b26a8SEric Blake     if (s->max_discard) {
887430b26a8SEric Blake         bs->bl.max_pdiscard = s->max_discard;
888430b26a8SEric Blake     }
889835db3eeSEric Blake }
890835db3eeSEric Blake 
891c5e8bfb7SKevin Wolf static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
892c5e8bfb7SKevin Wolf                                    BlockReopenQueue *queue, Error **errp)
893c5e8bfb7SKevin Wolf {
894c5e8bfb7SKevin Wolf     return 0;
895c5e8bfb7SKevin Wolf }
896c5e8bfb7SKevin Wolf 
8976a143727SKevin Wolf static BlockDriver bdrv_blkdebug = {
8986a143727SKevin Wolf     .format_name            = "blkdebug",
8996a143727SKevin Wolf     .protocol_name          = "blkdebug",
9006a143727SKevin Wolf     .instance_size          = sizeof(BDRVBlkdebugState),
9016a143727SKevin Wolf 
902f4681212SKevin Wolf     .bdrv_parse_filename    = blkdebug_parse_filename,
90366f82ceeSKevin Wolf     .bdrv_file_open         = blkdebug_open,
9046a143727SKevin Wolf     .bdrv_close             = blkdebug_close,
905c5e8bfb7SKevin Wolf     .bdrv_reopen_prepare    = blkdebug_reopen_prepare,
906d7010dfbSKevin Wolf     .bdrv_child_perm        = bdrv_filter_default_perms,
907d7010dfbSKevin Wolf 
908e1302255SPaolo Bonzini     .bdrv_getlength         = blkdebug_getlength,
9098eedfbd4SKevin Wolf     .bdrv_truncate          = blkdebug_truncate,
9102c31b04cSMax Reitz     .bdrv_refresh_filename  = blkdebug_refresh_filename,
911835db3eeSEric Blake     .bdrv_refresh_limits    = blkdebug_refresh_limits,
9126a143727SKevin Wolf 
9137c3a9985SKevin Wolf     .bdrv_co_preadv         = blkdebug_co_preadv,
9147c3a9985SKevin Wolf     .bdrv_co_pwritev        = blkdebug_co_pwritev,
9157c3a9985SKevin Wolf     .bdrv_co_flush_to_disk  = blkdebug_co_flush,
91663188c24SEric Blake     .bdrv_co_pwrite_zeroes  = blkdebug_co_pwrite_zeroes,
91763188c24SEric Blake     .bdrv_co_pdiscard       = blkdebug_co_pdiscard,
9188b9b0cc2SKevin Wolf 
9198b9b0cc2SKevin Wolf     .bdrv_debug_event           = blkdebug_debug_event,
9203c90c65dSKevin Wolf     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
9214cc70e93SFam Zheng     .bdrv_debug_remove_breakpoint
9224cc70e93SFam Zheng                                 = blkdebug_debug_remove_breakpoint,
9233c90c65dSKevin Wolf     .bdrv_debug_resume          = blkdebug_debug_resume,
9243c90c65dSKevin Wolf     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
9256a143727SKevin Wolf };
9266a143727SKevin Wolf 
9276a143727SKevin Wolf static void bdrv_blkdebug_init(void)
9286a143727SKevin Wolf {
9296a143727SKevin Wolf     bdrv_register(&bdrv_blkdebug);
9306a143727SKevin Wolf }
9316a143727SKevin Wolf 
9326a143727SKevin Wolf block_init(bdrv_blkdebug_init);
933