diff --git a/sys/kern/kern_fail.c b/sys/kern/kern_fail.c index 976a39ba8e28..063f7ac2f67c 100644 --- a/sys/kern/kern_fail.c +++ b/sys/kern/kern_fail.c @@ -403,6 +403,8 @@ fail_point_drain(struct fail_point *fp, int expected_ref) wakeup(FP_PAUSE_CHANNEL(fp)); tsleep(&fp, PWAIT, "fail_point_drain", hz / 100); } + if (fp->fp_callout) + callout_drain(fp->fp_callout); fail_point_swap_settings(fp, entries); } @@ -442,8 +444,8 @@ fail_point_sleep(struct fail_point *fp, int msecs, if (fp->fp_pre_sleep_fn) fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg); - timeout(fp->fp_post_sleep_fn, fp->fp_post_sleep_arg, - timo); + callout_reset(fp->fp_callout, timo, + fp->fp_post_sleep_fn, fp->fp_post_sleep_arg); *pret = FAIL_POINT_RC_QUEUED; } } @@ -493,6 +495,20 @@ fail_point_init(struct fail_point *fp, const char *fmt, ...) fp->fp_post_sleep_arg = NULL; } +void +fail_point_alloc_callout(struct fail_point *fp) +{ + + /** + * This assumes that calls to fail_point_use_timeout_path() + * will not race. + */ + if (fp->fp_callout != NULL) + return; + fp->fp_callout = fp_malloc(sizeof(*fp->fp_callout), M_WAITOK); + callout_init(fp->fp_callout, CALLOUT_MPSAFE); +} + /** * Free the resources held by a fail_point, and wake any paused threads. * Thou shalt not allow threads to hit this fail point after you enter this @@ -510,6 +526,10 @@ fail_point_destroy(struct fail_point *fp) fp->fp_name = NULL; } fp->fp_flags = 0; + if (fp->fp_callout) { + fp_free(fp->fp_callout); + fp->fp_callout = NULL; + } sx_xlock(&sx_fp_set); fail_point_garbage_collect(); diff --git a/sys/sys/fail.h b/sys/sys/fail.h index 1905aee82968..ffb3f3d536d2 100644 --- a/sys/sys/fail.h +++ b/sys/sys/fail.h @@ -84,6 +84,8 @@ struct fail_point { void (*fp_post_sleep_fn)(void *); /**< Arg for fp_post_sleep_fn */ void *fp_post_sleep_arg; + + struct callout *fp_callout; }; #define FAIL_POINT_DYNAMIC_NAME 0x01 /**< Must free name on destroy */ @@ -149,9 +151,12 @@ fail_point_sleep_set_post_arg(struct fail_point *fp, void *sleep_arg) { fp->fp_post_sleep_arg = sleep_arg; } + +void fail_point_alloc_callout(struct fail_point *); + /** * If the FAIL_POINT_USE_TIMEOUT flag is set on a failpoint, then - * FAIL_POINT_SLEEP will result in a call to timeout instead of + * FAIL_POINT_SLEEP will result in a call to callout_reset instead of * msleep. Note that if you sleep while this flag is set, you must * set fp_post_sleep_fn or an error will occur upon waking. */ @@ -163,9 +168,10 @@ fail_point_use_timeout_path(struct fail_point *fp, bool use_timeout, (post_sleep_fn == NULL && fp->fp_post_sleep_fn != NULL), ("Setting fp to use timeout, but not setting post_sleep_fn\n")); - if (use_timeout) + if (use_timeout) { + fail_point_alloc_callout(fp); fp->fp_flags |= FAIL_POINT_USE_TIMEOUT_PATH; - else + } else fp->fp_flags &= ~FAIL_POINT_USE_TIMEOUT_PATH; if (post_sleep_fn != NULL)