blkdebug: Add 'delay-ns' option
Sometimes reproducing a problem for debugging involves slow I/O, so let's add something to blkdebug to make I/O slow when we need it. This can be used either together with an error so that the request fails after the delay, or with errno=0, which allows the request to succeed after the delay. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Message-ID: <20260421161132.99878-2-kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Kevin Wolf committed
Apr 21, 2026 at 18:11 UTC
d5e4090177ad382e01084a1594a1a60a69f4c1cd
2 files changed
+18
-1
block/blkdebug.c
+14
-1
@@ -95,6 +95,7 @@ typedef struct BlkdebugRule {
95
int immediately;
96
int once;
97
int64_t offset;
98
+ int64_t delay_ns;
99
} inject;
100
struct {
101
int new_state;
@@ -144,6 +145,10 @@ static QemuOptsList inject_error_opts = {
145
.name = "immediately",
146
.type = QEMU_OPT_BOOL,
147
},
148
+ {
149
+ .name = "delay-ns",
150
+ .type = QEMU_OPT_NUMBER,
151
+ },
152
{ /* end of list */ }
153
},
154
};
@@ -216,6 +221,8 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
221
rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
222
rule->options.inject.immediately =
223
qemu_opt_get_bool(opts, "immediately", 0);
224
+ rule->options.inject.delay_ns =
225
+ qemu_opt_get_number(opts, "delay-ns", 0);
226
sector = qemu_opt_get_number(opts, "sector", -1);
227
rule->options.inject.offset =
228
sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
@@ -594,6 +601,7 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
601
BlkdebugRule *rule;
602
int error;
603
bool immediately;
604
+ int64_t delay_ns;
605
606
qemu_mutex_lock(&s->lock);
607
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
@@ -608,13 +616,14 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
616
}
617
}
618
611
- if (!rule || !rule->options.inject.error) {
619
+ if (!rule) {
620
qemu_mutex_unlock(&s->lock);
621
return 0;
622
}
623
624
immediately = rule->options.inject.immediately;
625
error = rule->options.inject.error;
626
+ delay_ns = rule->options.inject.delay_ns;
627
628
if (rule->options.inject.once) {
629
QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
@@ -622,6 +631,10 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
631
}
632
633
qemu_mutex_unlock(&s->lock);
634
+
635
+ if (delay_ns) {
636
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, delay_ns);
637
+ }
638
if (!immediately) {
639
aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
640
qemu_coroutine_yield();
qapi/block-core.json
+4
@@ -3919,6 +3919,9 @@
3919
#
3920
# @errno: error identifier (errno) to be returned; defaults to EIO
3921
#
3922
+# @delay-ns: request delay before completion in nanoseconds
3923
+# (default: 0, since: 11.1)
3924
+#
3925
# @sector: specifies the sector index which has to be affected in
3926
# order to actually trigger the event; defaults to "any sector"
3927
#
@@ -3934,6 +3937,7 @@
3937
'*state': 'int',
3938
'*iotype': 'BlkdebugIOType',
3939
'*errno': 'int',
3940
+ '*delay-ns': 'int',
3941
'*sector': 'int',
3942
'*once': 'bool',
3943
'*immediately': 'bool' } }