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