]> git.proxmox.com Git - mirror_qemu.git/blame - block/blkdebug.c
block: Split bdrv_merge_limits() from bdrv_refresh_limits()
[mirror_qemu.git] / block / blkdebug.c
CommitLineData
6a143727
KW
1/*
2 * Block protocol for I/O error injection
3 *
4 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
80c71a24 25#include "qemu/osdep.h"
da34e65c 26#include "qapi/error.h"
f348b6d1 27#include "qemu/cutils.h"
1de7afc9 28#include "qemu/config-file.h"
737e150e 29#include "block/block_int.h"
1de7afc9 30#include "qemu/module.h"
2c31b04c
HR
31#include "qapi/qmp/qbool.h"
32#include "qapi/qmp/qdict.h"
33#include "qapi/qmp/qint.h"
34#include "qapi/qmp/qstring.h"
20873526 35#include "sysemu/qtest.h"
6a143727
KW
36
37typedef struct BDRVBlkdebugState {
571cd43e 38 int state;
8f96b5be 39 int new_state;
835db3ee 40 int align;
3c90c65d 41
7fb1cf16 42 QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
571cd43e 43 QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
3c90c65d 44 QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
6a143727
KW
45} BDRVBlkdebugState;
46
b9f66d96 47typedef struct BlkdebugAIOCB {
7c84b1b8 48 BlockAIOCB common;
b9f66d96
KW
49 QEMUBH *bh;
50 int ret;
51} BlkdebugAIOCB;
52
3c90c65d
KW
53typedef struct BlkdebugSuspendedReq {
54 Coroutine *co;
55 char *tag;
56 QLIST_ENTRY(BlkdebugSuspendedReq) next;
57} BlkdebugSuspendedReq;
58
d7331bed 59static const AIOCBInfo blkdebug_aiocb_info = {
4c781717 60 .aiocb_size = sizeof(BlkdebugAIOCB),
b9f66d96
KW
61};
62
8b9b0cc2
KW
63enum {
64 ACTION_INJECT_ERROR,
65 ACTION_SET_STATE,
3c90c65d 66 ACTION_SUSPEND,
8b9b0cc2
KW
67};
68
69typedef struct BlkdebugRule {
a31939e6 70 BlkdebugEvent event;
8b9b0cc2
KW
71 int action;
72 int state;
73 union {
74 struct {
75 int error;
76 int immediately;
77 int once;
e4780db4 78 int64_t sector;
8b9b0cc2
KW
79 } inject;
80 struct {
81 int new_state;
82 } set_state;
3c90c65d
KW
83 struct {
84 char *tag;
85 } suspend;
8b9b0cc2
KW
86 } options;
87 QLIST_ENTRY(BlkdebugRule) next;
571cd43e 88 QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
8b9b0cc2
KW
89} BlkdebugRule;
90
91static QemuOptsList inject_error_opts = {
92 .name = "inject-error",
93 .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
94 .desc = {
95 {
96 .name = "event",
97 .type = QEMU_OPT_STRING,
98 },
99 {
100 .name = "state",
101 .type = QEMU_OPT_NUMBER,
102 },
103 {
104 .name = "errno",
105 .type = QEMU_OPT_NUMBER,
106 },
e4780db4
PB
107 {
108 .name = "sector",
109 .type = QEMU_OPT_NUMBER,
110 },
8b9b0cc2
KW
111 {
112 .name = "once",
113 .type = QEMU_OPT_BOOL,
114 },
115 {
116 .name = "immediately",
117 .type = QEMU_OPT_BOOL,
118 },
119 { /* end of list */ }
120 },
121};
122
123static QemuOptsList set_state_opts = {
124 .name = "set-state",
327cdad4 125 .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
8b9b0cc2
KW
126 .desc = {
127 {
128 .name = "event",
129 .type = QEMU_OPT_STRING,
130 },
131 {
132 .name = "state",
133 .type = QEMU_OPT_NUMBER,
134 },
135 {
136 .name = "new_state",
137 .type = QEMU_OPT_NUMBER,
138 },
139 { /* end of list */ }
140 },
141};
142
143static QemuOptsList *config_groups[] = {
144 &inject_error_opts,
145 &set_state_opts,
146 NULL
147};
148
a31939e6 149static int get_event_by_name(const char *name, BlkdebugEvent *event)
8b9b0cc2
KW
150{
151 int i;
152
7fb1cf16 153 for (i = 0; i < BLKDBG__MAX; i++) {
a31939e6 154 if (!strcmp(BlkdebugEvent_lookup[i], name)) {
8b9b0cc2
KW
155 *event = i;
156 return 0;
157 }
158 }
159
160 return -1;
161}
162
163struct add_rule_data {
164 BDRVBlkdebugState *s;
165 int action;
166};
167
28d0de7a 168static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
8b9b0cc2
KW
169{
170 struct add_rule_data *d = opaque;
171 BDRVBlkdebugState *s = d->s;
172 const char* event_name;
a31939e6 173 BlkdebugEvent event;
8b9b0cc2
KW
174 struct BlkdebugRule *rule;
175
176 /* Find the right event for the rule */
177 event_name = qemu_opt_get(opts, "event");
d4362d64 178 if (!event_name) {
8809cfc3 179 error_setg(errp, "Missing event name for rule");
d4362d64
SH
180 return -1;
181 } else if (get_event_by_name(event_name, &event) < 0) {
8809cfc3 182 error_setg(errp, "Invalid event name \"%s\"", event_name);
8b9b0cc2
KW
183 return -1;
184 }
185
186 /* Set attributes common for all actions */
7267c094 187 rule = g_malloc0(sizeof(*rule));
8b9b0cc2
KW
188 *rule = (struct BlkdebugRule) {
189 .event = event,
190 .action = d->action,
191 .state = qemu_opt_get_number(opts, "state", 0),
192 };
193
194 /* Parse action-specific options */
195 switch (d->action) {
196 case ACTION_INJECT_ERROR:
197 rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
198 rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
199 rule->options.inject.immediately =
200 qemu_opt_get_bool(opts, "immediately", 0);
e4780db4 201 rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
8b9b0cc2
KW
202 break;
203
204 case ACTION_SET_STATE:
205 rule->options.set_state.new_state =
206 qemu_opt_get_number(opts, "new_state", 0);
207 break;
3c90c65d
KW
208
209 case ACTION_SUSPEND:
210 rule->options.suspend.tag =
211 g_strdup(qemu_opt_get(opts, "tag"));
212 break;
8b9b0cc2
KW
213 };
214
215 /* Add the rule */
216 QLIST_INSERT_HEAD(&s->rules[event], rule, next);
217
218 return 0;
219}
220
9e35542b
KW
221static void remove_rule(BlkdebugRule *rule)
222{
223 switch (rule->action) {
224 case ACTION_INJECT_ERROR:
225 case ACTION_SET_STATE:
226 break;
3c90c65d
KW
227 case ACTION_SUSPEND:
228 g_free(rule->options.suspend.tag);
229 break;
9e35542b
KW
230 }
231
232 QLIST_REMOVE(rule, next);
233 g_free(rule);
234}
235
89f2b21e
HR
236static int read_config(BDRVBlkdebugState *s, const char *filename,
237 QDict *options, Error **errp)
8b9b0cc2 238{
85a040e5 239 FILE *f = NULL;
8b9b0cc2
KW
240 int ret;
241 struct add_rule_data d;
89f2b21e 242 Error *local_err = NULL;
8b9b0cc2 243
85a040e5
HR
244 if (filename) {
245 f = fopen(filename, "r");
246 if (f == NULL) {
247 error_setg_errno(errp, errno, "Could not read blkdebug config file");
248 return -errno;
249 }
8b9b0cc2 250
85a040e5
HR
251 ret = qemu_config_parse(f, config_groups, filename);
252 if (ret < 0) {
253 error_setg(errp, "Could not parse blkdebug config file");
254 ret = -EINVAL;
255 goto fail;
256 }
8b9b0cc2
KW
257 }
258
89f2b21e 259 qemu_config_parse_qdict(options, config_groups, &local_err);
84d18f06 260 if (local_err) {
89f2b21e
HR
261 error_propagate(errp, local_err);
262 ret = -EINVAL;
263 goto fail;
264 }
265
8b9b0cc2
KW
266 d.s = s;
267 d.action = ACTION_INJECT_ERROR;
8809cfc3 268 qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
d4362d64
SH
269 if (local_err) {
270 error_propagate(errp, local_err);
271 ret = -EINVAL;
272 goto fail;
273 }
8b9b0cc2
KW
274
275 d.action = ACTION_SET_STATE;
8809cfc3 276 qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
d4362d64
SH
277 if (local_err) {
278 error_propagate(errp, local_err);
279 ret = -EINVAL;
280 goto fail;
281 }
8b9b0cc2
KW
282
283 ret = 0;
284fail:
698f0d52
KW
285 qemu_opts_reset(&inject_error_opts);
286 qemu_opts_reset(&set_state_opts);
85a040e5
HR
287 if (f) {
288 fclose(f);
289 }
8b9b0cc2
KW
290 return ret;
291}
292
293/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
f4681212
KW
294static void blkdebug_parse_filename(const char *filename, QDict *options,
295 Error **errp)
6a143727 296{
f4681212 297 const char *c;
6a143727 298
8b9b0cc2 299 /* Parse the blkdebug: prefix */
f4681212 300 if (!strstart(filename, "blkdebug:", &filename)) {
d4881b9b
HR
301 /* There was no prefix; therefore, all options have to be already
302 present in the QDict (except for the filename) */
303 qdict_put(options, "x-image", qstring_from_str(filename));
f4681212 304 return;
6a143727 305 }
6a143727 306
f4681212 307 /* Parse config file path */
8b9b0cc2
KW
308 c = strchr(filename, ':');
309 if (c == NULL) {
f4681212
KW
310 error_setg(errp, "blkdebug requires both config file and image path");
311 return;
8b9b0cc2
KW
312 }
313
f4681212
KW
314 if (c != filename) {
315 QString *config_path;
316 config_path = qstring_from_substr(filename, 0, c - filename - 1);
317 qdict_put(options, "config", config_path);
8b9b0cc2 318 }
f4681212
KW
319
320 /* TODO Allow multi-level nesting and set file.filename here */
8b9b0cc2 321 filename = c + 1;
f4681212
KW
322 qdict_put(options, "x-image", qstring_from_str(filename));
323}
324
325static QemuOptsList runtime_opts = {
326 .name = "blkdebug",
327 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
328 .desc = {
329 {
330 .name = "config",
331 .type = QEMU_OPT_STRING,
332 .help = "Path to the configuration file",
333 },
334 {
335 .name = "x-image",
336 .type = QEMU_OPT_STRING,
337 .help = "[internal use only, will be removed]",
338 },
b35ee7fb
KW
339 {
340 .name = "align",
341 .type = QEMU_OPT_SIZE,
342 .help = "Required alignment in bytes",
343 },
f4681212
KW
344 { /* end of list */ }
345 },
346};
347
015a1036
HR
348static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
349 Error **errp)
f4681212
KW
350{
351 BDRVBlkdebugState *s = bs->opaque;
352 QemuOpts *opts;
353 Error *local_err = NULL;
4373593d 354 const char *config;
b35ee7fb 355 uint64_t align;
f4681212
KW
356 int ret;
357
87ea75d5 358 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
f4681212 359 qemu_opts_absorb_qdict(opts, options, &local_err);
84d18f06 360 if (local_err) {
10ffa72f 361 error_propagate(errp, local_err);
f4681212 362 ret = -EINVAL;
eaf944a4 363 goto out;
f4681212
KW
364 }
365
89f2b21e 366 /* Read rules from config file or command line options */
f4681212 367 config = qemu_opt_get(opts, "config");
89f2b21e 368 ret = read_config(s, config, options, errp);
85a040e5 369 if (ret) {
eaf944a4 370 goto out;
f4681212 371 }
8b9b0cc2 372
8db520ce 373 /* Set initial state */
571cd43e 374 s->state = 1;
8db520ce 375
6b826af7 376 /* Open the image file */
9a4f4c31
KW
377 bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
378 bs, &child_file, false, &local_err);
379 if (local_err) {
380 ret = -EINVAL;
10ffa72f 381 error_propagate(errp, local_err);
eaf944a4 382 goto out;
8b9b0cc2
KW
383 }
384
b35ee7fb 385 /* Set request alignment */
835db3ee
EB
386 align = qemu_opt_get_size(opts, "align", 0);
387 if (align < INT_MAX && is_power_of_2(align)) {
388 s->align = align;
389 } else if (align) {
b35ee7fb
KW
390 error_setg(errp, "Invalid alignment");
391 ret = -EINVAL;
eaf944a4 392 goto fail_unref;
b35ee7fb
KW
393 }
394
f4681212 395 ret = 0;
eaf944a4
KW
396 goto out;
397
398fail_unref:
9a4f4c31 399 bdrv_unref_child(bs, bs->file);
eaf944a4 400out:
f4681212
KW
401 qemu_opts_del(opts);
402 return ret;
6a143727
KW
403}
404
b9f66d96
KW
405static void error_callback_bh(void *opaque)
406{
407 struct BlkdebugAIOCB *acb = opaque;
408 qemu_bh_delete(acb->bh);
409 acb->common.cb(acb->common.opaque, acb->ret);
8007429a 410 qemu_aio_unref(acb);
b9f66d96
KW
411}
412
7c84b1b8 413static BlockAIOCB *inject_error(BlockDriverState *bs,
097310b5 414 BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
b9f66d96
KW
415{
416 BDRVBlkdebugState *s = bs->opaque;
571cd43e 417 int error = rule->options.inject.error;
b9f66d96
KW
418 struct BlkdebugAIOCB *acb;
419 QEMUBH *bh;
a069e2f1 420 bool immediately = rule->options.inject.immediately;
b9f66d96 421
571cd43e 422 if (rule->options.inject.once) {
a069e2f1
JS
423 QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
424 remove_rule(rule);
b9f66d96
KW
425 }
426
a069e2f1 427 if (immediately) {
b9f66d96
KW
428 return NULL;
429 }
430
d7331bed 431 acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
b9f66d96
KW
432 acb->ret = -error;
433
7e1efdf0 434 bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
b9f66d96
KW
435 acb->bh = bh;
436 qemu_bh_schedule(bh);
437
b666d239 438 return &acb->common;
b9f66d96
KW
439}
440
7c84b1b8 441static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
6a143727 442 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
097310b5 443 BlockCompletionFunc *cb, void *opaque)
6a143727
KW
444{
445 BDRVBlkdebugState *s = bs->opaque;
e4780db4
PB
446 BlkdebugRule *rule = NULL;
447
448 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
449 if (rule->options.inject.sector == -1 ||
450 (rule->options.inject.sector >= sector_num &&
451 rule->options.inject.sector < sector_num + nb_sectors)) {
452 break;
453 }
454 }
b9f66d96 455
571cd43e
PB
456 if (rule && rule->options.inject.error) {
457 return inject_error(bs, cb, opaque, rule);
b9f66d96
KW
458 }
459
9a4f4c31
KW
460 return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
461 cb, opaque);
6a143727
KW
462}
463
7c84b1b8 464static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
6a143727 465 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
097310b5 466 BlockCompletionFunc *cb, void *opaque)
6a143727
KW
467{
468 BDRVBlkdebugState *s = bs->opaque;
e4780db4
PB
469 BlkdebugRule *rule = NULL;
470
471 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
472 if (rule->options.inject.sector == -1 ||
473 (rule->options.inject.sector >= sector_num &&
474 rule->options.inject.sector < sector_num + nb_sectors)) {
475 break;
476 }
477 }
b9f66d96 478
571cd43e
PB
479 if (rule && rule->options.inject.error) {
480 return inject_error(bs, cb, opaque, rule);
b9f66d96
KW
481 }
482
9a4f4c31
KW
483 return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
484 cb, opaque);
6a143727
KW
485}
486
7c84b1b8 487static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
097310b5 488 BlockCompletionFunc *cb, void *opaque)
9e52c53b
PB
489{
490 BDRVBlkdebugState *s = bs->opaque;
491 BlkdebugRule *rule = NULL;
492
493 QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
494 if (rule->options.inject.sector == -1) {
495 break;
496 }
497 }
498
499 if (rule && rule->options.inject.error) {
500 return inject_error(bs, cb, opaque, rule);
501 }
502
9a4f4c31 503 return bdrv_aio_flush(bs->file->bs, cb, opaque);
9e52c53b
PB
504}
505
3c90c65d 506
6a143727
KW
507static void blkdebug_close(BlockDriverState *bs)
508{
509 BDRVBlkdebugState *s = bs->opaque;
8b9b0cc2
KW
510 BlkdebugRule *rule, *next;
511 int i;
512
7fb1cf16 513 for (i = 0; i < BLKDBG__MAX; i++) {
8b9b0cc2 514 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
9e35542b 515 remove_rule(rule);
8b9b0cc2
KW
516 }
517 }
6a143727
KW
518}
519
3c90c65d
KW
520static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
521{
522 BDRVBlkdebugState *s = bs->opaque;
523 BlkdebugSuspendedReq r;
524
525 r = (BlkdebugSuspendedReq) {
526 .co = qemu_coroutine_self(),
527 .tag = g_strdup(rule->options.suspend.tag),
528 };
529
530 remove_rule(rule);
531 QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next);
532
20873526
MT
533 if (!qtest_enabled()) {
534 printf("blkdebug: Suspended request '%s'\n", r.tag);
535 }
3c90c65d 536 qemu_coroutine_yield();
20873526
MT
537 if (!qtest_enabled()) {
538 printf("blkdebug: Resuming request '%s'\n", r.tag);
539 }
3c90c65d
KW
540
541 QLIST_REMOVE(&r, next);
542 g_free(r.tag);
543}
544
571cd43e 545static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
8f96b5be 546 bool injected)
8b9b0cc2
KW
547{
548 BDRVBlkdebugState *s = bs->opaque;
8b9b0cc2
KW
549
550 /* Only process rules for the current state */
8f96b5be 551 if (rule->state && rule->state != s->state) {
571cd43e 552 return injected;
8b9b0cc2
KW
553 }
554
555 /* Take the action */
556 switch (rule->action) {
557 case ACTION_INJECT_ERROR:
571cd43e
PB
558 if (!injected) {
559 QSIMPLEQ_INIT(&s->active_rules);
560 injected = true;
561 }
562 QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
8b9b0cc2
KW
563 break;
564
565 case ACTION_SET_STATE:
8f96b5be 566 s->new_state = rule->options.set_state.new_state;
8b9b0cc2 567 break;
3c90c65d
KW
568
569 case ACTION_SUSPEND:
570 suspend_request(bs, rule);
571 break;
8b9b0cc2 572 }
571cd43e 573 return injected;
8b9b0cc2
KW
574}
575
a31939e6 576static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
8b9b0cc2
KW
577{
578 BDRVBlkdebugState *s = bs->opaque;
3c90c65d 579 struct BlkdebugRule *rule, *next;
571cd43e 580 bool injected;
8b9b0cc2 581
7fb1cf16 582 assert((int)event >= 0 && event < BLKDBG__MAX);
8b9b0cc2 583
571cd43e 584 injected = false;
8f96b5be 585 s->new_state = s->state;
3c90c65d 586 QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
8f96b5be 587 injected = process_rule(bs, rule, injected);
8b9b0cc2 588 }
8f96b5be 589 s->state = s->new_state;
8b9b0cc2
KW
590}
591
3c90c65d
KW
592static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
593 const char *tag)
594{
595 BDRVBlkdebugState *s = bs->opaque;
596 struct BlkdebugRule *rule;
a31939e6 597 BlkdebugEvent blkdebug_event;
3c90c65d
KW
598
599 if (get_event_by_name(event, &blkdebug_event) < 0) {
600 return -ENOENT;
601 }
602
603
604 rule = g_malloc(sizeof(*rule));
605 *rule = (struct BlkdebugRule) {
606 .event = blkdebug_event,
607 .action = ACTION_SUSPEND,
608 .state = 0,
609 .options.suspend.tag = g_strdup(tag),
610 };
611
612 QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
613
614 return 0;
615}
616
617static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
618{
619 BDRVBlkdebugState *s = bs->opaque;
c547e564 620 BlkdebugSuspendedReq *r, *next;
3c90c65d 621
c547e564 622 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) {
3c90c65d
KW
623 if (!strcmp(r->tag, tag)) {
624 qemu_coroutine_enter(r->co, NULL);
625 return 0;
626 }
627 }
628 return -ENOENT;
629}
630
4cc70e93
FZ
631static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
632 const char *tag)
633{
634 BDRVBlkdebugState *s = bs->opaque;
c547e564 635 BlkdebugSuspendedReq *r, *r_next;
4cc70e93
FZ
636 BlkdebugRule *rule, *next;
637 int i, ret = -ENOENT;
638
7fb1cf16 639 for (i = 0; i < BLKDBG__MAX; i++) {
4cc70e93
FZ
640 QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
641 if (rule->action == ACTION_SUSPEND &&
642 !strcmp(rule->options.suspend.tag, tag)) {
643 remove_rule(rule);
644 ret = 0;
645 }
646 }
647 }
c547e564 648 QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) {
4cc70e93
FZ
649 if (!strcmp(r->tag, tag)) {
650 qemu_coroutine_enter(r->co, NULL);
651 ret = 0;
652 }
653 }
654 return ret;
655}
3c90c65d
KW
656
657static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
658{
659 BDRVBlkdebugState *s = bs->opaque;
660 BlkdebugSuspendedReq *r;
661
662 QLIST_FOREACH(r, &s->suspended_reqs, next) {
663 if (!strcmp(r->tag, tag)) {
664 return true;
665 }
666 }
667 return false;
668}
669
e1302255
PB
670static int64_t blkdebug_getlength(BlockDriverState *bs)
671{
9a4f4c31 672 return bdrv_getlength(bs->file->bs);
e1302255
PB
673}
674
8eedfbd4
KW
675static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
676{
9a4f4c31 677 return bdrv_truncate(bs->file->bs, offset);
8eedfbd4
KW
678}
679
4cdd01d3 680static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
2c31b04c 681{
2c31b04c 682 QDict *opts;
8779441b
HR
683 const QDictEntry *e;
684 bool force_json = false;
685
4cdd01d3 686 for (e = qdict_first(options); e; e = qdict_next(options, e)) {
8779441b 687 if (strcmp(qdict_entry_key(e), "config") &&
4cdd01d3 688 strcmp(qdict_entry_key(e), "x-image"))
8779441b
HR
689 {
690 force_json = true;
691 break;
692 }
693 }
2c31b04c 694
9a4f4c31 695 if (force_json && !bs->file->bs->full_open_options) {
2c31b04c
HR
696 /* The config file cannot be recreated, so creating a plain filename
697 * is impossible */
698 return;
699 }
700
9a4f4c31 701 if (!force_json && bs->file->bs->exact_filename[0]) {
8779441b
HR
702 snprintf(bs->exact_filename, sizeof(bs->exact_filename),
703 "blkdebug:%s:%s",
4cdd01d3 704 qdict_get_try_str(options, "config") ?: "",
9a4f4c31 705 bs->file->bs->exact_filename);
8779441b
HR
706 }
707
2c31b04c
HR
708 opts = qdict_new();
709 qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
710
9a4f4c31
KW
711 QINCREF(bs->file->bs->full_open_options);
712 qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
2c31b04c 713
4cdd01d3
KW
714 for (e = qdict_first(options); e; e = qdict_next(options, e)) {
715 if (strcmp(qdict_entry_key(e), "x-image")) {
8779441b
HR
716 qobject_incref(qdict_entry_value(e));
717 qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
2c31b04c
HR
718 }
719 }
720
2c31b04c
HR
721 bs->full_open_options = opts;
722}
723
835db3ee
EB
724static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
725{
726 BDRVBlkdebugState *s = bs->opaque;
727
728 if (s->align) {
729 bs->request_alignment = s->align;
730 }
731}
732
c5e8bfb7
KW
733static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
734 BlockReopenQueue *queue, Error **errp)
735{
736 return 0;
737}
738
6a143727 739static BlockDriver bdrv_blkdebug = {
f4681212
KW
740 .format_name = "blkdebug",
741 .protocol_name = "blkdebug",
742 .instance_size = sizeof(BDRVBlkdebugState),
6a143727 743
f4681212
KW
744 .bdrv_parse_filename = blkdebug_parse_filename,
745 .bdrv_file_open = blkdebug_open,
746 .bdrv_close = blkdebug_close,
c5e8bfb7 747 .bdrv_reopen_prepare = blkdebug_reopen_prepare,
f4681212 748 .bdrv_getlength = blkdebug_getlength,
8eedfbd4 749 .bdrv_truncate = blkdebug_truncate,
2c31b04c 750 .bdrv_refresh_filename = blkdebug_refresh_filename,
835db3ee 751 .bdrv_refresh_limits = blkdebug_refresh_limits,
6a143727 752
f4681212
KW
753 .bdrv_aio_readv = blkdebug_aio_readv,
754 .bdrv_aio_writev = blkdebug_aio_writev,
9e52c53b 755 .bdrv_aio_flush = blkdebug_aio_flush,
8b9b0cc2 756
3c90c65d
KW
757 .bdrv_debug_event = blkdebug_debug_event,
758 .bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
4cc70e93
FZ
759 .bdrv_debug_remove_breakpoint
760 = blkdebug_debug_remove_breakpoint,
3c90c65d
KW
761 .bdrv_debug_resume = blkdebug_debug_resume,
762 .bdrv_debug_is_suspended = blkdebug_debug_is_suspended,
6a143727
KW
763};
764
765static void bdrv_blkdebug_init(void)
766{
767 bdrv_register(&bdrv_blkdebug);
768}
769
770block_init(bdrv_blkdebug_init);