Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 May 2026 07:57:36 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: bae3d28fb6a7 - stable/15 - vn_lock_pair(): handle the case of vp1->v_vnlock == vp2->v_vnlock
Message-ID:  <6a17f570.2116c.67d93632@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by kib:

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

commit bae3d28fb6a72a5be337bf92c2294bbfdccbb13c
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-05-16 23:19:50 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-05-28 07:57:14 +0000

    vn_lock_pair(): handle the case of vp1->v_vnlock == vp2->v_vnlock
    
    (cherry picked from commit ace4a3e177c0da5efd9ceee0d9f46068562e3f5e)
---
 sys/kern/vfs_vnops.c | 32 +++++++++++++++++++++++++-------
 sys/sys/vnode.h      |  2 +-
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 393353d8c038..1746d344aa64 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -4358,9 +4358,16 @@ vn_lock_pair_pause(const char *wmesg)
  * Only one of LK_SHARED and LK_EXCLUSIVE must be specified.
  * LK_NODDLKTREAT can be optionally passed.
  *
- * If vp1 == vp2, only one, most exclusive, lock is obtained on it.
+ * If vp1->v_vnlock == vp2->v_vnlock, only one, most exclusive, lock
+ * is obtained on the vnode(s).  The function accounts for the
+ * possibility of vp1 or vp2' v_vnlock changing while the
+ * corresponding vnode is unlocked.
+ *
+ * Return values:
+ *    0       - locked, two unlocks are required
+ *    EDEADLK - locked, vnodes share the same lock, only one unlock is due.
  */
-void
+int
 vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
     struct vnode *vp2, bool vp2_locked, int lkflags2)
 {
@@ -4374,9 +4381,10 @@ vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
 	MPASS((lkflags2 & ~(LK_SHARED | LK_EXCLUSIVE | LK_NODDLKTREAT)) == 0);
 
 	if (vp1 == NULL && vp2 == NULL)
-		return;
+		return (0);
 
-	if (vp1 == vp2) {
+recheck_same:
+	if (vp1 != NULL && vp2 != NULL && vp1->v_vnlock == vp2->v_vnlock) {
 		MPASS(vp1_locked == vp2_locked);
 
 		/* Select the most exclusive mode for lock. */
@@ -4389,20 +4397,26 @@ vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
 			/* No need to relock if any lock is exclusive. */
 			if ((vp1->v_vnlock->lock_object.lo_flags &
 			    LK_NOSHARE) != 0)
-				return;
+				return (EDEADLK);
 
 			locked1 = VOP_ISLOCKED(vp1);
 			if (((lkflags1 & LK_SHARED) != 0 &&
 			    locked1 != LK_EXCLUSIVE) ||
 			    ((lkflags1 & LK_EXCLUSIVE) != 0 &&
 			    locked1 == LK_EXCLUSIVE))
-				return;
+				return (EDEADLK);
 			VOP_UNLOCK(vp1);
 		}
 
 		ASSERT_VOP_UNLOCKED(vp1, "vp1");
 		vn_lock(vp1, lkflags1 | LK_RETRY);
-		return;
+		if (vp1->v_vnlock == vp2->v_vnlock)
+			return (EDEADLK);
+		VOP_UNLOCK(vp1);
+		if (vp2_locked) {
+			VOP_UNLOCK(vp2);
+			vp2_locked = false;
+		}
 	}		
 
 	if (vp1 != NULL) {
@@ -4473,6 +4487,9 @@ vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
 			vn_lock(vp1, lkflags1 | LK_RETRY);
 			vp1_locked = true;
 		}
+		if (vp1 != NULL && vp2 != NULL &&
+		    vp1->v_vnlock == vp2->v_vnlock)
+			goto recheck_same;
 	}
 	if (vp1 != NULL) {
 		if (lkflags1 == LK_EXCLUSIVE)
@@ -4486,6 +4503,7 @@ vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
 		else
 			ASSERT_VOP_LOCKED(vp2, "vp2 ret");
 	}
+	return (0);
 }
 
 int
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index e48c4db95341..bb1d3faf567e 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -794,7 +794,7 @@ bool	vn_isdisk_error(struct vnode *vp, int *errp);
 bool	vn_isdisk(struct vnode *vp);
 int	_vn_lock(struct vnode *vp, int flags, const char *file, int line);
 #define vn_lock(vp, flags) _vn_lock(vp, flags, __FILE__, __LINE__)
-void	vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
+int	vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1,
 	    struct vnode *vp2, bool vp2_locked, int lkflags2);
 int	vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp);
 int	vn_open_cred(struct nameidata *ndp, int *flagp, int cmode,


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a17f570.2116c.67d93632>