xref: /openbmc/qemu/block/blkdebug.c (revision 2822c1b6)
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 
476     if (rule->options.inject.once) {
477         QSIMPLEQ_INIT(&s->active_rules);
478     }
479 
480     if (rule->options.inject.immediately) {
481         return NULL;
482     }
483 
484     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
485     acb->ret = -error;
486 
487     bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
488     acb->bh = bh;
489     qemu_bh_schedule(bh);
490 
491     return &acb->common;
492 }
493 
494 static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
495     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
496     BlockCompletionFunc *cb, void *opaque)
497 {
498     BDRVBlkdebugState *s = bs->opaque;
499     BlkdebugRule *rule = NULL;
500 
501     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
502         if (rule->options.inject.sector == -1 ||
503             (rule->options.inject.sector >= sector_num &&
504              rule->options.inject.sector < sector_num + nb_sectors)) {
505             break;
506         }
507     }
508 
509     if (rule && rule->options.inject.error) {
510         return inject_error(bs, cb, opaque, rule);
511     }
512 
513     return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
514 }
515 
516 static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
517     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
518     BlockCompletionFunc *cb, void *opaque)
519 {
520     BDRVBlkdebugState *s = bs->opaque;
521     BlkdebugRule *rule = NULL;
522 
523     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
524         if (rule->options.inject.sector == -1 ||
525             (rule->options.inject.sector >= sector_num &&
526              rule->options.inject.sector < sector_num + nb_sectors)) {
527             break;
528         }
529     }
530 
531     if (rule && rule->options.inject.error) {
532         return inject_error(bs, cb, opaque, rule);
533     }
534 
535     return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
536 }
537 
538 static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
539     BlockCompletionFunc *cb, void *opaque)
540 {
541     BDRVBlkdebugState *s = bs->opaque;
542     BlkdebugRule *rule = NULL;
543 
544     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
545         if (rule->options.inject.sector == -1) {
546             break;
547         }
548     }
549 
550     if (rule && rule->options.inject.error) {
551         return inject_error(bs, cb, opaque, rule);
552     }
553 
554     return bdrv_aio_flush(bs->file, cb, opaque);
555 }
556 
557 
558 static void blkdebug_close(BlockDriverState *bs)
559 {
560     BDRVBlkdebugState *s = bs->opaque;
561     BlkdebugRule *rule, *next;
562     int i;
563 
564     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
565         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
566             remove_rule(rule);
567         }
568     }
569 }
570 
571 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
572 {
573     BDRVBlkdebugState *s = bs->opaque;
574     BlkdebugSuspendedReq r;
575 
576     r = (BlkdebugSuspendedReq) {
577         .co         = qemu_coroutine_self(),
578         .tag        = g_strdup(rule->options.suspend.tag),
579     };
580 
581     remove_rule(rule);
582     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
583 
584     printf("blkdebug: Suspended request '%s'\n", r.tag);
585     qemu_coroutine_yield();
586     printf("blkdebug: Resuming request '%s'\n", r.tag);
587 
588     QLIST_REMOVE(&r, next);
589     g_free(r.tag);
590 }
591 
592 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
593     bool injected)
594 {
595     BDRVBlkdebugState *s = bs->opaque;
596 
597     /* Only process rules for the current state */
598     if (rule->state && rule->state != s->state) {
599         return injected;
600     }
601 
602     /* Take the action */
603     switch (rule->action) {
604     case ACTION_INJECT_ERROR:
605         if (!injected) {
606             QSIMPLEQ_INIT(&s->active_rules);
607             injected = true;
608         }
609         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
610         break;
611 
612     case ACTION_SET_STATE:
613         s->new_state = rule->options.set_state.new_state;
614         break;
615 
616     case ACTION_SUSPEND:
617         suspend_request(bs, rule);
618         break;
619     }
620     return injected;
621 }
622 
623 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
624 {
625     BDRVBlkdebugState *s = bs->opaque;
626     struct BlkdebugRule *rule, *next;
627     bool injected;
628 
629     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
630 
631     injected = false;
632     s->new_state = s->state;
633     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
634         injected = process_rule(bs, rule, injected);
635     }
636     s->state = s->new_state;
637 }
638 
639 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
640                                      const char *tag)
641 {
642     BDRVBlkdebugState *s = bs->opaque;
643     struct BlkdebugRule *rule;
644     BlkDebugEvent blkdebug_event;
645 
646     if (get_event_by_name(event, &blkdebug_event) < 0) {
647         return -ENOENT;
648     }
649 
650 
651     rule = g_malloc(sizeof(*rule));
652     *rule = (struct BlkdebugRule) {
653         .event  = blkdebug_event,
654         .action = ACTION_SUSPEND,
655         .state  = 0,
656         .options.suspend.tag = g_strdup(tag),
657     };
658 
659     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
660 
661     return 0;
662 }
663 
664 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
665 {
666     BDRVBlkdebugState *s = bs->opaque;
667     BlkdebugSuspendedReq *r, *next;
668 
669     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
670         if (!strcmp(r->tag, tag)) {
671             qemu_coroutine_enter(r->co, NULL);
672             return 0;
673         }
674     }
675     return -ENOENT;
676 }
677 
678 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
679                                             const char *tag)
680 {
681     BDRVBlkdebugState *s = bs->opaque;
682     BlkdebugSuspendedReq *r, *r_next;
683     BlkdebugRule *rule, *next;
684     int i, ret = -ENOENT;
685 
686     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
687         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
688             if (rule->action == ACTION_SUSPEND &&
689                 !strcmp(rule->options.suspend.tag, tag)) {
690                 remove_rule(rule);
691                 ret = 0;
692             }
693         }
694     }
695     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
696         if (!strcmp(r->tag, tag)) {
697             qemu_coroutine_enter(r->co, NULL);
698             ret = 0;
699         }
700     }
701     return ret;
702 }
703 
704 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
705 {
706     BDRVBlkdebugState *s = bs->opaque;
707     BlkdebugSuspendedReq *r;
708 
709     QLIST_FOREACH(r, &s->suspended_reqs, next) {
710         if (!strcmp(r->tag, tag)) {
711             return true;
712         }
713     }
714     return false;
715 }
716 
717 static int64_t blkdebug_getlength(BlockDriverState *bs)
718 {
719     return bdrv_getlength(bs->file);
720 }
721 
722 static void blkdebug_refresh_filename(BlockDriverState *bs)
723 {
724     QDict *opts;
725     const QDictEntry *e;
726     bool force_json = false;
727 
728     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
729         if (strcmp(qdict_entry_key(e), "config") &&
730             strcmp(qdict_entry_key(e), "x-image") &&
731             strcmp(qdict_entry_key(e), "image") &&
732             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
733         {
734             force_json = true;
735             break;
736         }
737     }
738 
739     if (force_json && !bs->file->full_open_options) {
740         /* The config file cannot be recreated, so creating a plain filename
741          * is impossible */
742         return;
743     }
744 
745     if (!force_json && bs->file->exact_filename[0]) {
746         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
747                  "blkdebug:%s:%s",
748                  qdict_get_try_str(bs->options, "config") ?: "",
749                  bs->file->exact_filename);
750     }
751 
752     opts = qdict_new();
753     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
754 
755     QINCREF(bs->file->full_open_options);
756     qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
757 
758     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
759         if (strcmp(qdict_entry_key(e), "x-image") &&
760             strcmp(qdict_entry_key(e), "image") &&
761             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
762         {
763             qobject_incref(qdict_entry_value(e));
764             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
765         }
766     }
767 
768     bs->full_open_options = opts;
769 }
770 
771 static BlockDriver bdrv_blkdebug = {
772     .format_name            = "blkdebug",
773     .protocol_name          = "blkdebug",
774     .instance_size          = sizeof(BDRVBlkdebugState),
775 
776     .bdrv_parse_filename    = blkdebug_parse_filename,
777     .bdrv_file_open         = blkdebug_open,
778     .bdrv_close             = blkdebug_close,
779     .bdrv_getlength         = blkdebug_getlength,
780     .bdrv_refresh_filename  = blkdebug_refresh_filename,
781 
782     .bdrv_aio_readv         = blkdebug_aio_readv,
783     .bdrv_aio_writev        = blkdebug_aio_writev,
784     .bdrv_aio_flush         = blkdebug_aio_flush,
785 
786     .bdrv_debug_event           = blkdebug_debug_event,
787     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
788     .bdrv_debug_remove_breakpoint
789                                 = blkdebug_debug_remove_breakpoint,
790     .bdrv_debug_resume          = blkdebug_debug_resume,
791     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
792 };
793 
794 static void bdrv_blkdebug_init(void)
795 {
796     bdrv_register(&bdrv_blkdebug);
797 }
798 
799 block_init(bdrv_blkdebug_init);
800