xref: /qemu/block/blkdebug.c (revision bfa3ab61)
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 };
220 
221 static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
222 {
223     struct add_rule_data *d = opaque;
224     BDRVBlkdebugState *s = d->s;
225     const char* event_name;
226     BlkDebugEvent event;
227     struct BlkdebugRule *rule;
228 
229     /* Find the right event for the rule */
230     event_name = qemu_opt_get(opts, "event");
231     if (!event_name) {
232         error_setg(errp, "Missing event name for rule");
233         return -1;
234     } else if (get_event_by_name(event_name, &event) < 0) {
235         error_setg(errp, "Invalid event name \"%s\"", event_name);
236         return -1;
237     }
238 
239     /* Set attributes common for all actions */
240     rule = g_malloc0(sizeof(*rule));
241     *rule = (struct BlkdebugRule) {
242         .event  = event,
243         .action = d->action,
244         .state  = qemu_opt_get_number(opts, "state", 0),
245     };
246 
247     /* Parse action-specific options */
248     switch (d->action) {
249     case ACTION_INJECT_ERROR:
250         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
251         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
252         rule->options.inject.immediately =
253             qemu_opt_get_bool(opts, "immediately", 0);
254         rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
255         break;
256 
257     case ACTION_SET_STATE:
258         rule->options.set_state.new_state =
259             qemu_opt_get_number(opts, "new_state", 0);
260         break;
261 
262     case ACTION_SUSPEND:
263         rule->options.suspend.tag =
264             g_strdup(qemu_opt_get(opts, "tag"));
265         break;
266     };
267 
268     /* Add the rule */
269     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
270 
271     return 0;
272 }
273 
274 static void remove_rule(BlkdebugRule *rule)
275 {
276     switch (rule->action) {
277     case ACTION_INJECT_ERROR:
278     case ACTION_SET_STATE:
279         break;
280     case ACTION_SUSPEND:
281         g_free(rule->options.suspend.tag);
282         break;
283     }
284 
285     QLIST_REMOVE(rule, next);
286     g_free(rule);
287 }
288 
289 static int read_config(BDRVBlkdebugState *s, const char *filename,
290                        QDict *options, Error **errp)
291 {
292     FILE *f = NULL;
293     int ret;
294     struct add_rule_data d;
295     Error *local_err = NULL;
296 
297     if (filename) {
298         f = fopen(filename, "r");
299         if (f == NULL) {
300             error_setg_errno(errp, errno, "Could not read blkdebug config file");
301             return -errno;
302         }
303 
304         ret = qemu_config_parse(f, config_groups, filename);
305         if (ret < 0) {
306             error_setg(errp, "Could not parse blkdebug config file");
307             ret = -EINVAL;
308             goto fail;
309         }
310     }
311 
312     qemu_config_parse_qdict(options, config_groups, &local_err);
313     if (local_err) {
314         error_propagate(errp, local_err);
315         ret = -EINVAL;
316         goto fail;
317     }
318 
319     d.s = s;
320     d.action = ACTION_INJECT_ERROR;
321     qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
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, &local_err);
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                           bs, &child_file, 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     bool immediately = rule->options.inject.immediately;
474 
475     if (rule->options.inject.once) {
476         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
477         remove_rule(rule);
478     }
479 
480     if (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 int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
723 {
724     return bdrv_truncate(bs->file, offset);
725 }
726 
727 static void blkdebug_refresh_filename(BlockDriverState *bs)
728 {
729     QDict *opts;
730     const QDictEntry *e;
731     bool force_json = false;
732 
733     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
734         if (strcmp(qdict_entry_key(e), "config") &&
735             strcmp(qdict_entry_key(e), "x-image") &&
736             strcmp(qdict_entry_key(e), "image") &&
737             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
738         {
739             force_json = true;
740             break;
741         }
742     }
743 
744     if (force_json && !bs->file->full_open_options) {
745         /* The config file cannot be recreated, so creating a plain filename
746          * is impossible */
747         return;
748     }
749 
750     if (!force_json && bs->file->exact_filename[0]) {
751         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
752                  "blkdebug:%s:%s",
753                  qdict_get_try_str(bs->options, "config") ?: "",
754                  bs->file->exact_filename);
755     }
756 
757     opts = qdict_new();
758     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
759 
760     QINCREF(bs->file->full_open_options);
761     qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
762 
763     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
764         if (strcmp(qdict_entry_key(e), "x-image") &&
765             strcmp(qdict_entry_key(e), "image") &&
766             strncmp(qdict_entry_key(e), "image.", strlen("image.")))
767         {
768             qobject_incref(qdict_entry_value(e));
769             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
770         }
771     }
772 
773     bs->full_open_options = opts;
774 }
775 
776 static BlockDriver bdrv_blkdebug = {
777     .format_name            = "blkdebug",
778     .protocol_name          = "blkdebug",
779     .instance_size          = sizeof(BDRVBlkdebugState),
780 
781     .bdrv_parse_filename    = blkdebug_parse_filename,
782     .bdrv_file_open         = blkdebug_open,
783     .bdrv_close             = blkdebug_close,
784     .bdrv_getlength         = blkdebug_getlength,
785     .bdrv_truncate          = blkdebug_truncate,
786     .bdrv_refresh_filename  = blkdebug_refresh_filename,
787 
788     .bdrv_aio_readv         = blkdebug_aio_readv,
789     .bdrv_aio_writev        = blkdebug_aio_writev,
790     .bdrv_aio_flush         = blkdebug_aio_flush,
791 
792     .bdrv_debug_event           = blkdebug_debug_event,
793     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
794     .bdrv_debug_remove_breakpoint
795                                 = blkdebug_debug_remove_breakpoint,
796     .bdrv_debug_resume          = blkdebug_debug_resume,
797     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
798 };
799 
800 static void bdrv_blkdebug_init(void)
801 {
802     bdrv_register(&bdrv_blkdebug);
803 }
804 
805 block_init(bdrv_blkdebug_init);
806