| 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);
}
/*
