From 243f5e3085bc46cb71cfe1e3dd48ecce75e2e944 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Fri, 21 Aug 2015 08:17:44 +0000 Subject: [PATCH] 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 MFC after: 5 days X-MFC with: r285021 --- .../uts/common/fs/zfs/zfs_vfsops.c | 26 ++++++++++++------- 1 file 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 ed56d17738a..b45d958a030 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 @@ -471,6 +471,19 @@ zfs_register_callbacks(vfs_t *vfsp) do_atime = B_TRUE; } + /* + * 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,