xref: /openbmc/qemu/block/blkdebug.c (revision 0e1d0245)
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 #include "sysemu/qtest.h"
34 
35 typedef struct BDRVBlkdebugState {
36     int state;
37     int new_state;
38 
39     QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
40     QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
41     QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
42 } BDRVBlkdebugState;
43 
44 typedef struct BlkdebugAIOCB {
45     BlockAIOCB common;
46     QEMUBH *bh;
47     int ret;
48 } BlkdebugAIOCB;
49 
50 typedef struct BlkdebugSuspendedReq {
51     Coroutine *co;
52     char *tag;
53     QLIST_ENTRY(BlkdebugSuspendedReq) next;
54 } BlkdebugSuspendedReq;
55 
56 static const AIOCBInfo blkdebug_aiocb_info = {
57     .aiocb_size    = sizeof(BlkdebugAIOCB),
58 };
59 
60 enum {
61     ACTION_INJECT_ERROR,
62     ACTION_SET_STATE,
63     ACTION_SUSPEND,
64 };
65 
66 typedef struct BlkdebugRule {
67     BlkDebugEvent event;
68     int action;
69     int state;
70     union {
71         struct {
72             int error;
73             int immediately;
74             int once;
75             int64_t sector;
76         } inject;
77         struct {
78             int new_state;
79         } set_state;
80         struct {
81             char *tag;
82         } suspend;
83     } options;
84     QLIST_ENTRY(BlkdebugRule) next;
85     QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
86 } BlkdebugRule;
87 
88 static QemuOptsList inject_error_opts = {
89     .name = "inject-error",
90     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
91     .desc = {
92         {
93             .name = "event",
94             .type = QEMU_OPT_STRING,
95         },
96         {
97             .name = "state",
98             .type = QEMU_OPT_NUMBER,
99         },
100         {
101             .name = "errno",
102             .type = QEMU_OPT_NUMBER,
103         },
104         {
105             .name = "sector",
106             .type = QEMU_OPT_NUMBER,
107         },
108         {
109             .name = "once",
110             .type = QEMU_OPT_BOOL,
111         },
112         {
113             .name = "immediately",
114             .type = QEMU_OPT_BOOL,
115         },
116         { /* end of list */ }
117     },
118 };
119 
120 static QemuOptsList set_state_opts = {
121     .name = "set-state",
122     .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
123     .desc = {
124         {
125             .name = "event",
126             .type = QEMU_OPT_STRING,
127         },
128         {
129             .name = "state",
130             .type = QEMU_OPT_NUMBER,
131         },
132         {
133             .name = "new_state",
134             .type = QEMU_OPT_NUMBER,
135         },
136         { /* end of list */ }
137     },
138 };
139 
140 static QemuOptsList *config_groups[] = {
141     &inject_error_opts,
142     &set_state_opts,
143     NULL
144 };
145 
146 static const char *event_names[BLKDBG_EVENT_MAX] = {
147     [BLKDBG_L1_UPDATE]                      = "l1_update",
148     [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
149     [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
150     [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
151 
152     [BLKDBG_L2_LOAD]                        = "l2_load",
153     [BLKDBG_L2_UPDATE]                      = "l2_update",
154     [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
155     [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
156     [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
157 
158     [BLKDBG_READ_AIO]                       = "read_aio",
159     [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
160     [BLKDBG_READ_COMPRESSED]                = "read_compressed",
161 
162     [BLKDBG_WRITE_AIO]                      = "write_aio",
163     [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
164 
165     [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
166     [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
167 
168     [BLKDBG_COW_READ]                       = "cow_read",
169     [BLKDBG_COW_WRITE]                      = "cow_write",
170 
171     [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
172     [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
173     [BLKDBG_REFTABLE_UPDATE]                = "reftable_update",
174 
175     [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
176     [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
177     [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
178     [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
179     [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
180     [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
181     [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
182     [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
183     [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
184 
185     [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
186     [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
187     [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
188 
189     [BLKDBG_FLUSH_TO_OS]                    = "flush_to_os",
190     [BLKDBG_FLUSH_TO_DISK]                  = "flush_to_disk",
191 
192     [BLKDBG_PWRITEV_RMW_HEAD]               = "pwritev_rmw.head",
193     [BLKDBG_PWRITEV_RMW_AFTER_HEAD]         = "pwritev_rmw.after_head",
194     [BLKDBG_PWRITEV_RMW_TAIL]               = "pwritev_rmw.tail",
195     [BLKDBG_PWRITEV_RMW_AFTER_TAIL]         = "pwritev_rmw.after_tail",
196     [BLKDBG_PWRITEV]                        = "pwritev",
197     [BLKDBG_PWRITEV_ZERO]                   = "pwritev_zero",
198     [BLKDBG_PWRITEV_DONE]                   = "pwritev_done",
199 
200     [BLKDBG_EMPTY_IMAGE_PREPARE]            = "empty_image_prepare",
201 };
202 
203 static int get_event_by_name(const char *name, BlkDebugEvent *event)
204 {
205     int i;
206 
207     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
208         if (!strcmp(event_names[i], name)) {
209             *event = i;
210             return 0;
211         }
212     }
213 
214     return -1;
215 }
216 
217 struct add_rule_data {
218     BDRVBlkdebugState *s;
219     int action;
220 };
221 
222 static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
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(errp, "Missing event name for rule");
234         return -1;
235     } else if (get_event_by_name(event_name, &event) < 0) {
236         error_setg(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     qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
323     if (local_err) {
324         error_propagate(errp, local_err);
325         ret = -EINVAL;
326         goto fail;
327     }
328 
329     d.action = ACTION_SET_STATE;
330     qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
331     if (local_err) {
332         error_propagate(errp, local_err);
333         ret = -EINVAL;
334         goto fail;
335     }
336 
337     ret = 0;
338 fail:
339     qemu_opts_reset(&inject_error_opts);
340     qemu_opts_reset(&set_state_opts);
341     if (f) {
342         fclose(f);
343     }
344     return ret;
345 }
346 
347 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
348 static void blkdebug_parse_filename(const char *filename, QDict *options,
349                                     Error **errp)
350 {
351     const char *c;
352 
353     /* Parse the blkdebug: prefix */
354     if (!strstart(filename, "blkdebug:", &filename)) {
355         /* There was no prefix; therefore, all options have to be already
356            present in the QDict (except for the filename) */
357         qdict_put(options, "x-image", qstring_from_str(filename));
358         return;
359     }
360 
361     /* Parse config file path */
362     c = strchr(filename, ':');
363     if (c == NULL) {
364         error_setg(errp, "blkdebug requires both config file and image path");
365         return;
366     }
367 
368     if (c != filename) {
369         QString *config_path;
370         config_path = qstring_from_substr(filename, 0, c - filename - 1);
371         qdict_put(options, "config", config_path);
372     }
373 
374     /* TODO Allow multi-level nesting and set file.filename here */
375     filename = c + 1;
376     qdict_put(options, "x-image", qstring_from_str(filename));
377 }
378 
379 static QemuOptsList runtime_opts = {
380     .name = "blkdebug",
381     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
382     .desc = {
383         {
384             .name = "config",
385             .type = QEMU_OPT_STRING,
386             .help = "Path to the configuration file",
387         },
388         {
389             .name = "x-image",
390             .type = QEMU_OPT_STRING,
391             .help = "[internal use only, will be removed]",
392         },
393         {
394             .name = "align",
395             .type = QEMU_OPT_SIZE,
396             .help = "Required alignment in bytes",
397         },
398         { /* end of list */ }
399     },
400 };
401 
402 static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
403                          Error **errp)
404 {
405     BDRVBlkdebugState *s = bs->opaque;
406     QemuOpts *opts;
407     Error *local_err = NULL;
408     const char *config;
409     uint64_t align;
410     int ret;
411 
412     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
413     qemu_opts_absorb_qdict(opts, options, &local_err);
414     if (local_err) {
415         error_propagate(errp, local_err);
416         ret = -EINVAL;
417         goto out;
418     }
419 
420     /* Read rules from config file or command line options */
421     config = qemu_opt_get(opts, "config");
422     ret = read_config(s, config, options, errp);
423     if (ret) {
424         goto out;
425     }
426 
427     /* Set initial state */
428     s->state = 1;
429 
430     /* Open the image file */
431     bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
432                                bs, &child_file, false, &local_err);
433     if (local_err) {
434         ret = -EINVAL;
435         error_propagate(errp, local_err);
436         goto out;
437     }
438 
439     /* Set request alignment */
440     align = qemu_opt_get_size(opts, "align", bs->request_alignment);
441     if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
442         bs->request_alignment = align;
443     } else {
444         error_setg(errp, "Invalid alignment");
445         ret = -EINVAL;
446         goto fail_unref;
447     }
448 
449     ret = 0;
450     goto out;
451 
452 fail_unref:
453     bdrv_unref_child(bs, bs->file);
454 out:
455     qemu_opts_del(opts);
456     return ret;
457 }
458 
459 static void error_callback_bh(void *opaque)
460 {
461     struct BlkdebugAIOCB *acb = opaque;
462     qemu_bh_delete(acb->bh);
463     acb->common.cb(acb->common.opaque, acb->ret);
464     qemu_aio_unref(acb);
465 }
466 
467 static BlockAIOCB *inject_error(BlockDriverState *bs,
468     BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
469 {
470     BDRVBlkdebugState *s = bs->opaque;
471     int error = rule->options.inject.error;
472     struct BlkdebugAIOCB *acb;
473     QEMUBH *bh;
474     bool immediately = rule->options.inject.immediately;
475 
476     if (rule->options.inject.once) {
477         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
478         remove_rule(rule);
479     }
480 
481     if (immediately) {
482         return NULL;
483     }
484 
485     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
486     acb->ret = -error;
487 
488     bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
489     acb->bh = bh;
490     qemu_bh_schedule(bh);
491 
492     return &acb->common;
493 }
494 
495 static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
496     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
497     BlockCompletionFunc *cb, void *opaque)
498 {
499     BDRVBlkdebugState *s = bs->opaque;
500     BlkdebugRule *rule = NULL;
501 
502     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
503         if (rule->options.inject.sector == -1 ||
504             (rule->options.inject.sector >= sector_num &&
505              rule->options.inject.sector < sector_num + nb_sectors)) {
506             break;
507         }
508     }
509 
510     if (rule && rule->options.inject.error) {
511         return inject_error(bs, cb, opaque, rule);
512     }
513 
514     return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
515                           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->bs, sector_num, qiov, nb_sectors,
538                            cb, opaque);
539 }
540 
541 static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
542     BlockCompletionFunc *cb, void *opaque)
543 {
544     BDRVBlkdebugState *s = bs->opaque;
545     BlkdebugRule *rule = NULL;
546 
547     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
548         if (rule->options.inject.sector == -1) {
549             break;
550         }
551     }
552 
553     if (rule && rule->options.inject.error) {
554         return inject_error(bs, cb, opaque, rule);
555     }
556 
557     return bdrv_aio_flush(bs->file->bs, cb, opaque);
558 }
559 
560 
561 static void blkdebug_close(BlockDriverState *bs)
562 {
563     BDRVBlkdebugState *s = bs->opaque;
564     BlkdebugRule *rule, *next;
565     int i;
566 
567     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
568         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
569             remove_rule(rule);
570         }
571     }
572 }
573 
574 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
575 {
576     BDRVBlkdebugState *s = bs->opaque;
577     BlkdebugSuspendedReq r;
578 
579     r = (BlkdebugSuspendedReq) {
580         .co         = qemu_coroutine_self(),
581         .tag        = g_strdup(rule->options.suspend.tag),
582     };
583 
584     remove_rule(rule);
585     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
586 
587     if (!qtest_enabled()) {
588         printf("blkdebug: Suspended request '%s'\n", r.tag);
589     }
590     qemu_coroutine_yield();
591     if (!qtest_enabled()) {
592         printf("blkdebug: Resuming request '%s'\n", r.tag);
593     }
594 
595     QLIST_REMOVE(&r, next);
596     g_free(r.tag);
597 }
598 
599 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
600     bool injected)
601 {
602     BDRVBlkdebugState *s = bs->opaque;
603 
604     /* Only process rules for the current state */
605     if (rule->state && rule->state != s->state) {
606         return injected;
607     }
608 
609     /* Take the action */
610     switch (rule->action) {
611     case ACTION_INJECT_ERROR:
612         if (!injected) {
613             QSIMPLEQ_INIT(&s->active_rules);
614             injected = true;
615         }
616         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
617         break;
618 
619     case ACTION_SET_STATE:
620         s->new_state = rule->options.set_state.new_state;
621         break;
622 
623     case ACTION_SUSPEND:
624         suspend_request(bs, rule);
625         break;
626     }
627     return injected;
628 }
629 
630 static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
631 {
632     BDRVBlkdebugState *s = bs->opaque;
633     struct BlkdebugRule *rule, *next;
634     bool injected;
635 
636     assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
637 
638     injected = false;
639     s->new_state = s->state;
640     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
641         injected = process_rule(bs, rule, injected);
642     }
643     s->state = s->new_state;
644 }
645 
646 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
647                                      const char *tag)
648 {
649     BDRVBlkdebugState *s = bs->opaque;
650     struct BlkdebugRule *rule;
651     BlkDebugEvent blkdebug_event;
652 
653     if (get_event_by_name(event, &blkdebug_event) < 0) {
654         return -ENOENT;
655     }
656 
657 
658     rule = g_malloc(sizeof(*rule));
659     *rule = (struct BlkdebugRule) {
660         .event  = blkdebug_event,
661         .action = ACTION_SUSPEND,
662         .state  = 0,
663         .options.suspend.tag = g_strdup(tag),
664     };
665 
666     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
667 
668     return 0;
669 }
670 
671 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
672 {
673     BDRVBlkdebugState *s = bs->opaque;
674     BlkdebugSuspendedReq *r, *next;
675 
676     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
677         if (!strcmp(r->tag, tag)) {
678             qemu_coroutine_enter(r->co, NULL);
679             return 0;
680         }
681     }
682     return -ENOENT;
683 }
684 
685 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
686                                             const char *tag)
687 {
688     BDRVBlkdebugState *s = bs->opaque;
689     BlkdebugSuspendedReq *r, *r_next;
690     BlkdebugRule *rule, *next;
691     int i, ret = -ENOENT;
692 
693     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
694         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
695             if (rule->action == ACTION_SUSPEND &&
696                 !strcmp(rule->options.suspend.tag, tag)) {
697                 remove_rule(rule);
698                 ret = 0;
699             }
700         }
701     }
702     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
703         if (!strcmp(r->tag, tag)) {
704             qemu_coroutine_enter(r->co, NULL);
705             ret = 0;
706         }
707     }
708     return ret;
709 }
710 
711 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
712 {
713     BDRVBlkdebugState *s = bs->opaque;
714     BlkdebugSuspendedReq *r;
715 
716     QLIST_FOREACH(r, &s->suspended_reqs, next) {
717         if (!strcmp(r->tag, tag)) {
718             return true;
719         }
720     }
721     return false;
722 }
723 
724 static int64_t blkdebug_getlength(BlockDriverState *bs)
725 {
726     return bdrv_getlength(bs->file->bs);
727 }
728 
729 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
730 {
731     return bdrv_truncate(bs->file->bs, offset);
732 }
733 
734 static void blkdebug_refresh_filename(BlockDriverState *bs)
735 {
736     QDict *opts;
737     const QDictEntry *e;
738     bool force_json = false;
739 
740     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
741         if (strcmp(qdict_entry_key(e), "config") &&
742             strcmp(qdict_entry_key(e), "x-image") &&
743             strcmp(qdict_entry_key(e), "image") &&
744             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
745         {
746             force_json = true;
747             break;
748         }
749     }
750 
751     if (force_json && !bs->file->bs->full_open_options) {
752         /* The config file cannot be recreated, so creating a plain filename
753          * is impossible */
754         return;
755     }
756 
757     if (!force_json && bs->file->bs->exact_filename[0]) {
758         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
759                  "blkdebug:%s:%s",
760                  qdict_get_try_str(bs->options, "config") ?: "",
761                  bs->file->bs->exact_filename);
762     }
763 
764     opts = qdict_new();
765     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
766 
767     QINCREF(bs->file->bs->full_open_options);
768     qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
769 
770     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
771         if (strcmp(qdict_entry_key(e), "x-image") &&
772             strcmp(qdict_entry_key(e), "image") &&
773             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
774         {
775             qobject_incref(qdict_entry_value(e));
776             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
777         }
778     }
779 
780     bs->full_open_options = opts;
781 }
782 
783 static BlockDriver bdrv_blkdebug = {
784     .format_name            = "blkdebug",
785     .protocol_name          = "blkdebug",
786     .instance_size          = sizeof(BDRVBlkdebugState),
787 
788     .bdrv_parse_filename    = blkdebug_parse_filename,
789     .bdrv_file_open         = blkdebug_open,
790     .bdrv_close             = blkdebug_close,
791     .bdrv_getlength         = blkdebug_getlength,
792     .bdrv_truncate          = blkdebug_truncate,
793     .bdrv_refresh_filename  = blkdebug_refresh_filename,
794 
795     .bdrv_aio_readv         = blkdebug_aio_readv,
796     .bdrv_aio_writev        = blkdebug_aio_writev,
797     .bdrv_aio_flush         = blkdebug_aio_flush,
798 
799     .bdrv_debug_event           = blkdebug_debug_event,
800     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
801     .bdrv_debug_remove_breakpoint
802                                 = blkdebug_debug_remove_breakpoint,
803     .bdrv_debug_resume          = blkdebug_debug_resume,
804     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
805 };
806 
807 static void bdrv_blkdebug_init(void)
808 {
809     bdrv_register(&bdrv_blkdebug);
810 }
811 
812 block_init(bdrv_blkdebug_init);
813