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

Andriy Gapon avg at FreeBSD.org
Mon May 16 15:28:40 UTC 2016


Author: avg
Date: Mon May 16 15:28:39 2016
New Revision: 299947
URL: https://svnweb.freebsd.org/changeset/base/299947

Log:
  fix locking in zfsctl_root_lookup
  
  Dropping the root vnode's lock after VFS_ROOT() didn't really help the
  fact that we acquired the lock while holding its child's, .zfs, lock
  while performing the operaiton.
  So, directly use zfs_zget() to get the root vnode.
  
  While there simplify the code in zfsctl_freebsd_root_lookup.
  We know that .zfs is always exclusively locked.
  We know that there is already a reference on *vpp, so no need for an
  extra one.
  Account for the fact that .. lookup may ask for a different lock type,
  not necessarily LK_EXCLUSIVE.  And handle a possible failure to acquire
  the lock given the lock flags.
  
  MFC after:	5 weeks

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

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Mon May 16 15:13:16 2016	(r299946)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Mon May 16 15:28:39 2016	(r299947)
@@ -537,9 +537,20 @@ zfsctl_root_lookup(vnode_t *dvp, char *n
 	ZFS_ENTER(zfsvfs);
 
 	if (strcmp(nm, "..") == 0) {
+#ifdef illumos
 		err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp);
+#else
+		/*
+		 * NB: can not use VFS_ROOT here as it would acquire
+		 * the vnode lock of the parent (root) vnode while
+		 * holding the child's (.zfs) lock.
+		 */
+		znode_t *rootzp;
+
+		err = zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp);
 		if (err == 0)
-			VOP_UNLOCK(*vpp, 0);
+			*vpp = ZTOV(rootzp);
+#endif
 	} else {
 		err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir,
 		    cr, ct, direntflags, realpnp);
@@ -601,10 +612,10 @@ zfsctl_freebsd_root_lookup(ap)
 	vnode_t **vpp = ap->a_vpp;
 	cred_t *cr = ap->a_cnp->cn_cred;
 	int flags = ap->a_cnp->cn_flags;
+	int lkflags = ap->a_cnp->cn_lkflags;
 	int nameiop = ap->a_cnp->cn_nameiop;
 	char nm[NAME_MAX + 1];
 	int err;
-	int ltype;
 
 	if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE))
 		return (EOPNOTSUPP);
@@ -613,16 +624,15 @@ zfsctl_freebsd_root_lookup(ap)
 	strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1);
 	err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL);
 	if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) {
-		ltype = VOP_ISLOCKED(dvp);
-		if (flags & ISDOTDOT) {
-			VN_HOLD(*vpp);
+		if (flags & ISDOTDOT)
 			VOP_UNLOCK(dvp, 0);
+		err = vn_lock(*vpp, lkflags);
+		if (err != 0) {
+			vrele(*vpp);
+			*vpp = NULL;
 		}
-		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
-		if (flags & ISDOTDOT) {
-			VN_RELE(*vpp);
-			vn_lock(dvp, ltype| LK_RETRY);
-		}
+		if (flags & ISDOTDOT)
+			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
 	}
 
 	return (err);


More information about the svn-src-all mailing list