Skip site navigation (1)Skip section navigation (2)


| raw e-mail | index | archive | help

    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
---
 sys/kern/vfs_subr.c | 7 ++++---
 1 file 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);
 }
 
 /*