zinject: Introduce ready delay fault injection

This adds a pause to the ZIO pipeline in the ready stage for
matching I/O (data, dnode, or raw bookmark).

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Rob Norris <robn@despairlabs.com>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Akash B <akash-b@hpe.com>
Signed-off-by: Robert Evans <evansr@google.com>
Closes #17787
This commit is contained in:
Robert Evans
2025-10-01 15:17:13 -04:00
committed by Tony Hutter
parent 073b34b3ee
commit ead0fb736d
6 changed files with 134 additions and 11 deletions
+10
View File
@@ -5305,6 +5305,16 @@ zio_ready(zio_t *zio)
return (NULL);
}
if (zio_injection_enabled) {
hrtime_t target = zio_handle_ready_delay(zio);
if (target != 0 && zio->io_target_timestamp == 0) {
zio->io_stage >>= 1;
zio->io_target_timestamp = target;
zio_delay_interrupt(zio);
return (NULL);
}
}
if (zio->io_ready) {
ASSERT(IO_IS_ALLOCATING(zio));
ASSERT(BP_GET_BIRTH(bp) == zio->io_txg ||
+38
View File
@@ -827,6 +827,44 @@ zio_handle_export_delay(spa_t *spa, hrtime_t elapsed)
zio_handle_pool_delay(spa, elapsed, ZINJECT_DELAY_EXPORT);
}
/*
* For testing, inject a delay before ready state.
*/
hrtime_t
zio_handle_ready_delay(zio_t *zio)
{
inject_handler_t *handler;
hrtime_t now = gethrtime();
hrtime_t target = 0;
/*
* Ignore I/O not associated with any logical data.
*/
if (zio->io_logical == NULL)
return (0);
rw_enter(&inject_lock, RW_READER);
for (handler = list_head(&inject_handlers); handler != NULL;
handler = list_next(&inject_handlers, handler)) {
if (zio->io_spa != handler->zi_spa ||
handler->zi_record.zi_cmd != ZINJECT_DELAY_READY)
continue;
/* If this handler matches, inject the delay */
if (zio_match_iotype(zio, handler->zi_record.zi_iotype) &&
zio_match_handler(&zio->io_logical->io_bookmark,
zio->io_bp ? BP_GET_TYPE(zio->io_bp) : DMU_OT_NONE,
zio_match_dva(zio), &handler->zi_record, zio->io_error)) {
target = now + (hrtime_t)handler->zi_record.zi_timer;
break;
}
}
rw_exit(&inject_lock);
return (target);
}
static int
zio_calculate_range(const char *pool, zinject_record_t *record)
{