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