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