Print this page
5056 ZFS deadlock on db_mtx and dn_holds
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>

@@ -21,10 +21,11 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2013, 2014, Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 
 /*
  * SPA: Storage Pool Allocator
  *

@@ -1086,10 +1087,12 @@
                 spa_create_zio_taskqs(spa);
         }
 
         list_create(&spa->spa_config_dirty_list, sizeof (vdev_t),
             offsetof(vdev_t, vdev_config_dirty_node));
+        list_create(&spa->spa_evicting_os_list, sizeof (objset_t),
+            offsetof(objset_t, os_evicting_node));
         list_create(&spa->spa_state_dirty_list, sizeof (vdev_t),
             offsetof(vdev_t, vdev_state_dirty_node));
 
         txg_list_create(&spa->spa_vdev_txg_list,
             offsetof(struct vdev, vdev_txg_node));

@@ -1112,13 +1115,16 @@
         ASSERT(spa->spa_dsl_pool == NULL);
         ASSERT(spa->spa_root_vdev == NULL);
         ASSERT(spa->spa_async_zio_root == NULL);
         ASSERT(spa->spa_state != POOL_STATE_UNINITIALIZED);
 
+        spa_evicting_os_wait(spa);
+
         txg_list_destroy(&spa->spa_vdev_txg_list);
 
         list_destroy(&spa->spa_config_dirty_list);
+        list_destroy(&spa->spa_evicting_os_list);
         list_destroy(&spa->spa_state_dirty_list);
 
         for (int t = 0; t < ZIO_TYPES; t++) {
                 for (int q = 0; q < ZIO_TASKQ_TYPES; q++) {
                         spa_taskqs_fini(spa, t, q);

@@ -2105,10 +2111,15 @@
                 gethrestime(&spa->spa_loaded_ts);
                 error = spa_load_impl(spa, pool_guid, config, state, type,
                     mosconfig, &ereport);
         }
 
+        /*
+         * Don't count references from objsets that are already closed
+         * and are making their way through the eviction process.
+         */
+        spa_evicting_os_wait(spa);
         spa->spa_minref = refcount_count(&spa->spa_refcount);
         if (error) {
                 if (error != EEXIST) {
                         spa->spa_loaded_ts.tv_sec = 0;
                         spa->spa_loaded_ts.tv_nsec = 0;

@@ -3673,10 +3684,15 @@
 
         spa_config_sync(spa, B_FALSE, B_TRUE);
 
         spa_history_log_version(spa, "create");
 
+        /*
+         * Don't count references from objsets that are already closed
+         * and are making their way through the eviction process.
+         */
+        spa_evicting_os_wait(spa);
         spa->spa_minref = refcount_count(&spa->spa_refcount);
 
         mutex_exit(&spa_namespace_lock);
 
         return (0);

@@ -4205,10 +4221,11 @@
                 /*
                  * Objsets may be open only because they're dirty, so we
                  * have to force it to sync before checking spa_refcnt.
                  */
                 txg_wait_synced(spa->spa_dsl_pool, 0);
+                spa_evicting_os_wait(spa);
 
                 /*
                  * A pool cannot be exported or destroyed if there are active
                  * references.  If we are resetting a pool, allow references by
                  * fault injection handlers.