aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2025-11-11 14:47:06 +0000
committerMark Johnston <markj@FreeBSD.org>2025-11-11 14:58:59 +0000
commit99cb3dca4773fe4a16c500f9cb55fcd62cd8d7f3 (patch)
treec3a25de04088b953af3004e2ca1359c804b87524
parent38839c872e7af6a1424009bf07d6b4450e9ca61d (diff)
vnode: Rework vput() to avoid holding the vnode lock after decrementing
It is not safe to modify the vnode structure after releasing one's reference. Modify vput() to avoid this. Use refcount_release_if_last() to opportunistically call vput_final() with the vnode lock held since we need the vnode lock in order to deactivate the vnode, and it's silly to drop the vnode lock and immediately reacquire it in this common case. Note that vunref() has a similar flaw. D52628 aims to fix the problem more holistically, but this change fixes observable panics in the meantime. Reported by: syzbot+6676b3ff282d590b0fb3@syzkaller.appspotmail.com Reported by: syzbot+38e26cf6f959e886f110@syzkaller.appspotmail.com Reviewed by: kib MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D52608
-rw-r--r--sys/kern/vfs_subr.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 58975f7ac932..9cf983f6f89d 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -3713,11 +3713,12 @@ vput(struct vnode *vp)
ASSERT_VOP_LOCKED(vp, __func__);
ASSERT_VI_UNLOCKED(vp, __func__);
- if (!refcount_release(&vp->v_usecount)) {
- VOP_UNLOCK(vp);
+ if (refcount_release_if_last(&vp->v_usecount)) {
+ vput_final(vp, VPUT);
return;
}
- vput_final(vp, VPUT);
+ VOP_UNLOCK(vp);
+ vrele(vp);
}
/*