Index: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c =================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c @@ -174,10 +174,6 @@ boolean_t spa_create_process = B_TRUE; /* no process ==> no sysdc */ extern int zfs_sync_pass_deferred_free; -#ifndef illumos -extern void spa_deadman(void *arg); -#endif - /* * This (illegal) pool name is used when temporarily importing a spa_t in order * to get the vdev stats associated with the imported devices. @@ -6883,8 +6879,8 @@ spa->spa_sync_starttime + spa->spa_deadman_synctime)); #else /* !illumos */ #ifdef _KERNEL - callout_reset(&spa->spa_deadman_cycid, - hz * spa->spa_deadman_synctime / NANOSEC, spa_deadman, spa); + callout_schedule(&spa->spa_deadman_cycid, + hz * spa->spa_deadman_synctime / NANOSEC); #endif #endif /* illumos */ Index: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c =================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c @@ -597,8 +597,8 @@ * If the zfs_deadman_enabled flag is set then it inspects all vdev queues * looking for potentially hung I/Os. */ -void -spa_deadman(void *arg) +static void +spa_deadman(void *arg, int pending) { spa_t *spa = arg; @@ -627,6 +627,16 @@ #endif } +#if defined(__FreeBSD__) && defined(_KERNEL) +static void +spa_deadman_timeout(void *arg) +{ + spa_t *spa = arg; + + taskqueue_enqueue(taskqueue_thread, &spa->spa_deadman_task); +} +#endif + /* * Create an uninitialized spa_t with the given name. Requires * spa_namespace_lock. The caller must ensure that the spa_t doesn't already @@ -698,7 +708,23 @@ mutex_exit(&cpu_lock); #else /* !illumos */ #ifdef _KERNEL + /* + * callout(9) does not provide a way to initialize a callout with + * a function and an argument, so we use callout_reset() to schedule + * the callout in the very distant future. Even if that event ever + * fires, it should be okayas we won't have any active zio-s. + * But normally spa_sync() will reschedule the callout with a proper + * timeout. + * callout(9) does not allow the callback function to sleep but + * vdev_deadman() needs to acquire vq_lock and illumos mutexes are + * emulated using sx(9). For this reason spa_deadman_timeout() + * will schedule spa_deadman() as task on a taskqueue that allows + * sleeping. + */ + TASK_INIT(&spa->spa_deadman_task, 0, spa_deadman, spa); callout_init(&spa->spa_deadman_cycid, 1); + callout_reset_sbt(&spa->spa_deadman_cycid, SBT_MAX, 0, + spa_deadman_timeout, spa, 0); #endif #endif refcount_create(&spa->spa_refcount); @@ -811,6 +837,7 @@ #else /* !illumos */ #ifdef _KERNEL callout_drain(&spa->spa_deadman_cycid); + taskqueue_drain(taskqueue_thread, &spa->spa_deadman_task); #endif #endif Index: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h =================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h @@ -267,6 +267,7 @@ #else /* !illumos */ #ifdef _KERNEL struct callout spa_deadman_cycid; /* callout id */ + struct task spa_deadman_task; #endif #endif /* illumos */ uint64_t spa_deadman_calls; /* number of deadman calls */