3246 ZFS I/O deadman thread

Reviewed by: Matt Ahrens <matthew.ahrens@delphix.com>
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Reviewed by: Christopher Siden <chris.siden@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>

NOTES: This patch has been reworked from the original in the
following ways to accomidate Linux ZFS implementation

*) Usage of the cyclic interface was replaced by the delayed taskq
   interface.  This avoids the need to implement new compatibility
   code and allows us to rely on the existing taskq implementation.

*) An extern for zfs_txg_synctime_ms was added to sys/dsl_pool.h
   because declaring externs in source files as was done in the
   original patch is just plain wrong.

*) Instead of panicing the system when the deadman triggers a
   zevent describing the blocked vdev and the first pending I/O
   is posted.  If the panic behavior is desired Linux provides
   other generic methods to panic the system when threads are
   observed to hang.

*) For reference, to delay zios by 30 seconds for testing you can
   use zinject as follows: 'zinject -d <vdev> -D30 <pool>'

References:
  illumos/illumos-gate@283b84606b
  https://www.illumos.org/issues/3246

Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1396
This commit is contained in:
George.Wilson
2013-04-29 15:49:23 -07:00
committed by Brian Behlendorf
parent 57f5a2008e
commit cc92e9d0c3
20 changed files with 275 additions and 50 deletions
+54
View File
@@ -236,6 +236,24 @@ static avl_tree_t spa_l2cache_avl;
kmem_cache_t *spa_buffer_pool;
int spa_mode_global;
/*
* Expiration time in units of zfs_txg_synctime_ms. This value has two
* meanings. First it is used to determine when the spa_deadman logic
* should fire. By default the spa_deadman will fire if spa_sync has
* not completed in 1000 * zfs_txg_synctime_ms (i.e. 1000 seconds).
* Secondly, the value determines if an I/O is considered "hung".
* Any I/O that has not completed in zfs_deadman_synctime is considered
* "hung" resulting in a zevent being posted.
* 1000 zfs_txg_synctime_ms (i.e. 1000 seconds).
*/
unsigned long zfs_deadman_synctime = 1000ULL;
/*
* By default the deadman is enabled.
*/
int zfs_deadman_enabled = 1;
/*
* ==========================================================================
* SPA config locking
@@ -412,6 +430,27 @@ spa_lookup(const char *name)
return (spa);
}
/*
* Fires when spa_sync has not completed within zfs_deadman_synctime_ms.
* 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)
{
spa_t *spa = arg;
zfs_dbgmsg("slow spa_sync: started %llu seconds ago, calls %llu",
(gethrtime() - spa->spa_sync_starttime) / NANOSEC,
++spa->spa_deadman_calls);
if (zfs_deadman_enabled)
vdev_deadman(spa->spa_root_vdev);
spa->spa_deadman_tqid = taskq_dispatch_delay(system_taskq,
spa_deadman, spa, TQ_SLEEP, ddi_get_lbolt() +
NSEC_TO_TICK(spa->spa_deadman_synctime));
}
/*
* Create an uninitialized spa_t with the given name. Requires
* spa_namespace_lock. The caller must ensure that the spa_t doesn't already
@@ -454,6 +493,9 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
spa->spa_proc = &p0;
spa->spa_proc_state = SPA_PROC_NONE;
spa->spa_deadman_synctime = zfs_deadman_synctime *
zfs_txg_synctime_ms * MICROSEC;
refcount_create(&spa->spa_refcount);
spa_config_lock_init(spa);
@@ -1492,6 +1534,12 @@ spa_prev_software_version(spa_t *spa)
return (spa->spa_prev_software_version);
}
uint64_t
spa_deadman_synctime(spa_t *spa)
{
return (spa->spa_deadman_synctime);
}
uint64_t
dva_get_dsize_sync(spa_t *spa, const dva_t *dva)
{
@@ -1812,4 +1860,10 @@ EXPORT_SYMBOL(spa_writeable);
EXPORT_SYMBOL(spa_mode);
EXPORT_SYMBOL(spa_namespace_lock);
module_param(zfs_deadman_synctime, ulong, 0644);
MODULE_PARM_DESC(zfs_deadman_synctime,"Expire in units of zfs_txg_synctime_ms");
module_param(zfs_deadman_enabled, int, 0644);
MODULE_PARM_DESC(zfs_deadman_enabled, "Enable deadman timer");
#endif