git: bdadd506cae4 - stable/13 - vn_lock_pair(): allow to request shared locking
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 04 Jul 2023 03:19:04 UTC
The branch stable/13 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=bdadd506cae4e57010a8e1fed5d14b2b3af48939 commit bdadd506cae4e57010a8e1fed5d14b2b3af48939 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2023-04-06 04:11:08 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2023-07-04 03:07:02 +0000 vn_lock_pair(): allow to request shared locking (cherry picked from commit bb24eaea498268572aa140c35c02e02884cdf930) --- sys/kern/vfs_vnops.c | 86 ++++++++++++++++++++++++++++++++--------------- sys/sys/vnode.h | 4 +-- sys/ufs/ffs/ffs_softdep.c | 10 +++--- sys/ufs/ufs/ufs_vnops.c | 2 +- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index dfaa6868c567..e314739fa0ad 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -3868,50 +3868,74 @@ vn_lock_pair_pause(const char *wmesg) /* * Lock pair of vnodes vp1, vp2, avoiding lock order reversal. - * vp1_locked indicates whether vp1 is exclusively locked; if not, vp1 - * must be unlocked. Same for vp2 and vp2_locked. One of the vnodes - * can be NULL. + * vp1_locked indicates whether vp1 is locked; if not, vp1 must be + * unlocked. Same for vp2 and vp2_locked. One of the vnodes can be + * NULL. * - * The function returns with both vnodes exclusively locked, and - * guarantees that it does not create lock order reversal with other - * threads during its execution. Both vnodes could be unlocked - * temporary (and reclaimed). + * The function returns with both vnodes exclusively or shared locked, + * according to corresponding lkflags, and guarantees that it does not + * create lock order reversal with other threads during its execution. + * Both vnodes could be unlocked temporary (and reclaimed). + * + * If requesting shared locking, locked vnode lock must not be recursed. */ void -vn_lock_pair(struct vnode *vp1, bool vp1_locked, struct vnode *vp2, - bool vp2_locked) +vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1, + struct vnode *vp2, bool vp2_locked, int lkflags2) { int error; + MPASS(lkflags1 == LK_SHARED || lkflags1 == LK_EXCLUSIVE); + MPASS(lkflags2 == LK_SHARED || lkflags2 == LK_EXCLUSIVE); + if (vp1 == NULL && vp2 == NULL) return; + if (vp1 != NULL) { - if (vp1_locked) - ASSERT_VOP_ELOCKED(vp1, "vp1"); - else + if (lkflags1 == LK_SHARED && + (vp1->v_vnlock->lock_object.lo_flags & LK_NOSHARE) != 0) + lkflags1 = LK_EXCLUSIVE; + if (vp1_locked && VOP_ISLOCKED(vp1) != LK_EXCLUSIVE) { + ASSERT_VOP_LOCKED(vp1, "vp1"); + if (lkflags1 == LK_EXCLUSIVE) { + VOP_UNLOCK(vp1); + ASSERT_VOP_UNLOCKED(vp1, + "vp1 shared recursed"); + vp1_locked = false; + } + } else if (!vp1_locked) ASSERT_VOP_UNLOCKED(vp1, "vp1"); } else { vp1_locked = true; } + if (vp2 != NULL) { - if (vp2_locked) - ASSERT_VOP_ELOCKED(vp2, "vp2"); - else + if (lkflags2 == LK_SHARED && + (vp2->v_vnlock->lock_object.lo_flags & LK_NOSHARE) != 0) + lkflags2 = LK_EXCLUSIVE; + if (vp2_locked && VOP_ISLOCKED(vp2) != LK_EXCLUSIVE) { + ASSERT_VOP_LOCKED(vp2, "vp2"); + if (lkflags2 == LK_EXCLUSIVE) { + VOP_UNLOCK(vp2); + ASSERT_VOP_UNLOCKED(vp2, + "vp2 shared recursed"); + vp2_locked = false; + } + } else if (!vp2_locked) ASSERT_VOP_UNLOCKED(vp2, "vp2"); } else { vp2_locked = true; } + if (!vp1_locked && !vp2_locked) { - vn_lock(vp1, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp1, lkflags1 | LK_RETRY); vp1_locked = true; } - for (;;) { - if (vp1_locked && vp2_locked) - break; + while (!vp1_locked || !vp2_locked) { if (vp1_locked && vp2 != NULL) { if (vp1 != NULL) { - error = VOP_LOCK1(vp2, LK_EXCLUSIVE | LK_NOWAIT, + error = VOP_LOCK1(vp2, lkflags2 | LK_NOWAIT, __FILE__, __LINE__); if (error == 0) break; @@ -3919,12 +3943,12 @@ vn_lock_pair(struct vnode *vp1, bool vp1_locked, struct vnode *vp2, vp1_locked = false; vn_lock_pair_pause("vlp1"); } - vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp2, lkflags2 | LK_RETRY); vp2_locked = true; } if (vp2_locked && vp1 != NULL) { if (vp2 != NULL) { - error = VOP_LOCK1(vp1, LK_EXCLUSIVE | LK_NOWAIT, + error = VOP_LOCK1(vp1, lkflags1 | LK_NOWAIT, __FILE__, __LINE__); if (error == 0) break; @@ -3932,14 +3956,22 @@ vn_lock_pair(struct vnode *vp1, bool vp1_locked, struct vnode *vp2, vp2_locked = false; vn_lock_pair_pause("vlp2"); } - vn_lock(vp1, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp1, lkflags1 | LK_RETRY); vp1_locked = true; } } - if (vp1 != NULL) - ASSERT_VOP_ELOCKED(vp1, "vp1 ret"); - if (vp2 != NULL) - ASSERT_VOP_ELOCKED(vp2, "vp2 ret"); + if (vp1 != NULL) { + if (lkflags1 == LK_EXCLUSIVE) + ASSERT_VOP_ELOCKED(vp1, "vp1 ret"); + else + ASSERT_VOP_LOCKED(vp1, "vp1 ret"); + } + if (vp2 != NULL) { + if (lkflags2 == LK_EXCLUSIVE) + ASSERT_VOP_ELOCKED(vp2, "vp2 ret"); + else + ASSERT_VOP_LOCKED(vp2, "vp2 ret"); + } } int diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 82e9ba9a2237..e79bd1c9ddba 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -761,8 +761,8 @@ 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, struct vnode *vp2, - bool vp2_locked); +void 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, u_int vn_open_flags, struct ucred *cred, struct file *fp); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index ff72dad97250..c86ae35ee8c5 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -3323,7 +3323,7 @@ softdep_prelink(struct vnode *dvp, if (vp != NULL) { VOP_UNLOCK(dvp); ffs_syncvnode(vp, MNT_NOWAIT, 0); - vn_lock_pair(dvp, false, vp, true); + vn_lock_pair(dvp, false, LK_EXCLUSIVE, vp, true, LK_EXCLUSIVE); if (dvp->v_data == NULL) goto out; } @@ -3335,7 +3335,8 @@ softdep_prelink(struct vnode *dvp, VOP_UNLOCK(dvp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_data == NULL) { - vn_lock_pair(dvp, false, vp, true); + vn_lock_pair(dvp, false, LK_EXCLUSIVE, vp, true, + LK_EXCLUSIVE); goto out; } ACQUIRE_LOCK(ump); @@ -3345,7 +3346,8 @@ softdep_prelink(struct vnode *dvp, VOP_UNLOCK(vp); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); if (dvp->v_data == NULL) { - vn_lock_pair(dvp, true, vp, false); + vn_lock_pair(dvp, true, LK_EXCLUSIVE, vp, false, + LK_EXCLUSIVE); goto out; } } @@ -3360,7 +3362,7 @@ softdep_prelink(struct vnode *dvp, journal_check_space(ump); FREE_LOCK(ump); - vn_lock_pair(dvp, false, vp, false); + vn_lock_pair(dvp, false, LK_EXCLUSIVE, vp, false, LK_EXCLUSIVE); out: ndp->ni_dvp_seqc = vn_seqc_read_any(dvp); if (vp != NULL) diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 985641b02378..41bbb701c4fc 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -230,7 +230,7 @@ ufs_sync_nlink(struct vnode *vp, struct vnode *vp1) if (vp1 != NULL) VOP_UNLOCK(vp1); error = ufs_sync_nlink1(mp); - vn_lock_pair(vp, false, vp1, false); + vn_lock_pair(vp, false, LK_EXCLUSIVE, vp1, false, LK_EXCLUSIVE); return (error); }