xref: /openbmc/qemu/block/blkdebug.c (revision 795c40b8)
1 /*
2  * Block protocol for I/O error injection
3  *
4  * Copyright (C) 2016-2017 Red Hat, Inc.
5  * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #include "qemu/osdep.h"
27 #include "qapi/error.h"
28 #include "qemu/cutils.h"
29 #include "qemu/config-file.h"
30 #include "block/block_int.h"
31 #include "qemu/module.h"
32 #include "qapi/qmp/qbool.h"
33 #include "qapi/qmp/qdict.h"
34 #include "qapi/qmp/qint.h"
35 #include "qapi/qmp/qstring.h"
36 #include "sysemu/qtest.h"
37 
38 typedef struct BDRVBlkdebugState {
39     int state;
40     int new_state;
41     uint64_t align;
42     uint64_t max_transfer;
43     uint64_t opt_write_zero;
44     uint64_t max_write_zero;
45     uint64_t opt_discard;
46     uint64_t max_discard;
47 
48     /* For blkdebug_refresh_filename() */
49     char *config_file;
50 
51     QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
52     QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
53     QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
54 } BDRVBlkdebugState;
55 
56 typedef struct BlkdebugAIOCB {
57     BlockAIOCB common;
58     int ret;
59 } BlkdebugAIOCB;
60 
61 typedef struct BlkdebugSuspendedReq {
62     Coroutine *co;
63     char *tag;
64     QLIST_ENTRY(BlkdebugSuspendedReq) next;
65 } BlkdebugSuspendedReq;
66 
67 enum {
68     ACTION_INJECT_ERROR,
69     ACTION_SET_STATE,
70     ACTION_SUSPEND,
71 };
72 
73 typedef struct BlkdebugRule {
74     BlkdebugEvent event;
75     int action;
76     int state;
77     union {
78         struct {
79             int error;
80             int immediately;
81             int once;
82             int64_t offset;
83         } inject;
84         struct {
85             int new_state;
86         } set_state;
87         struct {
88             char *tag;
89         } suspend;
90     } options;
91     QLIST_ENTRY(BlkdebugRule) next;
92     QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
93 } BlkdebugRule;
94 
95 static QemuOptsList inject_error_opts = {
96     .name = "inject-error",
97     .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
98     .desc = {
99         {
100             .name = "event",
101             .type = QEMU_OPT_STRING,
102         },
103         {
104             .name = "state",
105             .type = QEMU_OPT_NUMBER,
106         },
107         {
108             .name = "errno",
109             .type = QEMU_OPT_NUMBER,
110         },
111         {
112             .name = "sector",
113             .type = QEMU_OPT_NUMBER,
114         },
115         {
116             .name = "once",
117             .type = QEMU_OPT_BOOL,
118         },
119         {
120             .name = "immediately",
121             .type = QEMU_OPT_BOOL,
122         },
123         { /* end of list */ }
124     },
125 };
126 
127 static QemuOptsList set_state_opts = {
128     .name = "set-state",
129     .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
130     .desc = {
131         {
132             .name = "event",
133             .type = QEMU_OPT_STRING,
134         },
135         {
136             .name = "state",
137             .type = QEMU_OPT_NUMBER,
138         },
139         {
140             .name = "new_state",
141             .type = QEMU_OPT_NUMBER,
142         },
143         { /* end of list */ }
144     },
145 };
146 
147 static QemuOptsList *config_groups[] = {
148     &inject_error_opts,
149     &set_state_opts,
150     NULL
151 };
152 
153 static int get_event_by_name(const char *name, BlkdebugEvent *event)
154 {
155     int i;
156 
157     for (i = 0; i < BLKDBG__MAX; i++) {
158         if (!strcmp(BlkdebugEvent_lookup[i], name)) {
159             *event = i;
160             return 0;
161         }
162     }
163 
164     return -1;
165 }
166 
167 struct add_rule_data {
168     BDRVBlkdebugState *s;
169     int action;
170 };
171 
172 static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
173 {
174     struct add_rule_data *d = opaque;
175     BDRVBlkdebugState *s = d->s;
176     const char* event_name;
177     BlkdebugEvent event;
178     struct BlkdebugRule *rule;
179     int64_t sector;
180 
181     /* Find the right event for the rule */
182     event_name = qemu_opt_get(opts, "event");
183     if (!event_name) {
184         error_setg(errp, "Missing event name for rule");
185         return -1;
186     } else if (get_event_by_name(event_name, &event) < 0) {
187         error_setg(errp, "Invalid event name \"%s\"", event_name);
188         return -1;
189     }
190 
191     /* Set attributes common for all actions */
192     rule = g_malloc0(sizeof(*rule));
193     *rule = (struct BlkdebugRule) {
194         .event  = event,
195         .action = d->action,
196         .state  = qemu_opt_get_number(opts, "state", 0),
197     };
198 
199     /* Parse action-specific options */
200     switch (d->action) {
201     case ACTION_INJECT_ERROR:
202         rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
203         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
204         rule->options.inject.immediately =
205             qemu_opt_get_bool(opts, "immediately", 0);
206         sector = qemu_opt_get_number(opts, "sector", -1);
207         rule->options.inject.offset =
208             sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
209         break;
210 
211     case ACTION_SET_STATE:
212         rule->options.set_state.new_state =
213             qemu_opt_get_number(opts, "new_state", 0);
214         break;
215 
216     case ACTION_SUSPEND:
217         rule->options.suspend.tag =
218             g_strdup(qemu_opt_get(opts, "tag"));
219         break;
220     };
221 
222     /* Add the rule */
223     QLIST_INSERT_HEAD(&s->rules[event], rule, next);
224 
225     return 0;
226 }
227 
228 static void remove_rule(BlkdebugRule *rule)
229 {
230     switch (rule->action) {
231     case ACTION_INJECT_ERROR:
232     case ACTION_SET_STATE:
233         break;
234     case ACTION_SUSPEND:
235         g_free(rule->options.suspend.tag);
236         break;
237     }
238 
239     QLIST_REMOVE(rule, next);
240     g_free(rule);
241 }
242 
243 static int read_config(BDRVBlkdebugState *s, const char *filename,
244                        QDict *options, Error **errp)
245 {
246     FILE *f = NULL;
247     int ret;
248     struct add_rule_data d;
249     Error *local_err = NULL;
250 
251     if (filename) {
252         f = fopen(filename, "r");
253         if (f == NULL) {
254             error_setg_errno(errp, errno, "Could not read blkdebug config file");
255             return -errno;
256         }
257 
258         ret = qemu_config_parse(f, config_groups, filename);
259         if (ret < 0) {
260             error_setg(errp, "Could not parse blkdebug config file");
261             ret = -EINVAL;
262             goto fail;
263         }
264     }
265 
266     qemu_config_parse_qdict(options, config_groups, &local_err);
267     if (local_err) {
268         error_propagate(errp, local_err);
269         ret = -EINVAL;
270         goto fail;
271     }
272 
273     d.s = s;
274     d.action = ACTION_INJECT_ERROR;
275     qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
276     if (local_err) {
277         error_propagate(errp, local_err);
278         ret = -EINVAL;
279         goto fail;
280     }
281 
282     d.action = ACTION_SET_STATE;
283     qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
284     if (local_err) {
285         error_propagate(errp, local_err);
286         ret = -EINVAL;
287         goto fail;
288     }
289 
290     ret = 0;
291 fail:
292     qemu_opts_reset(&inject_error_opts);
293     qemu_opts_reset(&set_state_opts);
294     if (f) {
295         fclose(f);
296     }
297     return ret;
298 }
299 
300 /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
301 static void blkdebug_parse_filename(const char *filename, QDict *options,
302                                     Error **errp)
303 {
304     const char *c;
305 
306     /* Parse the blkdebug: prefix */
307     if (!strstart(filename, "blkdebug:", &filename)) {
308         /* There was no prefix; therefore, all options have to be already
309            present in the QDict (except for the filename) */
310         qdict_put_str(options, "x-image", filename);
311         return;
312     }
313 
314     /* Parse config file path */
315     c = strchr(filename, ':');
316     if (c == NULL) {
317         error_setg(errp, "blkdebug requires both config file and image path");
318         return;
319     }
320 
321     if (c != filename) {
322         QString *config_path;
323         config_path = qstring_from_substr(filename, 0, c - filename - 1);
324         qdict_put(options, "config", config_path);
325     }
326 
327     /* TODO Allow multi-level nesting and set file.filename here */
328     filename = c + 1;
329     qdict_put_str(options, "x-image", filename);
330 }
331 
332 static QemuOptsList runtime_opts = {
333     .name = "blkdebug",
334     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
335     .desc = {
336         {
337             .name = "config",
338             .type = QEMU_OPT_STRING,
339             .help = "Path to the configuration file",
340         },
341         {
342             .name = "x-image",
343             .type = QEMU_OPT_STRING,
344             .help = "[internal use only, will be removed]",
345         },
346         {
347             .name = "align",
348             .type = QEMU_OPT_SIZE,
349             .help = "Required alignment in bytes",
350         },
351         {
352             .name = "max-transfer",
353             .type = QEMU_OPT_SIZE,
354             .help = "Maximum transfer size in bytes",
355         },
356         {
357             .name = "opt-write-zero",
358             .type = QEMU_OPT_SIZE,
359             .help = "Optimum write zero alignment in bytes",
360         },
361         {
362             .name = "max-write-zero",
363             .type = QEMU_OPT_SIZE,
364             .help = "Maximum write zero size in bytes",
365         },
366         {
367             .name = "opt-discard",
368             .type = QEMU_OPT_SIZE,
369             .help = "Optimum discard alignment in bytes",
370         },
371         {
372             .name = "max-discard",
373             .type = QEMU_OPT_SIZE,
374             .help = "Maximum discard size in bytes",
375         },
376         { /* end of list */ }
377     },
378 };
379 
380 static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
381                          Error **errp)
382 {
383     BDRVBlkdebugState *s = bs->opaque;
384     QemuOpts *opts;
385     Error *local_err = NULL;
386     int ret;
387     uint64_t align;
388 
389     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
390     qemu_opts_absorb_qdict(opts, options, &local_err);
391     if (local_err) {
392         error_propagate(errp, local_err);
393         ret = -EINVAL;
394         goto out;
395     }
396 
397     /* Read rules from config file or command line options */
398     s->config_file = g_strdup(qemu_opt_get(opts, "config"));
399     ret = read_config(s, s->config_file, options, errp);
400     if (ret) {
401         goto out;
402     }
403 
404     /* Set initial state */
405     s->state = 1;
406 
407     /* Open the image file */
408     bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
409                                bs, &child_file, false, &local_err);
410     if (local_err) {
411         ret = -EINVAL;
412         error_propagate(errp, local_err);
413         goto out;
414     }
415 
416     bs->supported_write_flags = BDRV_REQ_FUA &
417         bs->file->bs->supported_write_flags;
418     bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
419         bs->file->bs->supported_zero_flags;
420     ret = -EINVAL;
421 
422     /* Set alignment overrides */
423     s->align = qemu_opt_get_size(opts, "align", 0);
424     if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
425         error_setg(errp, "Cannot meet constraints with align %" PRIu64,
426                    s->align);
427         goto out;
428     }
429     align = MAX(s->align, bs->file->bs->bl.request_alignment);
430 
431     s->max_transfer = qemu_opt_get_size(opts, "max-transfer", 0);
432     if (s->max_transfer &&
433         (s->max_transfer >= INT_MAX ||
434          !QEMU_IS_ALIGNED(s->max_transfer, align))) {
435         error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
436                    s->max_transfer);
437         goto out;
438     }
439 
440     s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
441     if (s->opt_write_zero &&
442         (s->opt_write_zero >= INT_MAX ||
443          !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
444         error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
445                    s->opt_write_zero);
446         goto out;
447     }
448 
449     s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
450     if (s->max_write_zero &&
451         (s->max_write_zero >= INT_MAX ||
452          !QEMU_IS_ALIGNED(s->max_write_zero,
453                           MAX(s->opt_write_zero, align)))) {
454         error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
455                    s->max_write_zero);
456         goto out;
457     }
458 
459     s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
460     if (s->opt_discard &&
461         (s->opt_discard >= INT_MAX ||
462          !QEMU_IS_ALIGNED(s->opt_discard, align))) {
463         error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
464                    s->opt_discard);
465         goto out;
466     }
467 
468     s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
469     if (s->max_discard &&
470         (s->max_discard >= INT_MAX ||
471          !QEMU_IS_ALIGNED(s->max_discard,
472                           MAX(s->opt_discard, align)))) {
473         error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
474                    s->max_discard);
475         goto out;
476     }
477 
478     ret = 0;
479 out:
480     if (ret < 0) {
481         g_free(s->config_file);
482     }
483     qemu_opts_del(opts);
484     return ret;
485 }
486 
487 static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
488 {
489     BDRVBlkdebugState *s = bs->opaque;
490     BlkdebugRule *rule = NULL;
491     int error;
492     bool immediately;
493 
494     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
495         uint64_t inject_offset = rule->options.inject.offset;
496 
497         if (inject_offset == -1 ||
498             (bytes && inject_offset >= offset &&
499              inject_offset < offset + bytes))
500         {
501             break;
502         }
503     }
504 
505     if (!rule || !rule->options.inject.error) {
506         return 0;
507     }
508 
509     immediately = rule->options.inject.immediately;
510     error = rule->options.inject.error;
511 
512     if (rule->options.inject.once) {
513         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
514         remove_rule(rule);
515     }
516 
517     if (!immediately) {
518         aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
519         qemu_coroutine_yield();
520     }
521 
522     return -error;
523 }
524 
525 static int coroutine_fn
526 blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
527                    QEMUIOVector *qiov, int flags)
528 {
529     int err;
530 
531     /* Sanity check block layer guarantees */
532     assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
533     assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
534     if (bs->bl.max_transfer) {
535         assert(bytes <= bs->bl.max_transfer);
536     }
537 
538     err = rule_check(bs, offset, bytes);
539     if (err) {
540         return err;
541     }
542 
543     return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
544 }
545 
546 static int coroutine_fn
547 blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
548                     QEMUIOVector *qiov, int flags)
549 {
550     int err;
551 
552     /* Sanity check block layer guarantees */
553     assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
554     assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
555     if (bs->bl.max_transfer) {
556         assert(bytes <= bs->bl.max_transfer);
557     }
558 
559     err = rule_check(bs, offset, bytes);
560     if (err) {
561         return err;
562     }
563 
564     return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
565 }
566 
567 static int blkdebug_co_flush(BlockDriverState *bs)
568 {
569     int err = rule_check(bs, 0, 0);
570 
571     if (err) {
572         return err;
573     }
574 
575     return bdrv_co_flush(bs->file->bs);
576 }
577 
578 static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
579                                                   int64_t offset, int count,
580                                                   BdrvRequestFlags flags)
581 {
582     uint32_t align = MAX(bs->bl.request_alignment,
583                          bs->bl.pwrite_zeroes_alignment);
584     int err;
585 
586     /* Only pass through requests that are larger than requested
587      * preferred alignment (so that we test the fallback to writes on
588      * unaligned portions), and check that the block layer never hands
589      * us anything unaligned that crosses an alignment boundary.  */
590     if (count < align) {
591         assert(QEMU_IS_ALIGNED(offset, align) ||
592                QEMU_IS_ALIGNED(offset + count, align) ||
593                DIV_ROUND_UP(offset, align) ==
594                DIV_ROUND_UP(offset + count, align));
595         return -ENOTSUP;
596     }
597     assert(QEMU_IS_ALIGNED(offset, align));
598     assert(QEMU_IS_ALIGNED(count, align));
599     if (bs->bl.max_pwrite_zeroes) {
600         assert(count <= bs->bl.max_pwrite_zeroes);
601     }
602 
603     err = rule_check(bs, offset, count);
604     if (err) {
605         return err;
606     }
607 
608     return bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
609 }
610 
611 static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
612                                              int64_t offset, int count)
613 {
614     uint32_t align = bs->bl.pdiscard_alignment;
615     int err;
616 
617     /* Only pass through requests that are larger than requested
618      * minimum alignment, and ensure that unaligned requests do not
619      * cross optimum discard boundaries. */
620     if (count < bs->bl.request_alignment) {
621         assert(QEMU_IS_ALIGNED(offset, align) ||
622                QEMU_IS_ALIGNED(offset + count, align) ||
623                DIV_ROUND_UP(offset, align) ==
624                DIV_ROUND_UP(offset + count, align));
625         return -ENOTSUP;
626     }
627     assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
628     assert(QEMU_IS_ALIGNED(count, bs->bl.request_alignment));
629     if (align && count >= align) {
630         assert(QEMU_IS_ALIGNED(offset, align));
631         assert(QEMU_IS_ALIGNED(count, align));
632     }
633     if (bs->bl.max_pdiscard) {
634         assert(count <= bs->bl.max_pdiscard);
635     }
636 
637     err = rule_check(bs, offset, count);
638     if (err) {
639         return err;
640     }
641 
642     return bdrv_co_pdiscard(bs->file->bs, offset, count);
643 }
644 
645 static void blkdebug_close(BlockDriverState *bs)
646 {
647     BDRVBlkdebugState *s = bs->opaque;
648     BlkdebugRule *rule, *next;
649     int i;
650 
651     for (i = 0; i < BLKDBG__MAX; i++) {
652         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
653             remove_rule(rule);
654         }
655     }
656 
657     g_free(s->config_file);
658 }
659 
660 static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
661 {
662     BDRVBlkdebugState *s = bs->opaque;
663     BlkdebugSuspendedReq r;
664 
665     r = (BlkdebugSuspendedReq) {
666         .co         = qemu_coroutine_self(),
667         .tag        = g_strdup(rule->options.suspend.tag),
668     };
669 
670     remove_rule(rule);
671     QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
672 
673     if (!qtest_enabled()) {
674         printf("blkdebug: Suspended request '%s'\n", r.tag);
675     }
676     qemu_coroutine_yield();
677     if (!qtest_enabled()) {
678         printf("blkdebug: Resuming request '%s'\n", r.tag);
679     }
680 
681     QLIST_REMOVE(&r, next);
682     g_free(r.tag);
683 }
684 
685 static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
686     bool injected)
687 {
688     BDRVBlkdebugState *s = bs->opaque;
689 
690     /* Only process rules for the current state */
691     if (rule->state && rule->state != s->state) {
692         return injected;
693     }
694 
695     /* Take the action */
696     switch (rule->action) {
697     case ACTION_INJECT_ERROR:
698         if (!injected) {
699             QSIMPLEQ_INIT(&s->active_rules);
700             injected = true;
701         }
702         QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
703         break;
704 
705     case ACTION_SET_STATE:
706         s->new_state = rule->options.set_state.new_state;
707         break;
708 
709     case ACTION_SUSPEND:
710         suspend_request(bs, rule);
711         break;
712     }
713     return injected;
714 }
715 
716 static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
717 {
718     BDRVBlkdebugState *s = bs->opaque;
719     struct BlkdebugRule *rule, *next;
720     bool injected;
721 
722     assert((int)event >= 0 && event < BLKDBG__MAX);
723 
724     injected = false;
725     s->new_state = s->state;
726     QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
727         injected = process_rule(bs, rule, injected);
728     }
729     s->state = s->new_state;
730 }
731 
732 static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
733                                      const char *tag)
734 {
735     BDRVBlkdebugState *s = bs->opaque;
736     struct BlkdebugRule *rule;
737     BlkdebugEvent blkdebug_event;
738 
739     if (get_event_by_name(event, &blkdebug_event) < 0) {
740         return -ENOENT;
741     }
742 
743 
744     rule = g_malloc(sizeof(*rule));
745     *rule = (struct BlkdebugRule) {
746         .event  = blkdebug_event,
747         .action = ACTION_SUSPEND,
748         .state  = 0,
749         .options.suspend.tag = g_strdup(tag),
750     };
751 
752     QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
753 
754     return 0;
755 }
756 
757 static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
758 {
759     BDRVBlkdebugState *s = bs->opaque;
760     BlkdebugSuspendedReq *r, *next;
761 
762     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
763         if (!strcmp(r->tag, tag)) {
764             qemu_coroutine_enter(r->co);
765             return 0;
766         }
767     }
768     return -ENOENT;
769 }
770 
771 static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
772                                             const char *tag)
773 {
774     BDRVBlkdebugState *s = bs->opaque;
775     BlkdebugSuspendedReq *r, *r_next;
776     BlkdebugRule *rule, *next;
777     int i, ret = -ENOENT;
778 
779     for (i = 0; i < BLKDBG__MAX; i++) {
780         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
781             if (rule->action == ACTION_SUSPEND &&
782                 !strcmp(rule->options.suspend.tag, tag)) {
783                 remove_rule(rule);
784                 ret = 0;
785             }
786         }
787     }
788     QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
789         if (!strcmp(r->tag, tag)) {
790             qemu_coroutine_enter(r->co);
791             ret = 0;
792         }
793     }
794     return ret;
795 }
796 
797 static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
798 {
799     BDRVBlkdebugState *s = bs->opaque;
800     BlkdebugSuspendedReq *r;
801 
802     QLIST_FOREACH(r, &s->suspended_reqs, next) {
803         if (!strcmp(r->tag, tag)) {
804             return true;
805         }
806     }
807     return false;
808 }
809 
810 static int64_t blkdebug_getlength(BlockDriverState *bs)
811 {
812     return bdrv_getlength(bs->file->bs);
813 }
814 
815 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
816 {
817     return bdrv_truncate(bs->file, offset, errp);
818 }
819 
820 static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
821 {
822     BDRVBlkdebugState *s = bs->opaque;
823     QDict *opts;
824     const QDictEntry *e;
825     bool force_json = false;
826 
827     for (e = qdict_first(options); e; e = qdict_next(options, e)) {
828         if (strcmp(qdict_entry_key(e), "config") &&
829             strcmp(qdict_entry_key(e), "x-image"))
830         {
831             force_json = true;
832             break;
833         }
834     }
835 
836     if (force_json && !bs->file->bs->full_open_options) {
837         /* The config file cannot be recreated, so creating a plain filename
838          * is impossible */
839         return;
840     }
841 
842     if (!force_json && bs->file->bs->exact_filename[0]) {
843         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
844                  "blkdebug:%s:%s", s->config_file ?: "",
845                  bs->file->bs->exact_filename);
846     }
847 
848     opts = qdict_new();
849     qdict_put_str(opts, "driver", "blkdebug");
850 
851     QINCREF(bs->file->bs->full_open_options);
852     qdict_put(opts, "image", bs->file->bs->full_open_options);
853 
854     for (e = qdict_first(options); e; e = qdict_next(options, e)) {
855         if (strcmp(qdict_entry_key(e), "x-image")) {
856             qobject_incref(qdict_entry_value(e));
857             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
858         }
859     }
860 
861     bs->full_open_options = opts;
862 }
863 
864 static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
865 {
866     BDRVBlkdebugState *s = bs->opaque;
867 
868     if (s->align) {
869         bs->bl.request_alignment = s->align;
870     }
871     if (s->max_transfer) {
872         bs->bl.max_transfer = s->max_transfer;
873     }
874     if (s->opt_write_zero) {
875         bs->bl.pwrite_zeroes_alignment = s->opt_write_zero;
876     }
877     if (s->max_write_zero) {
878         bs->bl.max_pwrite_zeroes = s->max_write_zero;
879     }
880     if (s->opt_discard) {
881         bs->bl.pdiscard_alignment = s->opt_discard;
882     }
883     if (s->max_discard) {
884         bs->bl.max_pdiscard = s->max_discard;
885     }
886 }
887 
888 static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
889                                    BlockReopenQueue *queue, Error **errp)
890 {
891     return 0;
892 }
893 
894 static BlockDriver bdrv_blkdebug = {
895     .format_name            = "blkdebug",
896     .protocol_name          = "blkdebug",
897     .instance_size          = sizeof(BDRVBlkdebugState),
898 
899     .bdrv_parse_filename    = blkdebug_parse_filename,
900     .bdrv_file_open         = blkdebug_open,
901     .bdrv_close             = blkdebug_close,
902     .bdrv_reopen_prepare    = blkdebug_reopen_prepare,
903     .bdrv_child_perm        = bdrv_filter_default_perms,
904 
905     .bdrv_getlength         = blkdebug_getlength,
906     .bdrv_truncate          = blkdebug_truncate,
907     .bdrv_refresh_filename  = blkdebug_refresh_filename,
908     .bdrv_refresh_limits    = blkdebug_refresh_limits,
909 
910     .bdrv_co_preadv         = blkdebug_co_preadv,
911     .bdrv_co_pwritev        = blkdebug_co_pwritev,
912     .bdrv_co_flush_to_disk  = blkdebug_co_flush,
913     .bdrv_co_pwrite_zeroes  = blkdebug_co_pwrite_zeroes,
914     .bdrv_co_pdiscard       = blkdebug_co_pdiscard,
915 
916     .bdrv_debug_event           = blkdebug_debug_event,
917     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
918     .bdrv_debug_remove_breakpoint
919                                 = blkdebug_debug_remove_breakpoint,
920     .bdrv_debug_resume          = blkdebug_debug_resume,
921     .bdrv_debug_is_suspended    = blkdebug_debug_is_suspended,
922 };
923 
924 static void bdrv_blkdebug_init(void)
925 {
926     bdrv_register(&bdrv_blkdebug);
927 }
928 
929 block_init(bdrv_blkdebug_init);
930