summaryrefslogtreecommitdiffstats
path: root/sys/cddl
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2015-08-21 08:17:44 +0000
committeravg <avg@FreeBSD.org>2015-08-21 08:17:44 +0000
commitae89183402f4643d960bca1315e1c423e217414f (patch)
tree1c235c7ba261c0c9ec59270249f305431f75069b /sys/cddl
parent1a948318181bbd9f93e662f240e3e68b5bf11c7e (diff)
downloadFreeBSD-src-ae89183402f4643d960bca1315e1c423e217414f.zip
FreeBSD-src-ae89183402f4643d960bca1315e1c423e217414f.tar.gz
try to fix lor between z_teardown_lock and spa_namespace_lock
The lock order reversal and a resulting deadlock were introduced in r285021 / D2865. The problem is that zfs_register_callbacks() calls dsl_prop_get_integer() that has to acquire spa_namespace_lock. At the same time, spa_config_sync() is called with spa_namespace_lock held and then it performs ZFS vnode operations that acquire z_teardown_lock in the reader mode. So, fix the problem by using dsl_prop_get_int_ds() instead of dsl_prop_get_integer(). The former does not need to look up the pool and the dataset by name. Reported by: many Reviewed by: delphij Tested by: delphij, Jens Schweikhardt <schweikh@schweikhardt.net> MFC after: 5 days X-MFC with: r285021
Diffstat (limited to 'sys/cddl')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
index ed56d17..b45d958 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -472,6 +472,19 @@ zfs_register_callbacks(vfs_t *vfsp)
}
/*
+ * We need to enter pool configuration here, so that we can use
+ * dsl_prop_get_int_ds() to handle the special nbmand property below.
+ * dsl_prop_get_integer() can not be used, because it has to acquire
+ * spa_namespace_lock and we can not do that because we already hold
+ * z_teardown_lock. The problem is that spa_config_sync() is called
+ * with spa_namespace_lock held and the function calls ZFS vnode
+ * operations to write the cache file and thus z_teardown_lock is
+ * acquired after spa_namespace_lock.
+ */
+ ds = dmu_objset_ds(os);
+ dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+
+ /*
* nbmand is a special property. It can only be changed at
* mount time.
*
@@ -482,14 +495,9 @@ zfs_register_callbacks(vfs_t *vfsp)
nbmand = B_FALSE;
} else if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) {
nbmand = B_TRUE;
- } else {
- char osname[MAXNAMELEN];
-
- dmu_objset_name(os, osname);
- if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand,
- NULL)) {
- return (error);
- }
+ } else if (error = dsl_prop_get_int_ds(ds, "nbmand", &nbmand) != 0) {
+ dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+ return (error);
}
/*
@@ -499,8 +507,6 @@ zfs_register_callbacks(vfs_t *vfsp)
* the first prop_register(), but I guess I like to go
* overboard...
*/
- ds = dmu_objset_ds(os);
- dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
error = dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zfsvfs);
error = error ? error : dsl_prop_register(ds,
OpenPOWER on IntegriCloud