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