Make lfs_vref/lfs_vunref not need to know about VXLOCK and VFREEING
explicitly (especially since we didn't know about VFREEING at all before), but notice the EBUSY return from vget() instead. Fix some more MP locking protocol issues, most of which were pointed out by Christian Ehrhardt this morning on tech-kern.
This commit is contained in:
parent
d7e1743903
commit
81ded5df65
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: lfs.h,v 1.101 2006/04/10 21:20:19 perseant Exp $ */
|
||||
/* $NetBSD: lfs.h,v 1.102 2006/04/13 23:46:28 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
@ -787,6 +787,7 @@ struct lfs {
|
||||
u_int16_t lfs_activesb; /* toggle between superblocks */
|
||||
daddr_t lfs_sbactive; /* disk address of current sb write */
|
||||
struct vnode *lfs_flushvp; /* vnode being flushed */
|
||||
int lfs_flushvp_fakevref; /* fake vref count for flushvp */
|
||||
struct vnode *lfs_unlockvp; /* being inactivated in lfs_segunlock */
|
||||
u_int32_t lfs_diropwait; /* # procs waiting on dirop flush */
|
||||
size_t lfs_devbsize; /* Device block size */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: lfs_bio.c,v 1.90 2006/03/05 17:33:33 christos Exp $ */
|
||||
/* $NetBSD: lfs_bio.c,v 1.91 2006/04/13 23:46:28 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
@ -67,7 +67,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.90 2006/03/05 17:33:33 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.91 2006/04/13 23:46:28 perseant Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -251,8 +251,10 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX use lockstatus */
|
||||
vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY); /* XXX use lockstatus */
|
||||
#endif
|
||||
if (error)
|
||||
if (error) {
|
||||
return error;
|
||||
simple_unlock(&fs->lfs_interlock);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (slept) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: lfs_segment.c,v 1.172 2006/04/07 23:59:28 perseant Exp $ */
|
||||
/* $NetBSD: lfs_segment.c,v 1.173 2006/04/13 23:46:28 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
@ -67,7 +67,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.172 2006/04/07 23:59:28 perseant Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.173 2006/04/13 23:46:28 perseant Exp $");
|
||||
|
||||
#ifdef DEBUG
|
||||
# define vndebug(vp, str) do { \
|
||||
@ -190,9 +190,7 @@ lfs_imtime(struct lfs *fs)
|
||||
* explicitly marks the file system busy. So lfs_segwrite is safe. I think.
|
||||
*/
|
||||
|
||||
#define SET_FLUSHING(fs,vp) (fs)->lfs_flushvp = (vp)
|
||||
#define IS_FLUSHING(fs,vp) ((fs)->lfs_flushvp == (vp))
|
||||
#define CLR_FLUSHING(fs,vp) (fs)->lfs_flushvp = NULL
|
||||
|
||||
int
|
||||
lfs_vflush(struct vnode *vp)
|
||||
@ -250,6 +248,7 @@ lfs_vflush(struct vnode *vp)
|
||||
wakeup(&fs->lfs_avail);
|
||||
lfs_freebuf(fs, bp);
|
||||
bp = NULL;
|
||||
simple_unlock(&vp->v_interlock);
|
||||
goto nextbp;
|
||||
}
|
||||
}
|
||||
@ -325,10 +324,11 @@ lfs_vflush(struct vnode *vp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SET_FLUSHING(fs,vp);
|
||||
fs->lfs_flushvp = vp;
|
||||
if (LFS_SHOULD_CHECKPOINT(fs, fs->lfs_sp->seg_flags)) {
|
||||
error = lfs_segwrite(vp->v_mount, SEGM_CKP | SEGM_SYNC);
|
||||
CLR_FLUSHING(fs,vp);
|
||||
fs->lfs_flushvp = NULL;
|
||||
KASSERT(fs->lfs_flushvp_fakevref == 0);
|
||||
lfs_segunlock(fs);
|
||||
return error;
|
||||
}
|
||||
@ -417,7 +417,9 @@ lfs_vflush(struct vnode *vp)
|
||||
simple_unlock(&global_v_numoutput_slock);
|
||||
splx(s);
|
||||
|
||||
CLR_FLUSHING(fs,vp);
|
||||
fs->lfs_flushvp = NULL;
|
||||
KASSERT(fs->lfs_flushvp_fakevref == 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2482,24 +2484,30 @@ lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb, int size)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check VXLOCK. Return 1 if the vnode is locked. Otherwise, vget it.
|
||||
* Call vget with LK_NOWAIT. If we are the one who holds VXLOCK/VFREEING,
|
||||
* however, we must press on. Just fake success in that case.
|
||||
*/
|
||||
int
|
||||
lfs_vref(struct vnode *vp)
|
||||
{
|
||||
ASSERT_MAYBE_SEGLOCK(VTOI(vp)->i_lfs);
|
||||
int error;
|
||||
struct lfs *fs;
|
||||
|
||||
fs = VTOI(vp)->i_lfs;
|
||||
|
||||
ASSERT_MAYBE_SEGLOCK(fs);
|
||||
|
||||
/*
|
||||
* If we return 1 here during a flush, we risk vinvalbuf() not
|
||||
* being able to flush all of the pages from this vnode, which
|
||||
* will cause it to panic. So, return 0 if a flush is in progress.
|
||||
*/
|
||||
if (vp->v_flag & VXLOCK) {
|
||||
if (IS_FLUSHING(VTOI(vp)->i_lfs, vp)) {
|
||||
return 0;
|
||||
}
|
||||
return (1);
|
||||
error = vget(vp, LK_NOWAIT);
|
||||
if (error == EBUSY && IS_FLUSHING(VTOI(vp)->i_lfs, vp)) {
|
||||
++fs->lfs_flushvp_fakevref;
|
||||
return 0;
|
||||
}
|
||||
return (vget(vp, 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2509,11 +2517,16 @@ lfs_vref(struct vnode *vp)
|
||||
void
|
||||
lfs_vunref(struct vnode *vp)
|
||||
{
|
||||
ASSERT_MAYBE_SEGLOCK(VTOI(vp)->i_lfs);
|
||||
struct lfs *fs;
|
||||
|
||||
fs = VTOI(vp)->i_lfs;
|
||||
ASSERT_MAYBE_SEGLOCK(fs);
|
||||
|
||||
/*
|
||||
* Analogous to lfs_vref, if the node is flushing, fake it.
|
||||
*/
|
||||
if ((vp->v_flag & VXLOCK) && IS_FLUSHING(VTOI(vp)->i_lfs, vp)) {
|
||||
if (IS_FLUSHING(fs, vp) && fs->lfs_flushvp_fakevref) {
|
||||
--fs->lfs_flushvp_fakevref;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: lfs_vnops.c,v 1.166 2006/04/11 22:08:00 perseant Exp $ */
|
||||
/* $NetBSD: lfs_vnops.c,v 1.167 2006/04/13 23:46:28 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
@ -67,7 +67,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.166 2006/04/11 22:08:00 perseant Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.167 2006/04/13 23:46:28 perseant Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -1105,14 +1105,15 @@ lfs_strategy(void *v)
|
||||
"lfs_strategy: sleeping on ino %d lbn %"
|
||||
PRId64 "\n", ip->i_number, bp->b_lblkno));
|
||||
simple_lock(&fs->lfs_interlock);
|
||||
if (fs->lfs_seglock)
|
||||
if (fs->lfs_seglock) {
|
||||
ltsleep(&fs->lfs_seglock,
|
||||
(PRIBIO + 1) | PNORELOCK,
|
||||
"lfs_strategy", 0,
|
||||
&fs->lfs_interlock);
|
||||
/* Things may be different now; start over. */
|
||||
slept = 1;
|
||||
break;
|
||||
slept = 1;
|
||||
break;
|
||||
}
|
||||
simple_unlock(&fs->lfs_interlock);
|
||||
}
|
||||
}
|
||||
simple_lock(&fs->lfs_interlock);
|
||||
@ -1186,8 +1187,10 @@ lfs_flush_dirops(struct lfs *fs)
|
||||
* make sure that we don't clear IN_MODIFIED
|
||||
* unnecessarily.
|
||||
*/
|
||||
if (vp->v_flag & VXLOCK)
|
||||
if (vp->v_flag & (VXLOCK | VFREEING)) {
|
||||
simple_lock(&fs->lfs_interlock);
|
||||
continue;
|
||||
}
|
||||
if (vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT) == 0) {
|
||||
needunlock = 1;
|
||||
} else {
|
||||
@ -2015,9 +2018,10 @@ again:
|
||||
preempt(1);
|
||||
|
||||
/* We've lost the interlock. Start over. */
|
||||
simple_lock(&vp->v_interlock);
|
||||
if (error == EDEADLK)
|
||||
if (error == EDEADLK) {
|
||||
simple_lock(&vp->v_interlock);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
KASSERT(sp->vp == vp);
|
||||
|
Loading…
Reference in New Issue
Block a user