diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2021-03-07 21:08:38 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2021-08-14 10:21:59 +0000 |
commit | 94cb19f46114950586fc363b518550c171849291 (patch) | |
tree | a1d6b33d5cb548f4b2bb7ece48d39a4523f60538 | |
parent | a14a142c6e32926b2d751356fb1f5ea4f3ddfa0c (diff) |
null_vput_pair(): release use reference on dvp earlier
(cherry picked from commit 16dea8341024b8ee8be619c27d4e63bd81bd9b6c)
-rw-r--r-- | sys/fs/nullfs/null_vnops.c | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index 6a6df55a0bef..e3a320a22bfa 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -1084,33 +1084,50 @@ null_vput_pair(struct vop_vput_pair_args *ap) vpp = ap->a_vpp; vp = NULL; lvp = NULL; - if (vpp != NULL) { + mp = NULL; + if (vpp != NULL) vp = *vpp; - if (vp != NULL) { + if (vp != NULL) { + lvp = NULLVPTOLOWERVP(vp); + vref(lvp); + if (!ap->a_unlock_vp) { vhold(vp); + vhold(lvp); mp = vp->v_mount; - lvp = NULLVPTOLOWERVP(vp); - if (ap->a_unlock_vp) - vref(lvp); + vfs_ref(mp); } } - res = VOP_VPUT_PAIR(ldvp, &lvp, ap->a_unlock_vp); + res = VOP_VPUT_PAIR(ldvp, lvp != NULL ? &lvp : NULL, true); + if (vp != NULL && ap->a_unlock_vp) + vrele(vp); + vrele(dvp); - /* lvp might have been unlocked and vp reclaimed */ - if (vp != NULL) { - if (!ap->a_unlock_vp && vp->v_vnlock != lvp->v_vnlock) { + if (vp == NULL || ap->a_unlock_vp) + return (res); + + /* lvp has been unlocked and vp might be reclaimed */ + VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); + if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) { + vput(vp); + vget(lvp, LK_EXCLUSIVE | LK_RETRY); + if (VN_IS_DOOMED(lvp)) { + vput(lvp); + vget(vp, LK_EXCLUSIVE | LK_RETRY); + } else { error = null_nodeget(mp, lvp, &vp1); if (error == 0) { - vput(vp); *vpp = vp1; + } else { + vget(vp, LK_EXCLUSIVE | LK_RETRY); } } - if (ap->a_unlock_vp) - vrele(vp); - vdrop(vp); + vfs_unbusy(mp); } - vrele(dvp); + vdrop(lvp); + vdrop(vp); + vfs_rel(mp); + return (res); } |