Statistics
| Branch: | Revision:

root / block / blkdebug.c @ 5d259fc7

History | View | Annotate | Download (19.9 kB)

1 6a143727 Kevin Wolf
/*
2 6a143727 Kevin Wolf
 * Block protocol for I/O error injection
3 6a143727 Kevin Wolf
 *
4 6a143727 Kevin Wolf
 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
5 6a143727 Kevin Wolf
 *
6 6a143727 Kevin Wolf
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 6a143727 Kevin Wolf
 * of this software and associated documentation files (the "Software"), to deal
8 6a143727 Kevin Wolf
 * in the Software without restriction, including without limitation the rights
9 6a143727 Kevin Wolf
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 6a143727 Kevin Wolf
 * copies of the Software, and to permit persons to whom the Software is
11 6a143727 Kevin Wolf
 * furnished to do so, subject to the following conditions:
12 6a143727 Kevin Wolf
 *
13 6a143727 Kevin Wolf
 * The above copyright notice and this permission notice shall be included in
14 6a143727 Kevin Wolf
 * all copies or substantial portions of the Software.
15 6a143727 Kevin Wolf
 *
16 6a143727 Kevin Wolf
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 6a143727 Kevin Wolf
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 6a143727 Kevin Wolf
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 6a143727 Kevin Wolf
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 6a143727 Kevin Wolf
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 6a143727 Kevin Wolf
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 6a143727 Kevin Wolf
 * THE SOFTWARE.
23 6a143727 Kevin Wolf
 */
24 6a143727 Kevin Wolf
25 6a143727 Kevin Wolf
#include "qemu-common.h"
26 1de7afc9 Paolo Bonzini
#include "qemu/config-file.h"
27 737e150e Paolo Bonzini
#include "block/block_int.h"
28 1de7afc9 Paolo Bonzini
#include "qemu/module.h"
29 6a143727 Kevin Wolf
30 6a143727 Kevin Wolf
typedef struct BDRVBlkdebugState {
31 571cd43e Paolo Bonzini
    int state;
32 8f96b5be Paolo Bonzini
    int new_state;
33 3c90c65d Kevin Wolf
34 571cd43e Paolo Bonzini
    QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
35 571cd43e Paolo Bonzini
    QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
36 3c90c65d Kevin Wolf
    QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
37 6a143727 Kevin Wolf
} BDRVBlkdebugState;
38 6a143727 Kevin Wolf
39 b9f66d96 Kevin Wolf
typedef struct BlkdebugAIOCB {
40 b9f66d96 Kevin Wolf
    BlockDriverAIOCB common;
41 b9f66d96 Kevin Wolf
    QEMUBH *bh;
42 b9f66d96 Kevin Wolf
    int ret;
43 b9f66d96 Kevin Wolf
} BlkdebugAIOCB;
44 b9f66d96 Kevin Wolf
45 3c90c65d Kevin Wolf
typedef struct BlkdebugSuspendedReq {
46 3c90c65d Kevin Wolf
    Coroutine *co;
47 3c90c65d Kevin Wolf
    char *tag;
48 3c90c65d Kevin Wolf
    QLIST_ENTRY(BlkdebugSuspendedReq) next;
49 3c90c65d Kevin Wolf
} BlkdebugSuspendedReq;
50 3c90c65d Kevin Wolf
51 b9f66d96 Kevin Wolf
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
52 b9f66d96 Kevin Wolf
53 d7331bed Stefan Hajnoczi
static const AIOCBInfo blkdebug_aiocb_info = {
54 b9f66d96 Kevin Wolf
    .aiocb_size = sizeof(BlkdebugAIOCB),
55 b9f66d96 Kevin Wolf
    .cancel     = blkdebug_aio_cancel,
56 b9f66d96 Kevin Wolf
};
57 b9f66d96 Kevin Wolf
58 8b9b0cc2 Kevin Wolf
enum {
59 8b9b0cc2 Kevin Wolf
    ACTION_INJECT_ERROR,
60 8b9b0cc2 Kevin Wolf
    ACTION_SET_STATE,
61 3c90c65d Kevin Wolf
    ACTION_SUSPEND,
62 8b9b0cc2 Kevin Wolf
};
63 8b9b0cc2 Kevin Wolf
64 8b9b0cc2 Kevin Wolf
typedef struct BlkdebugRule {
65 8b9b0cc2 Kevin Wolf
    BlkDebugEvent event;
66 8b9b0cc2 Kevin Wolf
    int action;
67 8b9b0cc2 Kevin Wolf
    int state;
68 8b9b0cc2 Kevin Wolf
    union {
69 8b9b0cc2 Kevin Wolf
        struct {
70 8b9b0cc2 Kevin Wolf
            int error;
71 8b9b0cc2 Kevin Wolf
            int immediately;
72 8b9b0cc2 Kevin Wolf
            int once;
73 e4780db4 Paolo Bonzini
            int64_t sector;
74 8b9b0cc2 Kevin Wolf
        } inject;
75 8b9b0cc2 Kevin Wolf
        struct {
76 8b9b0cc2 Kevin Wolf
            int new_state;
77 8b9b0cc2 Kevin Wolf
        } set_state;
78 3c90c65d Kevin Wolf
        struct {
79 3c90c65d Kevin Wolf
            char *tag;
80 3c90c65d Kevin Wolf
        } suspend;
81 8b9b0cc2 Kevin Wolf
    } options;
82 8b9b0cc2 Kevin Wolf
    QLIST_ENTRY(BlkdebugRule) next;
83 571cd43e Paolo Bonzini
    QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
84 8b9b0cc2 Kevin Wolf
} BlkdebugRule;
85 8b9b0cc2 Kevin Wolf
86 8b9b0cc2 Kevin Wolf
static QemuOptsList inject_error_opts = {
87 8b9b0cc2 Kevin Wolf
    .name = "inject-error",
88 8b9b0cc2 Kevin Wolf
    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
89 8b9b0cc2 Kevin Wolf
    .desc = {
90 8b9b0cc2 Kevin Wolf
        {
91 8b9b0cc2 Kevin Wolf
            .name = "event",
92 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_STRING,
93 8b9b0cc2 Kevin Wolf
        },
94 8b9b0cc2 Kevin Wolf
        {
95 8b9b0cc2 Kevin Wolf
            .name = "state",
96 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_NUMBER,
97 8b9b0cc2 Kevin Wolf
        },
98 8b9b0cc2 Kevin Wolf
        {
99 8b9b0cc2 Kevin Wolf
            .name = "errno",
100 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_NUMBER,
101 8b9b0cc2 Kevin Wolf
        },
102 8b9b0cc2 Kevin Wolf
        {
103 e4780db4 Paolo Bonzini
            .name = "sector",
104 e4780db4 Paolo Bonzini
            .type = QEMU_OPT_NUMBER,
105 e4780db4 Paolo Bonzini
        },
106 e4780db4 Paolo Bonzini
        {
107 8b9b0cc2 Kevin Wolf
            .name = "once",
108 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_BOOL,
109 8b9b0cc2 Kevin Wolf
        },
110 8b9b0cc2 Kevin Wolf
        {
111 8b9b0cc2 Kevin Wolf
            .name = "immediately",
112 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_BOOL,
113 8b9b0cc2 Kevin Wolf
        },
114 8b9b0cc2 Kevin Wolf
        { /* end of list */ }
115 8b9b0cc2 Kevin Wolf
    },
116 8b9b0cc2 Kevin Wolf
};
117 8b9b0cc2 Kevin Wolf
118 8b9b0cc2 Kevin Wolf
static QemuOptsList set_state_opts = {
119 8b9b0cc2 Kevin Wolf
    .name = "set-state",
120 327cdad4 Kevin Wolf
    .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
121 8b9b0cc2 Kevin Wolf
    .desc = {
122 8b9b0cc2 Kevin Wolf
        {
123 8b9b0cc2 Kevin Wolf
            .name = "event",
124 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_STRING,
125 8b9b0cc2 Kevin Wolf
        },
126 8b9b0cc2 Kevin Wolf
        {
127 8b9b0cc2 Kevin Wolf
            .name = "state",
128 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_NUMBER,
129 8b9b0cc2 Kevin Wolf
        },
130 8b9b0cc2 Kevin Wolf
        {
131 8b9b0cc2 Kevin Wolf
            .name = "new_state",
132 8b9b0cc2 Kevin Wolf
            .type = QEMU_OPT_NUMBER,
133 8b9b0cc2 Kevin Wolf
        },
134 8b9b0cc2 Kevin Wolf
        { /* end of list */ }
135 8b9b0cc2 Kevin Wolf
    },
136 8b9b0cc2 Kevin Wolf
};
137 8b9b0cc2 Kevin Wolf
138 8b9b0cc2 Kevin Wolf
static QemuOptsList *config_groups[] = {
139 8b9b0cc2 Kevin Wolf
    &inject_error_opts,
140 8b9b0cc2 Kevin Wolf
    &set_state_opts,
141 8b9b0cc2 Kevin Wolf
    NULL
142 8b9b0cc2 Kevin Wolf
};
143 8b9b0cc2 Kevin Wolf
144 8b9b0cc2 Kevin Wolf
static const char *event_names[BLKDBG_EVENT_MAX] = {
145 8252278a Kevin Wolf
    [BLKDBG_L1_UPDATE]                      = "l1_update",
146 8252278a Kevin Wolf
    [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
147 8252278a Kevin Wolf
    [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
148 8252278a Kevin Wolf
    [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
149 8252278a Kevin Wolf
150 8252278a Kevin Wolf
    [BLKDBG_L2_LOAD]                        = "l2_load",
151 8252278a Kevin Wolf
    [BLKDBG_L2_UPDATE]                      = "l2_update",
152 8252278a Kevin Wolf
    [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
153 8252278a Kevin Wolf
    [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
154 8252278a Kevin Wolf
    [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
155 8252278a Kevin Wolf
156 8252278a Kevin Wolf
    [BLKDBG_READ_AIO]                       = "read_aio",
157 8252278a Kevin Wolf
    [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
158 8252278a Kevin Wolf
    [BLKDBG_READ_COMPRESSED]                = "read_compressed",
159 8252278a Kevin Wolf
160 8252278a Kevin Wolf
    [BLKDBG_WRITE_AIO]                      = "write_aio",
161 8252278a Kevin Wolf
    [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
162 8252278a Kevin Wolf
163 8252278a Kevin Wolf
    [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
164 8252278a Kevin Wolf
    [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
165 8252278a Kevin Wolf
166 8252278a Kevin Wolf
    [BLKDBG_COW_READ]                       = "cow_read",
167 8252278a Kevin Wolf
    [BLKDBG_COW_WRITE]                      = "cow_write",
168 8252278a Kevin Wolf
169 8252278a Kevin Wolf
    [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
170 8252278a Kevin Wolf
    [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
171 afa50193 Max Reitz
    [BLKDBG_REFTABLE_UPDATE]                = "reftable_update",
172 8252278a Kevin Wolf
173 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
174 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
175 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
176 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
177 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
178 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
179 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
180 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
181 8252278a Kevin Wolf
    [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
182 8252278a Kevin Wolf
183 8252278a Kevin Wolf
    [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
184 8252278a Kevin Wolf
    [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
185 8252278a Kevin Wolf
    [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
186 bf736fe3 Kevin Wolf
187 bf736fe3 Kevin Wolf
    [BLKDBG_FLUSH_TO_OS]                    = "flush_to_os",
188 bf736fe3 Kevin Wolf
    [BLKDBG_FLUSH_TO_DISK]                  = "flush_to_disk",
189 9e1cb96d Kevin Wolf
190 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV_RMW_HEAD]               = "pwritev_rmw.head",
191 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV_RMW_AFTER_HEAD]         = "pwritev_rmw.after_head",
192 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV_RMW_TAIL]               = "pwritev_rmw.tail",
193 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV_RMW_AFTER_TAIL]         = "pwritev_rmw.after_tail",
194 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV]                        = "pwritev",
195 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV_ZERO]                   = "pwritev_zero",
196 9e1cb96d Kevin Wolf
    [BLKDBG_PWRITEV_DONE]                   = "pwritev_done",
197 8b9b0cc2 Kevin Wolf
};
198 8b9b0cc2 Kevin Wolf
199 8b9b0cc2 Kevin Wolf
static int get_event_by_name(const char *name, BlkDebugEvent *event)
200 8b9b0cc2 Kevin Wolf
{
201 8b9b0cc2 Kevin Wolf
    int i;
202 8b9b0cc2 Kevin Wolf
203 8b9b0cc2 Kevin Wolf
    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
204 8b9b0cc2 Kevin Wolf
        if (!strcmp(event_names[i], name)) {
205 8b9b0cc2 Kevin Wolf
            *event = i;
206 8b9b0cc2 Kevin Wolf
            return 0;
207 8b9b0cc2 Kevin Wolf
        }
208 8b9b0cc2 Kevin Wolf
    }
209 8b9b0cc2 Kevin Wolf
210 8b9b0cc2 Kevin Wolf
    return -1;
211 8b9b0cc2 Kevin Wolf
}
212 8b9b0cc2 Kevin Wolf
213 8b9b0cc2 Kevin Wolf
struct add_rule_data {
214 8b9b0cc2 Kevin Wolf
    BDRVBlkdebugState *s;
215 8b9b0cc2 Kevin Wolf
    int action;
216 8b9b0cc2 Kevin Wolf
};
217 8b9b0cc2 Kevin Wolf
218 8b9b0cc2 Kevin Wolf
static int add_rule(QemuOpts *opts, void *opaque)
219 8b9b0cc2 Kevin Wolf
{
220 8b9b0cc2 Kevin Wolf
    struct add_rule_data *d = opaque;
221 8b9b0cc2 Kevin Wolf
    BDRVBlkdebugState *s = d->s;
222 8b9b0cc2 Kevin Wolf
    const char* event_name;
223 8b9b0cc2 Kevin Wolf
    BlkDebugEvent event;
224 8b9b0cc2 Kevin Wolf
    struct BlkdebugRule *rule;
225 8b9b0cc2 Kevin Wolf
226 8b9b0cc2 Kevin Wolf
    /* Find the right event for the rule */
227 8b9b0cc2 Kevin Wolf
    event_name = qemu_opt_get(opts, "event");
228 8b9b0cc2 Kevin Wolf
    if (!event_name || get_event_by_name(event_name, &event) < 0) {
229 8b9b0cc2 Kevin Wolf
        return -1;
230 8b9b0cc2 Kevin Wolf
    }
231 8b9b0cc2 Kevin Wolf
232 8b9b0cc2 Kevin Wolf
    /* Set attributes common for all actions */
233 7267c094 Anthony Liguori
    rule = g_malloc0(sizeof(*rule));
234 8b9b0cc2 Kevin Wolf
    *rule = (struct BlkdebugRule) {
235 8b9b0cc2 Kevin Wolf
        .event  = event,
236 8b9b0cc2 Kevin Wolf
        .action = d->action,
237 8b9b0cc2 Kevin Wolf
        .state  = qemu_opt_get_number(opts, "state", 0),
238 8b9b0cc2 Kevin Wolf
    };
239 8b9b0cc2 Kevin Wolf
240 8b9b0cc2 Kevin Wolf
    /* Parse action-specific options */
241 8b9b0cc2 Kevin Wolf
    switch (d->action) {
242 8b9b0cc2 Kevin Wolf
    case ACTION_INJECT_ERROR:
243 8b9b0cc2 Kevin Wolf
        rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
244 8b9b0cc2 Kevin Wolf
        rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
245 8b9b0cc2 Kevin Wolf
        rule->options.inject.immediately =
246 8b9b0cc2 Kevin Wolf
            qemu_opt_get_bool(opts, "immediately", 0);
247 e4780db4 Paolo Bonzini
        rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
248 8b9b0cc2 Kevin Wolf
        break;
249 8b9b0cc2 Kevin Wolf
250 8b9b0cc2 Kevin Wolf
    case ACTION_SET_STATE:
251 8b9b0cc2 Kevin Wolf
        rule->options.set_state.new_state =
252 8b9b0cc2 Kevin Wolf
            qemu_opt_get_number(opts, "new_state", 0);
253 8b9b0cc2 Kevin Wolf
        break;
254 3c90c65d Kevin Wolf
255 3c90c65d Kevin Wolf
    case ACTION_SUSPEND:
256 3c90c65d Kevin Wolf
        rule->options.suspend.tag =
257 3c90c65d Kevin Wolf
            g_strdup(qemu_opt_get(opts, "tag"));
258 3c90c65d Kevin Wolf
        break;
259 8b9b0cc2 Kevin Wolf
    };
260 8b9b0cc2 Kevin Wolf
261 8b9b0cc2 Kevin Wolf
    /* Add the rule */
262 8b9b0cc2 Kevin Wolf
    QLIST_INSERT_HEAD(&s->rules[event], rule, next);
263 8b9b0cc2 Kevin Wolf
264 8b9b0cc2 Kevin Wolf
    return 0;
265 8b9b0cc2 Kevin Wolf
}
266 8b9b0cc2 Kevin Wolf
267 9e35542b Kevin Wolf
static void remove_rule(BlkdebugRule *rule)
268 9e35542b Kevin Wolf
{
269 9e35542b Kevin Wolf
    switch (rule->action) {
270 9e35542b Kevin Wolf
    case ACTION_INJECT_ERROR:
271 9e35542b Kevin Wolf
    case ACTION_SET_STATE:
272 9e35542b Kevin Wolf
        break;
273 3c90c65d Kevin Wolf
    case ACTION_SUSPEND:
274 3c90c65d Kevin Wolf
        g_free(rule->options.suspend.tag);
275 3c90c65d Kevin Wolf
        break;
276 9e35542b Kevin Wolf
    }
277 9e35542b Kevin Wolf
278 9e35542b Kevin Wolf
    QLIST_REMOVE(rule, next);
279 9e35542b Kevin Wolf
    g_free(rule);
280 9e35542b Kevin Wolf
}
281 9e35542b Kevin Wolf
282 89f2b21e Max Reitz
static int read_config(BDRVBlkdebugState *s, const char *filename,
283 89f2b21e Max Reitz
                       QDict *options, Error **errp)
284 8b9b0cc2 Kevin Wolf
{
285 85a040e5 Max Reitz
    FILE *f = NULL;
286 8b9b0cc2 Kevin Wolf
    int ret;
287 8b9b0cc2 Kevin Wolf
    struct add_rule_data d;
288 89f2b21e Max Reitz
    Error *local_err = NULL;
289 8b9b0cc2 Kevin Wolf
290 85a040e5 Max Reitz
    if (filename) {
291 85a040e5 Max Reitz
        f = fopen(filename, "r");
292 85a040e5 Max Reitz
        if (f == NULL) {
293 85a040e5 Max Reitz
            error_setg_errno(errp, errno, "Could not read blkdebug config file");
294 85a040e5 Max Reitz
            return -errno;
295 85a040e5 Max Reitz
        }
296 8b9b0cc2 Kevin Wolf
297 85a040e5 Max Reitz
        ret = qemu_config_parse(f, config_groups, filename);
298 85a040e5 Max Reitz
        if (ret < 0) {
299 85a040e5 Max Reitz
            error_setg(errp, "Could not parse blkdebug config file");
300 85a040e5 Max Reitz
            ret = -EINVAL;
301 85a040e5 Max Reitz
            goto fail;
302 85a040e5 Max Reitz
        }
303 8b9b0cc2 Kevin Wolf
    }
304 8b9b0cc2 Kevin Wolf
305 89f2b21e Max Reitz
    qemu_config_parse_qdict(options, config_groups, &local_err);
306 89f2b21e Max Reitz
    if (error_is_set(&local_err)) {
307 89f2b21e Max Reitz
        error_propagate(errp, local_err);
308 89f2b21e Max Reitz
        ret = -EINVAL;
309 89f2b21e Max Reitz
        goto fail;
310 89f2b21e Max Reitz
    }
311 89f2b21e Max Reitz
312 8b9b0cc2 Kevin Wolf
    d.s = s;
313 8b9b0cc2 Kevin Wolf
    d.action = ACTION_INJECT_ERROR;
314 8b9b0cc2 Kevin Wolf
    qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
315 8b9b0cc2 Kevin Wolf
316 8b9b0cc2 Kevin Wolf
    d.action = ACTION_SET_STATE;
317 8b9b0cc2 Kevin Wolf
    qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
318 8b9b0cc2 Kevin Wolf
319 8b9b0cc2 Kevin Wolf
    ret = 0;
320 8b9b0cc2 Kevin Wolf
fail:
321 698f0d52 Kevin Wolf
    qemu_opts_reset(&inject_error_opts);
322 698f0d52 Kevin Wolf
    qemu_opts_reset(&set_state_opts);
323 85a040e5 Max Reitz
    if (f) {
324 85a040e5 Max Reitz
        fclose(f);
325 85a040e5 Max Reitz
    }
326 8b9b0cc2 Kevin Wolf
    return ret;
327 8b9b0cc2 Kevin Wolf
}
328 8b9b0cc2 Kevin Wolf
329 8b9b0cc2 Kevin Wolf
/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
330 f4681212 Kevin Wolf
static void blkdebug_parse_filename(const char *filename, QDict *options,
331 f4681212 Kevin Wolf
                                    Error **errp)
332 6a143727 Kevin Wolf
{
333 f4681212 Kevin Wolf
    const char *c;
334 6a143727 Kevin Wolf
335 8b9b0cc2 Kevin Wolf
    /* Parse the blkdebug: prefix */
336 f4681212 Kevin Wolf
    if (!strstart(filename, "blkdebug:", &filename)) {
337 d4881b9b Max Reitz
        /* There was no prefix; therefore, all options have to be already
338 d4881b9b Max Reitz
           present in the QDict (except for the filename) */
339 d4881b9b Max Reitz
        qdict_put(options, "x-image", qstring_from_str(filename));
340 f4681212 Kevin Wolf
        return;
341 6a143727 Kevin Wolf
    }
342 6a143727 Kevin Wolf
343 f4681212 Kevin Wolf
    /* Parse config file path */
344 8b9b0cc2 Kevin Wolf
    c = strchr(filename, ':');
345 8b9b0cc2 Kevin Wolf
    if (c == NULL) {
346 f4681212 Kevin Wolf
        error_setg(errp, "blkdebug requires both config file and image path");
347 f4681212 Kevin Wolf
        return;
348 8b9b0cc2 Kevin Wolf
    }
349 8b9b0cc2 Kevin Wolf
350 f4681212 Kevin Wolf
    if (c != filename) {
351 f4681212 Kevin Wolf
        QString *config_path;
352 f4681212 Kevin Wolf
        config_path = qstring_from_substr(filename, 0, c - filename - 1);
353 f4681212 Kevin Wolf
        qdict_put(options, "config", config_path);
354 8b9b0cc2 Kevin Wolf
    }
355 f4681212 Kevin Wolf
356 f4681212 Kevin Wolf
    /* TODO Allow multi-level nesting and set file.filename here */
357 8b9b0cc2 Kevin Wolf
    filename = c + 1;
358 f4681212 Kevin Wolf
    qdict_put(options, "x-image", qstring_from_str(filename));
359 f4681212 Kevin Wolf
}
360 f4681212 Kevin Wolf
361 f4681212 Kevin Wolf
static QemuOptsList runtime_opts = {
362 f4681212 Kevin Wolf
    .name = "blkdebug",
363 f4681212 Kevin Wolf
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
364 f4681212 Kevin Wolf
    .desc = {
365 f4681212 Kevin Wolf
        {
366 f4681212 Kevin Wolf
            .name = "config",
367 f4681212 Kevin Wolf
            .type = QEMU_OPT_STRING,
368 f4681212 Kevin Wolf
            .help = "Path to the configuration file",
369 f4681212 Kevin Wolf
        },
370 f4681212 Kevin Wolf
        {
371 f4681212 Kevin Wolf
            .name = "x-image",
372 f4681212 Kevin Wolf
            .type = QEMU_OPT_STRING,
373 f4681212 Kevin Wolf
            .help = "[internal use only, will be removed]",
374 f4681212 Kevin Wolf
        },
375 b35ee7fb Kevin Wolf
        {
376 b35ee7fb Kevin Wolf
            .name = "align",
377 b35ee7fb Kevin Wolf
            .type = QEMU_OPT_SIZE,
378 b35ee7fb Kevin Wolf
            .help = "Required alignment in bytes",
379 b35ee7fb Kevin Wolf
        },
380 f4681212 Kevin Wolf
        { /* end of list */ }
381 f4681212 Kevin Wolf
    },
382 f4681212 Kevin Wolf
};
383 f4681212 Kevin Wolf
384 015a1036 Max Reitz
static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
385 015a1036 Max Reitz
                         Error **errp)
386 f4681212 Kevin Wolf
{
387 f4681212 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
388 f4681212 Kevin Wolf
    QemuOpts *opts;
389 f4681212 Kevin Wolf
    Error *local_err = NULL;
390 4373593d Max Reitz
    const char *config;
391 b35ee7fb Kevin Wolf
    uint64_t align;
392 f4681212 Kevin Wolf
    int ret;
393 f4681212 Kevin Wolf
394 87ea75d5 Peter Crosthwaite
    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
395 f4681212 Kevin Wolf
    qemu_opts_absorb_qdict(opts, options, &local_err);
396 f4681212 Kevin Wolf
    if (error_is_set(&local_err)) {
397 10ffa72f Max Reitz
        error_propagate(errp, local_err);
398 f4681212 Kevin Wolf
        ret = -EINVAL;
399 f4681212 Kevin Wolf
        goto fail;
400 f4681212 Kevin Wolf
    }
401 f4681212 Kevin Wolf
402 89f2b21e Max Reitz
    /* Read rules from config file or command line options */
403 f4681212 Kevin Wolf
    config = qemu_opt_get(opts, "config");
404 89f2b21e Max Reitz
    ret = read_config(s, config, options, errp);
405 85a040e5 Max Reitz
    if (ret) {
406 85a040e5 Max Reitz
        goto fail;
407 f4681212 Kevin Wolf
    }
408 8b9b0cc2 Kevin Wolf
409 8db520ce Kevin Wolf
    /* Set initial state */
410 571cd43e Paolo Bonzini
    s->state = 1;
411 8db520ce Kevin Wolf
412 8b9b0cc2 Kevin Wolf
    /* Open the backing file */
413 4373593d Max Reitz
    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
414 4373593d Max Reitz
                          flags, true, false, &local_err);
415 8b9b0cc2 Kevin Wolf
    if (ret < 0) {
416 10ffa72f Max Reitz
        error_propagate(errp, local_err);
417 f4681212 Kevin Wolf
        goto fail;
418 8b9b0cc2 Kevin Wolf
    }
419 8b9b0cc2 Kevin Wolf
420 b35ee7fb Kevin Wolf
    /* Set request alignment */
421 b35ee7fb Kevin Wolf
    align = qemu_opt_get_size(opts, "align", bs->request_alignment);
422 b35ee7fb Kevin Wolf
    if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
423 b35ee7fb Kevin Wolf
        bs->request_alignment = align;
424 b35ee7fb Kevin Wolf
    } else {
425 b35ee7fb Kevin Wolf
        error_setg(errp, "Invalid alignment");
426 b35ee7fb Kevin Wolf
        ret = -EINVAL;
427 b35ee7fb Kevin Wolf
        goto fail;
428 b35ee7fb Kevin Wolf
    }
429 b35ee7fb Kevin Wolf
430 f4681212 Kevin Wolf
    ret = 0;
431 f4681212 Kevin Wolf
fail:
432 f4681212 Kevin Wolf
    qemu_opts_del(opts);
433 f4681212 Kevin Wolf
    return ret;
434 6a143727 Kevin Wolf
}
435 6a143727 Kevin Wolf
436 b9f66d96 Kevin Wolf
static void error_callback_bh(void *opaque)
437 b9f66d96 Kevin Wolf
{
438 b9f66d96 Kevin Wolf
    struct BlkdebugAIOCB *acb = opaque;
439 b9f66d96 Kevin Wolf
    qemu_bh_delete(acb->bh);
440 b9f66d96 Kevin Wolf
    acb->common.cb(acb->common.opaque, acb->ret);
441 b9f66d96 Kevin Wolf
    qemu_aio_release(acb);
442 b9f66d96 Kevin Wolf
}
443 b9f66d96 Kevin Wolf
444 b9f66d96 Kevin Wolf
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
445 b9f66d96 Kevin Wolf
{
446 b666d239 Kevin Wolf
    BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
447 b9f66d96 Kevin Wolf
    qemu_aio_release(acb);
448 b9f66d96 Kevin Wolf
}
449 b9f66d96 Kevin Wolf
450 b9f66d96 Kevin Wolf
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
451 571cd43e Paolo Bonzini
    BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
452 b9f66d96 Kevin Wolf
{
453 b9f66d96 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
454 571cd43e Paolo Bonzini
    int error = rule->options.inject.error;
455 b9f66d96 Kevin Wolf
    struct BlkdebugAIOCB *acb;
456 b9f66d96 Kevin Wolf
    QEMUBH *bh;
457 b9f66d96 Kevin Wolf
458 571cd43e Paolo Bonzini
    if (rule->options.inject.once) {
459 571cd43e Paolo Bonzini
        QSIMPLEQ_INIT(&s->active_rules);
460 b9f66d96 Kevin Wolf
    }
461 b9f66d96 Kevin Wolf
462 571cd43e Paolo Bonzini
    if (rule->options.inject.immediately) {
463 b9f66d96 Kevin Wolf
        return NULL;
464 b9f66d96 Kevin Wolf
    }
465 b9f66d96 Kevin Wolf
466 d7331bed Stefan Hajnoczi
    acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
467 b9f66d96 Kevin Wolf
    acb->ret = -error;
468 b9f66d96 Kevin Wolf
469 b9f66d96 Kevin Wolf
    bh = qemu_bh_new(error_callback_bh, acb);
470 b9f66d96 Kevin Wolf
    acb->bh = bh;
471 b9f66d96 Kevin Wolf
    qemu_bh_schedule(bh);
472 b9f66d96 Kevin Wolf
473 b666d239 Kevin Wolf
    return &acb->common;
474 b9f66d96 Kevin Wolf
}
475 b9f66d96 Kevin Wolf
476 6a143727 Kevin Wolf
static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
477 6a143727 Kevin Wolf
    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
478 6a143727 Kevin Wolf
    BlockDriverCompletionFunc *cb, void *opaque)
479 6a143727 Kevin Wolf
{
480 6a143727 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
481 e4780db4 Paolo Bonzini
    BlkdebugRule *rule = NULL;
482 e4780db4 Paolo Bonzini
483 e4780db4 Paolo Bonzini
    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
484 e4780db4 Paolo Bonzini
        if (rule->options.inject.sector == -1 ||
485 e4780db4 Paolo Bonzini
            (rule->options.inject.sector >= sector_num &&
486 e4780db4 Paolo Bonzini
             rule->options.inject.sector < sector_num + nb_sectors)) {
487 e4780db4 Paolo Bonzini
            break;
488 e4780db4 Paolo Bonzini
        }
489 e4780db4 Paolo Bonzini
    }
490 b9f66d96 Kevin Wolf
491 571cd43e Paolo Bonzini
    if (rule && rule->options.inject.error) {
492 571cd43e Paolo Bonzini
        return inject_error(bs, cb, opaque, rule);
493 b9f66d96 Kevin Wolf
    }
494 b9f66d96 Kevin Wolf
495 368e8dd1 Paolo Bonzini
    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
496 6a143727 Kevin Wolf
}
497 6a143727 Kevin Wolf
498 6a143727 Kevin Wolf
static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
499 6a143727 Kevin Wolf
    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
500 6a143727 Kevin Wolf
    BlockDriverCompletionFunc *cb, void *opaque)
501 6a143727 Kevin Wolf
{
502 6a143727 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
503 e4780db4 Paolo Bonzini
    BlkdebugRule *rule = NULL;
504 e4780db4 Paolo Bonzini
505 e4780db4 Paolo Bonzini
    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
506 e4780db4 Paolo Bonzini
        if (rule->options.inject.sector == -1 ||
507 e4780db4 Paolo Bonzini
            (rule->options.inject.sector >= sector_num &&
508 e4780db4 Paolo Bonzini
             rule->options.inject.sector < sector_num + nb_sectors)) {
509 e4780db4 Paolo Bonzini
            break;
510 e4780db4 Paolo Bonzini
        }
511 e4780db4 Paolo Bonzini
    }
512 b9f66d96 Kevin Wolf
513 571cd43e Paolo Bonzini
    if (rule && rule->options.inject.error) {
514 571cd43e Paolo Bonzini
        return inject_error(bs, cb, opaque, rule);
515 b9f66d96 Kevin Wolf
    }
516 b9f66d96 Kevin Wolf
517 368e8dd1 Paolo Bonzini
    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
518 6a143727 Kevin Wolf
}
519 6a143727 Kevin Wolf
520 3c90c65d Kevin Wolf
521 6a143727 Kevin Wolf
static void blkdebug_close(BlockDriverState *bs)
522 6a143727 Kevin Wolf
{
523 6a143727 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
524 8b9b0cc2 Kevin Wolf
    BlkdebugRule *rule, *next;
525 8b9b0cc2 Kevin Wolf
    int i;
526 8b9b0cc2 Kevin Wolf
527 8b9b0cc2 Kevin Wolf
    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
528 8b9b0cc2 Kevin Wolf
        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
529 9e35542b Kevin Wolf
            remove_rule(rule);
530 8b9b0cc2 Kevin Wolf
        }
531 8b9b0cc2 Kevin Wolf
    }
532 6a143727 Kevin Wolf
}
533 6a143727 Kevin Wolf
534 3c90c65d Kevin Wolf
static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
535 3c90c65d Kevin Wolf
{
536 3c90c65d Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
537 3c90c65d Kevin Wolf
    BlkdebugSuspendedReq r;
538 3c90c65d Kevin Wolf
539 3c90c65d Kevin Wolf
    r = (BlkdebugSuspendedReq) {
540 3c90c65d Kevin Wolf
        .co         = qemu_coroutine_self(),
541 3c90c65d Kevin Wolf
        .tag        = g_strdup(rule->options.suspend.tag),
542 3c90c65d Kevin Wolf
    };
543 3c90c65d Kevin Wolf
544 3c90c65d Kevin Wolf
    remove_rule(rule);
545 3c90c65d Kevin Wolf
    QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
546 3c90c65d Kevin Wolf
547 3c90c65d Kevin Wolf
    printf("blkdebug: Suspended request '%s'\n", r.tag);
548 3c90c65d Kevin Wolf
    qemu_coroutine_yield();
549 3c90c65d Kevin Wolf
    printf("blkdebug: Resuming request '%s'\n", r.tag);
550 3c90c65d Kevin Wolf
551 3c90c65d Kevin Wolf
    QLIST_REMOVE(&r, next);
552 3c90c65d Kevin Wolf
    g_free(r.tag);
553 3c90c65d Kevin Wolf
}
554 3c90c65d Kevin Wolf
555 571cd43e Paolo Bonzini
static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
556 8f96b5be Paolo Bonzini
    bool injected)
557 8b9b0cc2 Kevin Wolf
{
558 8b9b0cc2 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
559 8b9b0cc2 Kevin Wolf
560 8b9b0cc2 Kevin Wolf
    /* Only process rules for the current state */
561 8f96b5be Paolo Bonzini
    if (rule->state && rule->state != s->state) {
562 571cd43e Paolo Bonzini
        return injected;
563 8b9b0cc2 Kevin Wolf
    }
564 8b9b0cc2 Kevin Wolf
565 8b9b0cc2 Kevin Wolf
    /* Take the action */
566 8b9b0cc2 Kevin Wolf
    switch (rule->action) {
567 8b9b0cc2 Kevin Wolf
    case ACTION_INJECT_ERROR:
568 571cd43e Paolo Bonzini
        if (!injected) {
569 571cd43e Paolo Bonzini
            QSIMPLEQ_INIT(&s->active_rules);
570 571cd43e Paolo Bonzini
            injected = true;
571 571cd43e Paolo Bonzini
        }
572 571cd43e Paolo Bonzini
        QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
573 8b9b0cc2 Kevin Wolf
        break;
574 8b9b0cc2 Kevin Wolf
575 8b9b0cc2 Kevin Wolf
    case ACTION_SET_STATE:
576 8f96b5be Paolo Bonzini
        s->new_state = rule->options.set_state.new_state;
577 8b9b0cc2 Kevin Wolf
        break;
578 3c90c65d Kevin Wolf
579 3c90c65d Kevin Wolf
    case ACTION_SUSPEND:
580 3c90c65d Kevin Wolf
        suspend_request(bs, rule);
581 3c90c65d Kevin Wolf
        break;
582 8b9b0cc2 Kevin Wolf
    }
583 571cd43e Paolo Bonzini
    return injected;
584 8b9b0cc2 Kevin Wolf
}
585 8b9b0cc2 Kevin Wolf
586 8b9b0cc2 Kevin Wolf
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
587 8b9b0cc2 Kevin Wolf
{
588 8b9b0cc2 Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
589 3c90c65d Kevin Wolf
    struct BlkdebugRule *rule, *next;
590 571cd43e Paolo Bonzini
    bool injected;
591 8b9b0cc2 Kevin Wolf
592 95ee3914 Blue Swirl
    assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
593 8b9b0cc2 Kevin Wolf
594 571cd43e Paolo Bonzini
    injected = false;
595 8f96b5be Paolo Bonzini
    s->new_state = s->state;
596 3c90c65d Kevin Wolf
    QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
597 8f96b5be Paolo Bonzini
        injected = process_rule(bs, rule, injected);
598 8b9b0cc2 Kevin Wolf
    }
599 8f96b5be Paolo Bonzini
    s->state = s->new_state;
600 8b9b0cc2 Kevin Wolf
}
601 8b9b0cc2 Kevin Wolf
602 3c90c65d Kevin Wolf
static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
603 3c90c65d Kevin Wolf
                                     const char *tag)
604 3c90c65d Kevin Wolf
{
605 3c90c65d Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
606 3c90c65d Kevin Wolf
    struct BlkdebugRule *rule;
607 3c90c65d Kevin Wolf
    BlkDebugEvent blkdebug_event;
608 3c90c65d Kevin Wolf
609 3c90c65d Kevin Wolf
    if (get_event_by_name(event, &blkdebug_event) < 0) {
610 3c90c65d Kevin Wolf
        return -ENOENT;
611 3c90c65d Kevin Wolf
    }
612 3c90c65d Kevin Wolf
613 3c90c65d Kevin Wolf
614 3c90c65d Kevin Wolf
    rule = g_malloc(sizeof(*rule));
615 3c90c65d Kevin Wolf
    *rule = (struct BlkdebugRule) {
616 3c90c65d Kevin Wolf
        .event  = blkdebug_event,
617 3c90c65d Kevin Wolf
        .action = ACTION_SUSPEND,
618 3c90c65d Kevin Wolf
        .state  = 0,
619 3c90c65d Kevin Wolf
        .options.suspend.tag = g_strdup(tag),
620 3c90c65d Kevin Wolf
    };
621 3c90c65d Kevin Wolf
622 3c90c65d Kevin Wolf
    QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
623 3c90c65d Kevin Wolf
624 3c90c65d Kevin Wolf
    return 0;
625 3c90c65d Kevin Wolf
}
626 3c90c65d Kevin Wolf
627 3c90c65d Kevin Wolf
static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
628 3c90c65d Kevin Wolf
{
629 3c90c65d Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
630 c547e564 Fam Zheng
    BlkdebugSuspendedReq *r, *next;
631 3c90c65d Kevin Wolf
632 c547e564 Fam Zheng
    QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
633 3c90c65d Kevin Wolf
        if (!strcmp(r->tag, tag)) {
634 3c90c65d Kevin Wolf
            qemu_coroutine_enter(r->co, NULL);
635 3c90c65d Kevin Wolf
            return 0;
636 3c90c65d Kevin Wolf
        }
637 3c90c65d Kevin Wolf
    }
638 3c90c65d Kevin Wolf
    return -ENOENT;
639 3c90c65d Kevin Wolf
}
640 3c90c65d Kevin Wolf
641 4cc70e93 Fam Zheng
static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
642 4cc70e93 Fam Zheng
                                            const char *tag)
643 4cc70e93 Fam Zheng
{
644 4cc70e93 Fam Zheng
    BDRVBlkdebugState *s = bs->opaque;
645 c547e564 Fam Zheng
    BlkdebugSuspendedReq *r, *r_next;
646 4cc70e93 Fam Zheng
    BlkdebugRule *rule, *next;
647 4cc70e93 Fam Zheng
    int i, ret = -ENOENT;
648 4cc70e93 Fam Zheng
649 4cc70e93 Fam Zheng
    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
650 4cc70e93 Fam Zheng
        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
651 4cc70e93 Fam Zheng
            if (rule->action == ACTION_SUSPEND &&
652 4cc70e93 Fam Zheng
                !strcmp(rule->options.suspend.tag, tag)) {
653 4cc70e93 Fam Zheng
                remove_rule(rule);
654 4cc70e93 Fam Zheng
                ret = 0;
655 4cc70e93 Fam Zheng
            }
656 4cc70e93 Fam Zheng
        }
657 4cc70e93 Fam Zheng
    }
658 c547e564 Fam Zheng
    QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
659 4cc70e93 Fam Zheng
        if (!strcmp(r->tag, tag)) {
660 4cc70e93 Fam Zheng
            qemu_coroutine_enter(r->co, NULL);
661 4cc70e93 Fam Zheng
            ret = 0;
662 4cc70e93 Fam Zheng
        }
663 4cc70e93 Fam Zheng
    }
664 4cc70e93 Fam Zheng
    return ret;
665 4cc70e93 Fam Zheng
}
666 3c90c65d Kevin Wolf
667 3c90c65d Kevin Wolf
static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
668 3c90c65d Kevin Wolf
{
669 3c90c65d Kevin Wolf
    BDRVBlkdebugState *s = bs->opaque;
670 3c90c65d Kevin Wolf
    BlkdebugSuspendedReq *r;
671 3c90c65d Kevin Wolf
672 3c90c65d Kevin Wolf
    QLIST_FOREACH(r, &s->suspended_reqs, next) {
673 3c90c65d Kevin Wolf
        if (!strcmp(r->tag, tag)) {
674 3c90c65d Kevin Wolf
            return true;
675 3c90c65d Kevin Wolf
        }
676 3c90c65d Kevin Wolf
    }
677 3c90c65d Kevin Wolf
    return false;
678 3c90c65d Kevin Wolf
}
679 3c90c65d Kevin Wolf
680 e1302255 Paolo Bonzini
static int64_t blkdebug_getlength(BlockDriverState *bs)
681 e1302255 Paolo Bonzini
{
682 e1302255 Paolo Bonzini
    return bdrv_getlength(bs->file);
683 e1302255 Paolo Bonzini
}
684 e1302255 Paolo Bonzini
685 6a143727 Kevin Wolf
static BlockDriver bdrv_blkdebug = {
686 f4681212 Kevin Wolf
    .format_name            = "blkdebug",
687 f4681212 Kevin Wolf
    .protocol_name          = "blkdebug",
688 f4681212 Kevin Wolf
    .instance_size          = sizeof(BDRVBlkdebugState),
689 6a143727 Kevin Wolf
690 f4681212 Kevin Wolf
    .bdrv_parse_filename    = blkdebug_parse_filename,
691 f4681212 Kevin Wolf
    .bdrv_file_open         = blkdebug_open,
692 f4681212 Kevin Wolf
    .bdrv_close             = blkdebug_close,
693 f4681212 Kevin Wolf
    .bdrv_getlength         = blkdebug_getlength,
694 6a143727 Kevin Wolf
695 f4681212 Kevin Wolf
    .bdrv_aio_readv         = blkdebug_aio_readv,
696 f4681212 Kevin Wolf
    .bdrv_aio_writev        = blkdebug_aio_writev,
697 8b9b0cc2 Kevin Wolf
698 3c90c65d Kevin Wolf
    .bdrv_debug_event           = blkdebug_debug_event,
699 3c90c65d Kevin Wolf
    .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
700 4cc70e93 Fam Zheng
    .bdrv_debug_remove_breakpoint
701 4cc70e93 Fam Zheng
                                = blkdebug_debug_remove_breakpoint,
702 3c90c65d Kevin Wolf
    .bdrv_debug_resume          = blkdebug_debug_resume,
703 3c90c65d Kevin Wolf
    .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
704 6a143727 Kevin Wolf
};
705 6a143727 Kevin Wolf
706 6a143727 Kevin Wolf
static void bdrv_blkdebug_init(void)
707 6a143727 Kevin Wolf
{
708 6a143727 Kevin Wolf
    bdrv_register(&bdrv_blkdebug);
709 6a143727 Kevin Wolf
}
710 6a143727 Kevin Wolf
711 6a143727 Kevin Wolf
block_init(bdrv_blkdebug_init);