Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Jan 2014 12:22:46 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r260704 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
Message-ID:  <201401161222.s0GCMkjM084087@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Thu Jan 16 12:22:46 2014
New Revision: 260704
URL: http://svnweb.freebsd.org/changeset/base/260704

Log:
  zfs: getnewvnode_reserve must be called outside of a zfs transaction
  
  Otherwise we could run into the following deadlock.
  A thread has a transaction open and assigned to a transaction group.
  That would prevent the transaction group from be quiesced and synced.
  The thread is blocked in getnewvnode_reserve waiting for a vnode to
  a be reclaimed.  vnlru thread is blocked trying to enter ZFS VOP because
  a filesystem is suspended by an ongoing rollback or receive operation.
  In its turn the operation is waiting for the current transaction group
  to be synced.
  
  zfs_zget is always used outside of active transactions, but zfs_mknode
  is always used in a transaction context.  Thus, we hoist
  getnewvnode_reserve from zfs_mknode to its callers.
  
  While there, assert that ZFS always calls getnewvnode while having
  a vnode reserved.
  
  Reported by:	adrian
  Tested by:	adrian
  MFC after:	17 days
  Sponsored by:	HybridCluster

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c	Thu Jan 16 12:21:21 2014	(r260703)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c	Thu Jan 16 12:22:46 2014	(r260704)
@@ -951,6 +951,8 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *
 		return (SET_ERROR(EDQUOT));
 	}
 
+	getnewvnode_reserve(1);
+
 	tx = dmu_tx_create(zfsvfs->z_os);
 	dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
 	    ZFS_SA_BASE_ATTR_SIZE);
@@ -985,6 +987,8 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *
 	zfs_acl_ids_free(&acl_ids);
 	dmu_tx_commit(tx);
 
+	getnewvnode_drop_reserve();
+
 	*xvpp = ZTOV(xzp);
 
 	return (0);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	Thu Jan 16 12:21:21 2014	(r260703)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	Thu Jan 16 12:22:46 2014	(r260704)
@@ -1625,6 +1625,9 @@ zfs_create(vnode_t *dvp, char *name, vat
 			return (error);
 		}
 	}
+
+	getnewvnode_reserve(1);
+
 top:
 	*vpp = NULL;
 
@@ -1653,6 +1656,7 @@ top:
 				zfs_acl_ids_free(&acl_ids);
 			if (strcmp(name, "..") == 0)
 				error = SET_ERROR(EISDIR);
+			getnewvnode_drop_reserve();
 			ZFS_EXIT(zfsvfs);
 			return (error);
 		}
@@ -1721,6 +1725,7 @@ top:
 			}
 			zfs_acl_ids_free(&acl_ids);
 			dmu_tx_abort(tx);
+			getnewvnode_drop_reserve();
 			ZFS_EXIT(zfsvfs);
 			return (error);
 		}
@@ -1787,6 +1792,7 @@ top:
 		}
 	}
 out:
+	getnewvnode_drop_reserve();
 	if (dl)
 		zfs_dirent_unlock(dl);
 
@@ -2130,6 +2136,9 @@ zfs_mkdir(vnode_t *dvp, char *dirname, v
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
+
+	getnewvnode_reserve(1);
+
 	/*
 	 * First make sure the new directory doesn't exist.
 	 *
@@ -2143,6 +2152,7 @@ top:
 	if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf,
 	    NULL, NULL)) {
 		zfs_acl_ids_free(&acl_ids);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
@@ -2150,6 +2160,7 @@ top:
 	if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) {
 		zfs_acl_ids_free(&acl_ids);
 		zfs_dirent_unlock(dl);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
@@ -2157,6 +2168,7 @@ top:
 	if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) {
 		zfs_acl_ids_free(&acl_ids);
 		zfs_dirent_unlock(dl);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (SET_ERROR(EDQUOT));
 	}
@@ -2189,6 +2201,7 @@ top:
 		}
 		zfs_acl_ids_free(&acl_ids);
 		dmu_tx_abort(tx);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
@@ -2218,6 +2231,8 @@ top:
 
 	dmu_tx_commit(tx);
 
+	getnewvnode_drop_reserve();
+
 	zfs_dirent_unlock(dl);
 
 	if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
@@ -4109,6 +4124,9 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp,
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
+
+	getnewvnode_reserve(1);
+
 top:
 	/*
 	 * Attempt to lock directory; fail if entry already exists.
@@ -4116,6 +4134,7 @@ top:
 	error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL);
 	if (error) {
 		zfs_acl_ids_free(&acl_ids);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
@@ -4123,6 +4142,7 @@ top:
 	if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
 		zfs_acl_ids_free(&acl_ids);
 		zfs_dirent_unlock(dl);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
@@ -4130,6 +4150,7 @@ top:
 	if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) {
 		zfs_acl_ids_free(&acl_ids);
 		zfs_dirent_unlock(dl);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (SET_ERROR(EDQUOT));
 	}
@@ -4157,6 +4178,7 @@ top:
 		}
 		zfs_acl_ids_free(&acl_ids);
 		dmu_tx_abort(tx);
+		getnewvnode_drop_reserve();
 		ZFS_EXIT(zfsvfs);
 		return (error);
 	}
@@ -4195,6 +4217,8 @@ top:
 
 	dmu_tx_commit(tx);
 
+	getnewvnode_drop_reserve();
+
 	zfs_dirent_unlock(dl);
 
 	if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Thu Jan 16 12:21:21 2014	(r260703)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Thu Jan 16 12:22:46 2014	(r260704)
@@ -624,6 +624,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu
 
 	zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
 
+	KASSERT(td->td_vp_reserv > 0,
+	    ("zfs_znode_alloc: getnewvnode without any vnodes reserved"));
 	error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp);
 	if (error != 0) {
 		kmem_cache_free(znode_cache, zp);
@@ -830,7 +832,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, d
 		}
 	}
 
-	getnewvnode_reserve(1);
 	ZFS_OBJ_HOLD_ENTER(zfsvfs, obj);
 	VERIFY(0 == sa_buf_hold(zfsvfs->z_os, obj, NULL, &db));
 
@@ -1016,7 +1017,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, d
 		KASSERT(err == 0, ("insmntque() failed: error %d", err));
 	}
 	ZFS_OBJ_HOLD_EXIT(zfsvfs, obj);
-	getnewvnode_drop_reserve();
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201401161222.s0GCMkjM084087>