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

Andriy Gapon avg at FreeBSD.org
Tue Sep 12 06:06:59 UTC 2017


Author: avg
Date: Tue Sep 12 06:06:58 2017
New Revision: 323483
URL: https://svnweb.freebsd.org/changeset/base/323483

Log:
  zfsctl_snapdir_lookup should be able to handle an uncovered vnode
  
  The uncovered vnode is possible because there is no guarantee that
  its hold count would go to zero (and it would be inactivated and reclaimed)
  immediately after a covering filesystem is unmounted.
  So, such a vnode should be expected and it is possible to re-use it
  without any trouble.
  
  MFC after:	3 weeks
  Sponsored by:	Panzura

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	Tue Sep 12 06:05:30 2017	(r323482)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Tue Sep 12 06:06:58 2017	(r323483)
@@ -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