diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 93e0a2404532..f455757ff1c6 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -606,3 +606,8 @@ in your dentry operations instead.
 	dentry separately, and it now has request_mask and query_flags arguments
 	to specify the fields and sync type requested by statx.  Filesystems not
 	supporting any statx-specific features may ignore the new arguments.
+--
+[recommended]
+	->d_weak_revalidate should perform the same handling of LOOKUP_OPEN as
+	->d_revalidate.  If LOOKUP_OPEN is not set, d_weak_revalidate need not
+	do anything.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 5fd325df59e2..c2025e226b29 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -1015,14 +1015,15 @@ struct dentry_operations {
 	doing a lookup in the parent directory. This includes "/", "." and "..",
 	as well as procfs-style symlinks and mountpoint traversal.
 
-	In this case, we are less concerned with whether the dentry is still
-	fully correct, but rather that the inode is still valid. As with
-	d_revalidate, most local filesystems will set this to NULL since their
-	dcache entries are always valid.
+	Filesystems only need this if they handle LOOKUP_OPEN in
+	d_revalidate, in which case the same handling should be applied
+	in d_weak_revalidate.  When LOOKUP_OPEN is not set,
+	d_weak_revalidate can safely be a no-op.
 
 	This function has the same return code semantics as d_revalidate.
 
-	d_weak_revalidate is only called after leaving rcu-walk mode.
+	d_weak_revalidate is only called after leaving rcu-walk mode,
+	so LOOKUP_RCU is never set.
 
   d_hash: called when the VFS adds a dentry to the hash table. The first
 	dentry passed to d_hash is the parent directory that the name is
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index bd456c668d39..99eaf3c6d44c 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -111,7 +111,6 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 
 const struct dentry_operations v9fs_cached_dentry_operations = {
 	.d_revalidate = v9fs_lookup_revalidate,
-	.d_weak_revalidate = v9fs_lookup_revalidate,
 	.d_delete = v9fs_cached_dentry_delete,
 	.d_release = v9fs_dentry_release,
 };
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 5ceaeb1f6fb6..fc349577526f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -118,13 +118,6 @@ nfs_opendir(struct inode *inode, struct file *filp)
 		goto out;
 	}
 	filp->private_data = ctx;
-	if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) {
-		/* This is a mountpoint, so d_revalidate will never
-		 * have been called, so we need to refresh the
-		 * inode (for close-open consistency) ourselves.
-		 */
-		__nfs_revalidate_inode(NFS_SERVER(inode), inode);
-	}
 out:
 	put_rpccred(cred);
 	return res;
@@ -972,17 +965,19 @@ EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate);
  * If rcu_walk prevents us from performing a full check, return 0.
  */
 static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
-			      int rcu_walk)
+			      unsigned int flags)
 {
 	if (IS_ROOT(dentry))
 		return 1;
+	if (flags & LOOKUP_JUMPED)
+		return 1;
 	if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
 		return 0;
 	if (!nfs_verify_change_attribute(dir, dentry->d_time))
 		return 0;
 	/* Revalidate nfsi->cache_change_attribute before we declare a match */
 	if (nfs_mapping_need_revalidate_inode(dir)) {
-		if (rcu_walk)
+		if (flags & LOOKUP_RCU)
 			return 0;
 		if (__nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
 			return 0;
@@ -1056,7 +1051,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
 		return 0;
 	if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
 		return 1;
-	return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
+	return !nfs_check_verifier(dir, dentry, flags);
 }
 
 /*
@@ -1114,7 +1109,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 
 	/* Force a full look up iff the parent directory has changed */
 	if (!nfs_is_exclusive_create(dir, flags) &&
-	    nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
+	    nfs_check_verifier(dir, dentry, flags)) {
 		error = nfs_lookup_verify_inode(inode, flags);
 		if (error) {
 			if (flags & LOOKUP_RCU)
@@ -1129,6 +1124,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 
 	if (flags & LOOKUP_RCU)
 		return -ECHILD;
+	if (flags & LOOKUP_JUMPED)
+		return 1;
 
 	if (NFS_STALE(inode))
 		goto out_bad;
@@ -1210,44 +1207,6 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 	return error;
 }
 
-/*
- * A weaker form of d_revalidate for revalidating just the d_inode(dentry)
- * when we don't really care about the dentry name. This is called when a
- * pathwalk ends on a dentry that was not found via a normal lookup in the
- * parent dir (e.g.: ".", "..", procfs symlinks or mountpoint traversals).
- *
- * In this situation, we just want to verify that the inode itself is OK
- * since the dentry might have changed on the server.
- */
-static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags)
-{
-	struct inode *inode = d_inode(dentry);
-	int error = 0;
-
-	/*
-	 * I believe we can only get a negative dentry here in the case of a
-	 * procfs-style symlink. Just assume it's correct for now, but we may
-	 * eventually need to do something more here.
-	 */
-	if (!inode) {
-		dfprintk(LOOKUPCACHE, "%s: %pd2 has negative inode\n",
-				__func__, dentry);
-		return 1;
-	}
-
-	if (is_bad_inode(inode)) {
-		dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
-				__func__, dentry);
-		return 0;
-	}
-
-	if (nfs_mapping_need_revalidate_inode(inode))
-		error = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
-	dfprintk(LOOKUPCACHE, "NFS: %s: inode %lu is %s\n",
-			__func__, inode->i_ino, error ? "invalid" : "valid");
-	return !error;
-}
-
 /*
  * This is called from dput() when d_count is going to 0.
  */
@@ -1314,7 +1273,7 @@ static void nfs_d_release(struct dentry *dentry)
 
 const struct dentry_operations nfs_dentry_operations = {
 	.d_revalidate	= nfs_lookup_revalidate,
-	.d_weak_revalidate	= nfs_weak_revalidate,
+	.d_weak_revalidate	= nfs_lookup_revalidate,
 	.d_delete	= nfs_dentry_delete,
 	.d_iput		= nfs_dentry_iput,
 	.d_automount	= nfs_d_automount,
@@ -1393,6 +1352,7 @@ static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
 
 const struct dentry_operations nfs4_dentry_operations = {
 	.d_revalidate	= nfs4_lookup_revalidate,
+	.d_weak_revalidate	= nfs4_lookup_revalidate,
 	.d_delete	= nfs_dentry_delete,
 	.d_iput		= nfs_dentry_iput,
 	.d_automount	= nfs_d_automount,
