summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_subr.c
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2003-09-20 00:21:48 +0000
committerjeff <jeff@FreeBSD.org>2003-09-20 00:21:48 +0000
commit517dcea6c887615d6df5b301e114c77ba2c25a87 (patch)
treee064886f22ea0d1a5cdb0c19a1a075e8b3c309ab /sys/kern/vfs_subr.c
parent905b86aa3741484f87998054478f6bddf5ff8c54 (diff)
downloadFreeBSD-src-517dcea6c887615d6df5b301e114c77ba2c25a87.zip
FreeBSD-src-517dcea6c887615d6df5b301e114c77ba2c25a87.tar.gz
- In reassignbuf() don't unlock vp and lock newvp if they are the same.
Doing so creates a race where the buf is on neither list. - Only vfree() in an error case in vclean() if VSHOULDFREE() thinks we should. - Convert the error case in vclean() to INVARIANTS from DIAGNOSTIC as this really should not happen and is fast to check.
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r--sys/kern/vfs_subr.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 7a32058..2506e11 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1869,12 +1869,14 @@ reassignbuf(bp, newvp)
register struct buf *bp;
register struct vnode *newvp;
{
+ struct vnode *vp;
int delay;
if (newvp == NULL) {
printf("reassignbuf: NULL");
return;
}
+ vp = bp->b_vp;
++reassignbufcalls;
/*
@@ -1887,20 +1889,22 @@ reassignbuf(bp, newvp)
/*
* Delete from old vnode list, if on one.
*/
- VI_LOCK(bp->b_vp);
+ VI_LOCK(vp);
if (bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) {
buf_vlist_remove(bp);
- if (bp->b_vp != newvp) {
+ if (vp != newvp) {
vdropl(bp->b_vp);
bp->b_vp = NULL; /* for clarification */
}
}
- VI_UNLOCK(bp->b_vp);
+ if (vp != newvp) {
+ VI_UNLOCK(vp);
+ VI_LOCK(newvp);
+ }
/*
* If dirty, put on list of dirty buffers; otherwise insert onto list
* of clean buffers.
*/
- VI_LOCK(newvp);
if (bp->b_flags & B_DELWRI) {
if ((newvp->v_iflag & VI_ONWORKLST) == 0) {
switch (newvp->v_type) {
@@ -2580,13 +2584,14 @@ vclean(vp, flags, td)
VI_LOCK(vp);
v_incr_usecount(vp, -1);
if (vp->v_usecount <= 0) {
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
if (vp->v_usecount < 0 || vp->v_writecount != 0) {
vprint("vclean: bad ref count", vp);
panic("vclean: ref cnt");
}
#endif
- vfree(vp);
+ if (VSHOULDFREE(vp))
+ vfree(vp);
}
VI_UNLOCK(vp);
}
OpenPOWER on IntegriCloud