xref: /openbmc/qemu/block/blkdebug.c (revision 77a8257e)
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     [BLKDBG_EMPTY_IMAGE_PREPARE]            = "empty_image_prepare",
200 };
201 
202 static int get_event_by_name(const char *name, BlkDebugEvent *event)
203 {
204     int i;
205 
206     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
207         if (!strcmp(event_names[i], name)) {
208             *event = i;
209             return 0;
210         }
211     }
212 
213     return -1;
214 }
215 
216 struct add_rule_data {
217     BDRVBlkdebugState *s;
218     int action;
219     Error **errp;
220 };
221 
222 static int add_rule(QemuOpts *opts, void *opaque)
223 {
224     struct add_rule_data *d = opaque;
225     BDRVBlkdebugState *s = d->s;
226     const char* event_name;
227     BlkDebugEvent event;
228     struct BlkdebugRule *rule;
229 
230     /* Find the right event for the rule */
231     event_name = qemu_opt_get(opts, "event");
232     if (!event_name) {
233         error_setg(d->errp, "Missing event name for rule");
234         return -1;
235     } else if (get_event_by_name(event_name, &event) < 0) {
236         error_setg(d->errp, "Invalid event name \"%s\"", event_name);
237         return -1;
238     }
239 
240     /* Set attributes common for all actions */
241     rule = g_malloc0(sizeof(*rule));
242     *rule = (struct BlkdebugRule) {
243         .event  = event,
244         .action = d->action,
245         .state  = qemu_opt_get_number(opts, "state", 0),
246     };
247 
248     /* Parse action-specific options */
249     switch (d->action) {
250     case ACTION_INJECT_ERROR:
251         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
252         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
253         rule->options.inject.immediately =
254             qemu_opt_get_bool(opts, "immediately", 0);
255         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
256         break;
257 
258     case ACTION_SET_STATE:
259         rule->options.set_state.new_state =
260             qemu_opt_get_number(opts, "new_state", 0);
261         break;
262 
263     case ACTION_SUSPEND:
264         rule->options.suspend.tag =
265             g_strdup(qemu_opt_get(opts, "tag"));
266         break;
267     };
268 
269     /* Add the rule */
270     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
271 
272     return 0;
273 }
274 
275 static void remove_rule(BlkdebugRule *rule)
276 {
277     switch (rule->action) {
278     case ACTION_INJECT_ERROR:
279     case ACTION_SET_STATE:
280         break;
281     case ACTION_SUSPEND:
282         g_free(rule->options.suspend.tag);
283         break;
284     }
285 
286     QLIST_REMOVE(rule, next);
287     g_free(rule);
288 }
289 
290 static int read_config(BDRVBlkdebugState *s, const char *filename,
291                        QDict *options, Error **errp)
292 {
293     FILE *f = NULL;
294     int ret;
295     struct add_rule_data d;
296     Error *local_err = NULL;
297 
298     if (filename) {
299         f = fopen(filename, "r");
300         if (f == NULL) {
301             error_setg_errno(errp, errno, "Could not read blkdebug config file");
302             return -errno;
303         }
304 
305         ret = qemu_config_parse(f, config_groups, filename);
306         if (ret < 0) {
307             error_setg(errp, "Could not parse blkdebug config file");
308             ret = -EINVAL;
309             goto fail;
310         }
311     }
312 
313     qemu_config_parse_qdict(options, config_groups, &local_err);
314     if (local_err) {
315         error_propagate(errp, local_err);
316         ret = -EINVAL;
317         goto fail;
318     }
319 
320     d.s = s;
321     d.action = ACTION_INJECT_ERROR;
322     d.errp = &local_err;
323     qemu_opts_foreach(&inject_error_opts, add_rule, &d, 1);
324     if (local_err) {
325         error_propagate(errp, local_err);
326         ret = -EINVAL;
327         goto fail;
328     }
329 
330     d.action = ACTION_SET_STATE;
331     qemu_opts_foreach(&set_state_opts, add_rule, &d, 1);
332     if (local_err) {
333         error_propagate(errp, local_err);
334         ret = -EINVAL;
335         goto fail;
336     }
337 
338     ret = 0;
339 fail:
340     qemu_opts_reset(&inject_error_opts);
341     qemu_opts_reset(&set_state_opts);
342     if (f) {
343         fclose(f);
344     }
345     return ret;
346 }
347 
348 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
349 static void blkdebug_parse_filename(const char *filename, QDict *options,
350                                     Error **errp)
351 {
352     const char *c;
353 
354     /* Parse the blkdebug: prefix */
355     if (!strstart(filename, "blkdebug:", &filename)) {
356         /* There was no prefix; therefore, all options have to be already
357            present in the QDict (except for the filename) */
358         qdict_put(options, "x-image", qstring_from_str(filename));
359         return;
360     }
361 
362     /* Parse config file path */
363     c = strchr(filename, ':');
364     if (c == NULL) {
365         error_setg(errp, "blkdebug requires both config file and image path");
366         return;
367     }
368 
369     if (c != filename) {
370         QString *config_path;
371         config_path = qstring_from_substr(filename, 0, c - filename - 1);
372         qdict_put(options, "config", config_path);
373     }
374 
375     /* TODO Allow multi-level nesting and set file.filename here */
376     filename = c + 1;
377     qdict_put(options, "x-image", qstring_from_str(filename));
378 }
379 
380 static QemuOptsList runtime_opts = {
381     .name = "blkdebug",
382     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
383     .desc = {
384         {
385             .name = "config",
386             .type = QEMU_OPT_STRING,
387             .help = "Path to the configuration file",
388         },
389         {
390             .name = "x-image",
391             .type = QEMU_OPT_STRING,
392             .help = "[internal use only, will be removed]",
393         },
394         {
395             .name = "align",
396             .type = QEMU_OPT_SIZE,
397             .help = "Required alignment in bytes",
398         },
399         { /* end of list */ }
400     },
401 };
402 
403 static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
404                          Error **errp)
405 {
406     BDRVBlkdebugState *s = bs->opaque;
407     QemuOpts *opts;
408     Error *local_err = NULL;
409     const char *config;
410     uint64_t align;
411     int ret;
412 
413     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
414     qemu_opts_absorb_qdict(opts, options, &local_err);
415     if (local_err) {
416         error_propagate(errp, local_err);
417         ret = -EINVAL;
418         goto out;
419     }
420 
421     /* Read rules from config file or command line options */
422     config = qemu_opt_get(opts, "config");
423     ret = read_config(s, config, options, errp);
424     if (ret) {
425         goto out;
426     }
427 
428     /* Set initial state */
429     s->state = 1;
430 
431     /* Open the backing file */
432     assert(bs->file == NULL);
433     ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
434                           flags | BDRV_O_PROTOCOL, false, &local_err);
435     if (ret < 0) {
436         error_propagate(errp, local_err);
437         goto out;
438     }
439 
440     /* Set request alignment */
441     align = qemu_opt_get_size(opts, "align", bs->request_alignment);
442     if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
443         bs->request_alignment = align;
444     } else {
445         error_setg(errp, "Invalid alignment");
446         ret = -EINVAL;
447         goto fail_unref;
448     }
449 
450     ret = 0;
451     goto out;
452 
453 fail_unref:
454     bdrv_unref(bs->file);
455 out:
456     qemu_opts_del(opts);
457     return ret;
458 }
459 
460 static void error_callback_bh(void *opaque)
461 {
462     struct BlkdebugAIOCB *acb = opaque;
463     qemu_bh_delete(acb->bh);
464     acb->common.cb(acb->common.opaque, acb->ret);
465     qemu_aio_unref(acb);
466 }
467 
468 static BlockAIOCB *inject_error(BlockDriverState *bs,
469     BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
470 {
471     BDRVBlkdebugState *s = bs->opaque;
472     int error = rule->options.inject.error;
473     struct BlkdebugAIOCB *acb;
474     QEMUBH *bh;
475     bool immediately = rule->options.inject.immediately;
476 
477     if (rule->options.inject.once) {
478         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
479         remove_rule(rule);
480     }
481 
482     if (immediately) {
483         return NULL;
484     }
485 
486     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
487     acb->ret = -error;
488 
489     bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
490     acb->bh = bh;
491     qemu_bh_schedule(bh);
492 
493     return &acb->common;
494 }
495 
496 static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
497     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
498     BlockCompletionFunc *cb, void *opaque)
499 {
500     BDRVBlkdebugState *s = bs->opaque;
501     BlkdebugRule *rule = NULL;
502 
503     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
504         if (rule->options.inject.sector == -1 ||
505             (rule->options.inject.sector >= sector_num &&
506              rule->options.inject.sector < sector_num + nb_sectors)) {
507             break;
508         }
509     }
510 
511     if (rule && rule->options.inject.error) {
512         return inject_error(bs, cb, opaque, rule);
513     }
514 
515     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
516 }
517 
518 static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
519     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
520     BlockCompletionFunc *cb, void *opaque)
521 {
522     BDRVBlkdebugState *s = bs->opaque;
523     BlkdebugRule *rule = NULL;
524 
525     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
526         if (rule->options.inject.sector == -1 ||
527             (rule->options.inject.sector >= sector_num &&
528              rule->options.inject.sector < sector_num + nb_sectors)) {
529             break;
530         }
531     }
532 
533     if (rule && rule->options.inject.error) {
534         return inject_error(bs, cb, opaque, rule);
535     }
536 
537     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
538 }
539 
540 static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
541     BlockCompletionFunc *cb, void *opaque)
542 {
543     BDRVBlkdebugState *s = bs->opaque;
544     BlkdebugRule *rule = NULL;
545 
546     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
547         if (rule->options.inject.sector == -1) {
548             break;
549         }
550     }
551 
552     if (rule && rule->options.inject.error) {
553         return inject_error(bs, cb, opaque, rule);
554     }
555 
556     return bdrv_aio_flush(bs->file, cb, opaque);
557 }
558 
559 
560 static void blkdebug_close(BlockDriverState *bs)
561 {
562     BDRVBlkdebugState *s = bs->opaque;
563     BlkdebugRule *rule, *next;
564     int i;
565 
566     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
567         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
568             remove_rule(rule);
569         }
570     }
571 }
572 
573 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
574 {
575     BDRVBlkdebugState *s = bs->opaque;
576     BlkdebugSuspendedReq r;
577 
578     r = (BlkdebugSuspendedReq) {
579         .co         = qemu_coroutine_self(),
580         .tag        = g_strdup(rule->options.suspend.tag),
581     };
582 
583     remove_rule(rule);
584     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
585 
586     printf("blkdebug: Suspended request '%s'\n", r.tag);
587     qemu_coroutine_yield();
588     printf("blkdebug: Resuming request '%s'\n", r.tag);
589 
590     QLIST_REMOVE(&r, next);
591     g_free(r.tag);
592 }
593 
594 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
595     bool injected)
596 {
597     BDRVBlkdebugState *s = bs->opaque;
598 
599     /* Only process rules for the current state */
600     if (rule->state && rule->state != s->state) {
601         return injected;
602     }
603 
604     /* Take the action */
605     switch (rule->action) {
606     case ACTION_INJECT_ERROR:
607         if (!injected) {
608             QSIMPLEQ_INIT(&s->active_rules);
609             injected = true;
610         }
611         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
612         break;
613 
614     case ACTION_SET_STATE:
615         s->new_state = rule->options.set_state.new_state;
616         break;
617 
618     case ACTION_SUSPEND:
619         suspend_request(bs, rule);
620         break;
621     }
622     return injected;
623 }
624 
625 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
626 {
627     BDRVBlkdebugState *s = bs->opaque;
628     struct BlkdebugRule *rule, *next;
629     bool injected;
630 
631     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
632 
633     injected = false;
634     s->new_state = s->state;
635     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
636         injected = process_rule(bs, rule, injected);
637     }
638     s->state = s->new_state;
639 }
640 
641 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
642                                      const char *tag)
643 {
644     BDRVBlkdebugState *s = bs->opaque;
645     struct BlkdebugRule *rule;
646     BlkDebugEvent blkdebug_event;
647 
648     if (get_event_by_name(event, &blkdebug_event) < 0) {
649         return -ENOENT;
650     }
651 
652 
653     rule = g_malloc(sizeof(*rule));
654     *rule = (struct BlkdebugRule) {
655         .event  = blkdebug_event,
656         .action = ACTION_SUSPEND,
657         .state  = 0,
658         .options.suspend.tag = g_strdup(tag),
659     };
660 
661     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
662 
663     return 0;
664 }
665 
666 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
667 {
668     BDRVBlkdebugState *s = bs->opaque;
669     BlkdebugSuspendedReq *r, *next;
670 
671     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
672         if (!strcmp(r->tag, tag)) {
673             qemu_coroutine_enter(r->co, NULL);
674             return 0;
675         }
676     }
677     return -ENOENT;
678 }
679 
680 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
681                                             const char *tag)
682 {
683     BDRVBlkdebugState *s = bs->opaque;
684     BlkdebugSuspendedReq *r, *r_next;
685     BlkdebugRule *rule, *next;
686     int i, ret = -ENOENT;
687 
688     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
689         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
690             if (rule->action == ACTION_SUSPEND &&
691                 !strcmp(rule->options.suspend.tag, tag)) {
692                 remove_rule(rule);
693                 ret = 0;
694             }
695         }
696     }
697     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
698         if (!strcmp(r->tag, tag)) {
699             qemu_coroutine_enter(r->co, NULL);
700             ret = 0;
701         }
702     }
703     return ret;
704 }
705 
706 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
707 {
708     BDRVBlkdebugState *s = bs->opaque;
709     BlkdebugSuspendedReq *r;
710 
711     QLIST_FOREACH(r, &s->suspended_reqs, next) {
712         if (!strcmp(r->tag, tag)) {
713             return true;
714         }
715     }
716     return false;
717 }
718 
719 static int64_t blkdebug_getlength(BlockDriverState *bs)
720 {
721     return bdrv_getlength(bs->file);
722 }
723 
724 static void blkdebug_refresh_filename(BlockDriverState *bs)
725 {
726     QDict *opts;
727     const QDictEntry *e;
728     bool force_json = false;
729 
730     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
731         if (strcmp(qdict_entry_key(e), "config") &&
732             strcmp(qdict_entry_key(e), "x-image") &&
733             strcmp(qdict_entry_key(e), "image") &&
734             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
735         {
736             force_json = true;
737             break;
738         }
739     }
740 
741     if (force_json && !bs->file->full_open_options) {
742         /* The config file cannot be recreated, so creating a plain filename
743          * is impossible */
744         return;
745     }
746 
747     if (!force_json && bs->file->exact_filename[0]) {
748         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
749                  "blkdebug:%s:%s",
750                  qdict_get_try_str(bs->options, "config") ?: "",
751                  bs->file->exact_filename);
752     }
753 
754     opts = qdict_new();
755     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
756 
757     QINCREF(bs->file->full_open_options);
758     qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
759 
760     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
761         if (strcmp(qdict_entry_key(e), "x-image") &&
762             strcmp(qdict_entry_key(e), "image") &&
763             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
764         {
765             qobject_incref(qdict_entry_value(e));
766             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
767         }
768     }
769 
770     bs->full_open_options = opts;
771 }
772 
773 static BlockDriver bdrv_blkdebug = {
774     .format_name            = "blkdebug",
775     .protocol_name          = "blkdebug",
776     .instance_size          = sizeof(BDRVBlkdebugState),
777 
778     .bdrv_parse_filename    = blkdebug_parse_filename,
779     .bdrv_file_open         = blkdebug_open,
780     .bdrv_close             = blkdebug_close,
781     .bdrv_getlength         = blkdebug_getlength,
782     .bdrv_refresh_filename  = blkdebug_refresh_filename,
783 
784     .bdrv_aio_readv         = blkdebug_aio_readv,
785     .bdrv_aio_writev        = blkdebug_aio_writev,
786     .bdrv_aio_flush         = blkdebug_aio_flush,
787 
788     .bdrv_debug_event           = blkdebug_debug_event,
789     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
790     .bdrv_debug_remove_breakpoint
791                                 = blkdebug_debug_remove_breakpoint,
792     .bdrv_debug_resume          = blkdebug_debug_resume,
793     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
794 };
795 
796 static void bdrv_blkdebug_init(void)
797 {
798     bdrv_register(&bdrv_blkdebug);
799 }
800 
801 block_init(bdrv_blkdebug_init);
802