git: 0a4eb4d65c11 - stable/13 - null_bypass(): prevent loosing the only reference to the lower vnode

Konstantin Belousov kib at FreeBSD.org
Tue Aug 3 09:52:47 UTC 2021


The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=0a4eb4d65c11dc775733dd5a0a470419e1376515

commit 0a4eb4d65c11dc775733dd5a0a470419e1376515
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-07-20 00:53:08 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-08-03 09:52:35 +0000

    null_bypass(): prevent loosing the only reference to the lower vnode
    
    (cherry picked from commit d5b078163e0d6bb2fe36f8e49a44853908d5e2db)
---
 sys/fs/nullfs/null_vnops.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 4dfc5efaf9ed..03f8b0dcbf7d 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -266,6 +266,17 @@ null_bypass(struct vop_generic_args *ap)
 			old_vps[i] = *this_vp_p;
 			*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
 
+			/*
+			 * The upper vnode reference to the lower
+			 * vnode is the only reference that keeps our
+			 * pointer to the lower vnode alive.  If lower
+			 * vnode is relocked during the VOP call,
+			 * upper vnode might become unlocked and
+			 * reclaimed, which invalidates our reference.
+			 * Add a transient hold around VOP call.
+			 */
+			vhold(*this_vp_p);
+
 			/*
 			 * XXX - Several operations have the side effect
 			 * of vrele'ing their vp's.  We must account for
@@ -300,6 +311,7 @@ null_bypass(struct vop_generic_args *ap)
 			lvp = *(vps_p[i]);
 
 			/*
+			 * Get rid of the transient hold on lvp.
 			 * If lowervp was unlocked during VOP
 			 * operation, nullfs upper vnode could have
 			 * been reclaimed, which changes its v_vnlock
@@ -307,11 +319,14 @@ null_bypass(struct vop_generic_args *ap)
 			 * must move lock ownership from lower to
 			 * upper (reclaimed) vnode.
 			 */
-			if (lvp != NULLVP &&
-			    VOP_ISLOCKED(lvp) == LK_EXCLUSIVE &&
-			    old_vps[i]->v_vnlock != lvp->v_vnlock) {
-				VOP_UNLOCK(lvp);
-				VOP_LOCK(old_vps[i], LK_EXCLUSIVE | LK_RETRY);
+			if (lvp != NULLVP) {
+				if (VOP_ISLOCKED(lvp) == LK_EXCLUSIVE &&
+				    old_vps[i]->v_vnlock != lvp->v_vnlock) {
+					VOP_UNLOCK(lvp);
+					VOP_LOCK(old_vps[i], LK_EXCLUSIVE |
+					    LK_RETRY);
+				}
+				vdrop(lvp);
 			}
 
 			*(vps_p[i]) = old_vps[i];


More information about the dev-commits-src-branches mailing list