svn commit: r324253 - stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs

Andriy Gapon avg at FreeBSD.org
Wed Oct 4 07:37:37 UTC 2017


Author: avg
Date: Wed Oct  4 07:37:36 2017
New Revision: 324253
URL: https://svnweb.freebsd.org/changeset/base/324253

Log:
  MFC r323483: zfsctl_snapdir_lookup should be able to handle an uncovered vnode

Modified:
  stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
==============================================================================
--- stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Wed Oct  4 07:36:06 2017	(r324252)
+++ stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Wed Oct  4 07:37:36 2017	(r324253)
@@ -816,6 +816,12 @@ zfsctl_snapshot_vnode_setup(vnode_t *vp, void *arg)
  * Lookup entry point for the 'snapshot' directory.  Try to open the
  * snapshot if it exist, creating the pseudo filesystem vnode as necessary.
  * Perform a mount of the associated dataset on top of the vnode.
+ * There are four possibilities:
+ * - the snapshot node and vnode do not exist
+ * - the snapshot vnode is covered by the mounted snapshot
+ * - the snapshot vnode is not covered yet, the mount operation is in progress
+ * - the snapshot vnode is not covered, because the snapshot has been unmounted
+ * The last two states are transient and should be relatively short-lived.
  */
 int
 zfsctl_snapdir_lookup(ap)
@@ -881,7 +887,7 @@ zfsctl_snapdir_lookup(ap)
 
 		/*
 		 * The vnode must be referenced at least by this thread and
-		 * the mounted snapshot or the thread doing the mounting.
+		 * the mount point or the thread doing the mounting.
 		 * There can be more references from concurrent lookups.
 		 */
 		KASSERT(vrefcnt(*vpp) > 1, ("found unreferenced mountpoint"));
@@ -893,22 +899,31 @@ zfsctl_snapdir_lookup(ap)
 		if (err != EJUSTRETURN)
 			return (err);
 
-#ifdef INVARIANTS
 		/*
-		 * If the vnode not covered yet, then the mount operation
-		 * must be in progress.
+		 * If the vnode is not covered, then either the mount operation
+		 * is in progress or the snapshot has already been unmounted
+		 * but the vnode hasn't been inactivated and reclaimed yet.
+		 * We can try to re-use the vnode in the latter case.
 		 */
 		VI_LOCK(*vpp);
-		KASSERT(((*vpp)->v_iflag & VI_MOUNT) != 0,
-		    ("snapshot vnode not covered"));
-		VI_UNLOCK(*vpp);
-#endif
-		vput(*vpp);
+		if (((*vpp)->v_iflag & VI_MOUNT) == 0) {
+			/* Upgrade to exclusive lock in order to:
+			 * - avoid race conditions
+			 * - satisfy the contract of mount_snapshot()
+			 */
+			err = VOP_LOCK(*vpp, LK_TRYUPGRADE | LK_INTERLOCK);
+			if (err == 0)
+				break;
+		} else {
+			VI_UNLOCK(*vpp);
+		}
 
 		/*
-		 * In this situation we can loop on uncontested locks and starve
+		 * In this state we can loop on uncontested locks and starve
 		 * the thread doing the lengthy, non-trivial mount operation.
+		 * So, yield to prevent that from happening.
 		 */
+		vput(*vpp);
 		kern_yield(PRI_USER);
 	}
 


More information about the svn-src-all mailing list