svn commit: r197458 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs

Pawel Jakub Dawidek pjd at FreeBSD.org
Thu Sep 24 15:49:15 UTC 2009


Author: pjd
Date: Thu Sep 24 15:49:15 2009
New Revision: 197458
URL: http://svn.freebsd.org/changeset/base/197458

Log:
  Close race in zfs_zget(). We have to increase usecount first and then
  check for VI_DOOMED flag. Before this change vnode could be reclaimed
  between checking for the flag and increasing usecount.
  
  MFC after:	3 days

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

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 Sep 24 15:34:18 2009	(r197457)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Thu Sep 24 15:49:15 2009	(r197458)
@@ -890,17 +890,25 @@ again:
 		if (zp->z_unlinked) {
 			err = ENOENT;
 		} else {
-			if ((vp = ZTOV(zp)) != NULL) {
-				VI_LOCK(vp);
+			int dying = 0;
+
+			vp = ZTOV(zp);
+			if (vp == NULL)
+				dying = 1;
+			else {
+				VN_HOLD(vp);
 				if ((vp->v_iflag & VI_DOOMED) != 0) {
-					VI_UNLOCK(vp);
-					vp = NULL;
-				} else
-					VI_UNLOCK(vp);
+					dying = 1;
+					/*
+					 * Don't VN_RELE() vnode here, because
+					 * it can call vn_lock() which creates
+					 * LOR between vnode lock and znode
+					 * lock. We will VN_RELE() the vnode
+					 * after droping znode lock.
+					 */
+				}
 			}
-			if (vp != NULL)
-				VN_HOLD(vp);
-			else {
+			if (dying) {
 				if (first) {
 					ZFS_LOG(1, "dying znode detected (zp=%p)", zp);
 					first = 0;
@@ -912,6 +920,8 @@ again:
 				dmu_buf_rele(db, NULL);
 				mutex_exit(&zp->z_lock);
 				ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
+				if (vp != NULL)
+					VN_RELE(vp);
 				tsleep(zp, 0, "zcollide", 1);
 				goto again;
 			}


More information about the svn-src-all mailing list