mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-25 03:37:45 +03:00
Illumos 5056 - ZFS deadlock on db_mtx and dn_holds
5056 ZFS deadlock on db_mtx and dn_holds Author: Justin Gibbs <justing@spectralogic.com> Reviewed by: Will Andrews <willa@spectralogic.com> Reviewed by: Matt Ahrens <mahrens@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Approved by: Dan McDonald <danmcd@omniti.com> References: https://www.illumos.org/issues/5056 https://github.com/illumos/illumos-gate/commit/bc9014e Porting Notes: sa_handle_get_from_db(): - the original patch includes an otherwise unmentioned fix for a possible usage of an uninitialised variable dmu_objset_open_impl(): - Under Illumos list_link_init() is the same as filling a list_node_t with NULLs, so they don't notice if they miss doing list_link_init() on a zero'd containing structure (e.g. allocated with kmem_zalloc as here). Under Linux, not so much: an uninitialised list_node_t goes "Boom!" some time later when it's used or destroyed. dmu_objset_evict_dbufs(): - reduce stack usage using kmem_alloc() Ported-by: Chris Dunlop <chris@onthe.net.au> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
committed by
Brian Behlendorf
parent
d683ddbb72
commit
0c66c32d1d
@@ -22,6 +22,7 @@
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@@ -524,6 +525,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
|
||||
mutex_init(&spa->spa_async_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_errlist_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_errlog_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_evicting_os_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_history_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_proc_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_props_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
@@ -533,6 +535,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
|
||||
mutex_init(&spa->spa_feat_stats_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
|
||||
cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&spa->spa_proc_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&spa->spa_scrub_io_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&spa->spa_suspend_cv, NULL, CV_DEFAULT, NULL);
|
||||
@@ -619,6 +622,7 @@ spa_remove(spa_t *spa)
|
||||
|
||||
ASSERT(MUTEX_HELD(&spa_namespace_lock));
|
||||
ASSERT(spa->spa_state == POOL_STATE_UNINITIALIZED);
|
||||
ASSERT3U(refcount_count(&spa->spa_refcount), ==, 0);
|
||||
|
||||
nvlist_free(spa->spa_config_splitting);
|
||||
|
||||
@@ -651,6 +655,7 @@ spa_remove(spa_t *spa)
|
||||
bplist_destroy(&spa->spa_free_bplist[t]);
|
||||
|
||||
cv_destroy(&spa->spa_async_cv);
|
||||
cv_destroy(&spa->spa_evicting_os_cv);
|
||||
cv_destroy(&spa->spa_proc_cv);
|
||||
cv_destroy(&spa->spa_scrub_io_cv);
|
||||
cv_destroy(&spa->spa_suspend_cv);
|
||||
@@ -658,6 +663,7 @@ spa_remove(spa_t *spa)
|
||||
mutex_destroy(&spa->spa_async_lock);
|
||||
mutex_destroy(&spa->spa_errlist_lock);
|
||||
mutex_destroy(&spa->spa_errlog_lock);
|
||||
mutex_destroy(&spa->spa_evicting_os_lock);
|
||||
mutex_destroy(&spa->spa_history_lock);
|
||||
mutex_destroy(&spa->spa_proc_lock);
|
||||
mutex_destroy(&spa->spa_props_lock);
|
||||
@@ -714,6 +720,20 @@ spa_close(spa_t *spa, void *tag)
|
||||
(void) refcount_remove(&spa->spa_refcount, tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a reference to the given spa_t held by a dsl dir that is
|
||||
* being asynchronously released. Async releases occur from a taskq
|
||||
* performing eviction of dsl datasets and dirs. The namespace lock
|
||||
* isn't held and the hold by the object being evicted may contribute to
|
||||
* spa_minref (e.g. dataset or directory released during pool export),
|
||||
* so the asserts in spa_close() do not apply.
|
||||
*/
|
||||
void
|
||||
spa_async_close(spa_t *spa, void *tag)
|
||||
{
|
||||
(void) refcount_remove(&spa->spa_refcount, tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the spa refcount is zero. Must be called with
|
||||
* spa_namespace_lock held. We really compare against spa_minref, which is the
|
||||
@@ -1597,6 +1617,34 @@ spa_log_class(spa_t *spa)
|
||||
return (spa->spa_log_class);
|
||||
}
|
||||
|
||||
void
|
||||
spa_evicting_os_register(spa_t *spa, objset_t *os)
|
||||
{
|
||||
mutex_enter(&spa->spa_evicting_os_lock);
|
||||
list_insert_head(&spa->spa_evicting_os_list, os);
|
||||
mutex_exit(&spa->spa_evicting_os_lock);
|
||||
}
|
||||
|
||||
void
|
||||
spa_evicting_os_deregister(spa_t *spa, objset_t *os)
|
||||
{
|
||||
mutex_enter(&spa->spa_evicting_os_lock);
|
||||
list_remove(&spa->spa_evicting_os_list, os);
|
||||
cv_broadcast(&spa->spa_evicting_os_cv);
|
||||
mutex_exit(&spa->spa_evicting_os_lock);
|
||||
}
|
||||
|
||||
void
|
||||
spa_evicting_os_wait(spa_t *spa)
|
||||
{
|
||||
mutex_enter(&spa->spa_evicting_os_lock);
|
||||
while (!list_is_empty(&spa->spa_evicting_os_list))
|
||||
cv_wait(&spa->spa_evicting_os_cv, &spa->spa_evicting_os_lock);
|
||||
mutex_exit(&spa->spa_evicting_os_lock);
|
||||
|
||||
dmu_buf_user_evict_wait();
|
||||
}
|
||||
|
||||
int
|
||||
spa_max_replication(spa_t *spa)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user