summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2005-02-19 11:44:57 +0000
committerphk <phk@FreeBSD.org>2005-02-19 11:44:57 +0000
commit66dfd6396149e353342cd31080e6b88469aec335 (patch)
treed9295850a39808606f8fe29612e510d2f3b4ef1a
parent480b39e8f236038a1603ca2d67104be32bf2b696 (diff)
downloadFreeBSD-src-66dfd6396149e353342cd31080e6b88469aec335.zip
FreeBSD-src-66dfd6396149e353342cd31080e6b88469aec335.tar.gz
Try to unbreak the vnode locking around vop_reclaim() (based mostly on
patch from kan@). Pull bufobj_invalbuf() out of vinvalbuf() and make g_vfs call it on close. This is not yet a generally safe function, but for this very specific use it is safe. This solves the problem with buffers not being flushed by unmount or after failed mount attempts.
-rw-r--r--sys/geom/geom_vfs.c4
-rw-r--r--sys/kern/vfs_subr.c66
-rw-r--r--sys/nfsclient/nfs_vnops.c2
-rw-r--r--sys/sys/bufobj.h1
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c2
-rw-r--r--sys/ufs/ufs/ufs_inode.c2
-rw-r--r--sys/vm/vnode_pager.c2
7 files changed, 40 insertions, 39 deletions
diff --git a/sys/geom/geom_vfs.c b/sys/geom/geom_vfs.c
index c875897..d8f6c1d 100644
--- a/sys/geom/geom_vfs.c
+++ b/sys/geom/geom_vfs.c
@@ -153,6 +153,7 @@ g_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr
bo->bo_ops = g_vfs_bufops;
bo->bo_private = cp;
bo->bo_bsize = pp->sectorsize;
+ gp->softc = bo;
return (error);
}
@@ -161,9 +162,12 @@ void
g_vfs_close(struct g_consumer *cp, struct thread *td)
{
struct g_geom *gp;
+ struct bufobj *bo;
g_topology_assert();
gp = cp->geom;
+ bo = gp->softc;
+ bufobj_invalbuf(bo, V_SAVE, td, 0, 0);
g_wither_geom_close(gp, ENXIO);
}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 7c83674..d72227a 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -84,7 +84,7 @@ static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
static void delmntque(struct vnode *vp);
static void insmntque(struct vnode *vp, struct mount *mp);
static void vlruvp(struct vnode *vp);
-static int flushbuflist(struct bufv *bufv, int flags, struct vnode *vp,
+static int flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo,
int slpflag, int slptimeo);
static void syncer_shutdown(void *arg, int howto);
static int vtryrecycle(struct vnode *vp);
@@ -927,22 +927,14 @@ insmntque(struct vnode *vp, struct mount *mp)
}
/*
- * Flush out and invalidate all buffers associated with a vnode.
+ * Flush out and invalidate all buffers associated with a bufobj
* Called with the underlying object locked.
*/
int
-vinvalbuf(vp, flags, td, slpflag, slptimeo)
- struct vnode *vp;
- int flags;
- struct thread *td;
- int slpflag, slptimeo;
+bufobj_invalbuf(struct bufobj *bo, int flags, struct thread *td, int slpflag, int slptimeo)
{
int error;
- struct bufobj *bo;
-
- ASSERT_VOP_LOCKED(vp, "vinvalbuf");
- bo = &vp->v_bufobj;
BO_LOCK(bo);
if (flags & V_SAVE) {
error = bufobj_wwait(bo, slpflag, slptimeo);
@@ -970,10 +962,10 @@ vinvalbuf(vp, flags, td, slpflag, slptimeo)
*/
do {
error = flushbuflist(&bo->bo_clean,
- flags, vp, slpflag, slptimeo);
+ flags, bo, slpflag, slptimeo);
if (error == 0)
error = flushbuflist(&bo->bo_dirty,
- flags, vp, slpflag, slptimeo);
+ flags, bo, slpflag, slptimeo);
if (error != 0 && error != EAGAIN) {
BO_UNLOCK(bo);
return (error);
@@ -990,7 +982,7 @@ vinvalbuf(vp, flags, td, slpflag, slptimeo)
BO_UNLOCK(bo);
if (bo->bo_object != NULL) {
VM_OBJECT_LOCK(bo->bo_object);
- vm_object_pip_wait(bo->bo_object, "vnvlbx");
+ vm_object_pip_wait(bo->bo_object, "bovlbx");
VM_OBJECT_UNLOCK(bo->bo_object);
}
BO_LOCK(bo);
@@ -1018,21 +1010,31 @@ vinvalbuf(vp, flags, td, slpflag, slptimeo)
}
/*
+ * Flush out and invalidate all buffers associated with a vnode.
+ * Called with the underlying object locked.
+ */
+int
+vinvalbuf(struct vnode *vp, int flags, struct thread *td, int slpflag, int slptimeo)
+{
+
+ ASSERT_VOP_LOCKED(vp, "vinvalbuf");
+ return (bufobj_invalbuf(&vp->v_bufobj, flags, td, slpflag, slptimeo));
+}
+
+/*
* Flush out buffers on the specified list.
*
*/
static int
-flushbuflist(bufv, flags, vp, slpflag, slptimeo)
+flushbuflist(bufv, flags, bo, slpflag, slptimeo)
struct bufv *bufv;
int flags;
- struct vnode *vp;
+ struct bufobj *bo;
int slpflag, slptimeo;
{
struct buf *bp, *nbp;
int retval, error;
- struct bufobj *bo;
- bo = &vp->v_bufobj;
ASSERT_BO_LOCKED(bo);
retval = 0;
@@ -1049,31 +1051,23 @@ flushbuflist(bufv, flags, vp, slpflag, slptimeo)
BO_LOCK(bo);
return (error != ENOLCK ? error : EAGAIN);
}
+ if (bp->b_bufobj != bo) { /* XXX: necessary ? */
+ BO_LOCK(bo);
+ return (EAGAIN);
+ }
/*
* XXX Since there are no node locks for NFS, I
* believe there is a slight chance that a delayed
* write will occur while sleeping just above, so
- * check for it. Note that vfs_bio_awrite expects
- * buffers to reside on a queue, while bwrite and
- * brelse do not.
+ * check for it.
*/
if (((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) &&
- (flags & V_SAVE)) {
-
- if (bp->b_vp == vp) {
- if (bp->b_flags & B_CLUSTEROK) {
- vfs_bio_awrite(bp);
- } else {
- bremfree(bp);
- bp->b_flags |= B_ASYNC;
- bwrite(bp);
- }
- } else {
- bremfree(bp);
- (void) bwrite(bp);
- }
+ (flags & V_SAVE)) {
+ bremfree(bp);
+ bp->b_flags |= B_ASYNC;
+ bwrite(bp);
BO_LOCK(bo);
- return (EAGAIN);
+ return (EAGAIN); /* XXX: why not loop ? */
}
bremfree(bp);
bp->b_flags |= (B_INVAL | B_NOCACHE | B_RELBUF);
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 5a90982..1c41c93 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -538,7 +538,9 @@ nfs_close(struct vop_close_args *ap)
error = nfs_flush(vp, MNT_WAIT, ap->a_td, cm);
/* np->n_flag &= ~NMODIFIED; */
} else {
+ VOP_LOCK(vp, LK_EXCLUSIVE, curthread);
error = nfs_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
+ VOP_UNLOCK(vp, 0, curthread);
}
}
/*
diff --git a/sys/sys/bufobj.h b/sys/sys/bufobj.h
index 7b0243e..caad00f 100644
--- a/sys/sys/bufobj.h
+++ b/sys/sys/bufobj.h
@@ -125,6 +125,7 @@ struct bufobj {
void bufobj_wdrop(struct bufobj *bo);
void bufobj_wref(struct bufobj *bo);
+int bufobj_invalbuf(struct bufobj *bo, int flags, struct thread *td, int slpflag, int slptimeo);
int bufobj_wwait(struct bufobj *bo, int slpflag, int timeo);
int bufsync(struct bufobj *bo, int waitfor, struct thread *td);
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 0499224..6635e2b 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -794,7 +794,6 @@ ffs_mountfs(devvp, mp, td)
out:
if (bp)
brelse(bp);
- vinvalbuf(devvp, V_SAVE, td, 0, 0);
if (cp != NULL) {
DROP_GIANT();
g_topology_lock();
@@ -956,7 +955,6 @@ ffs_unmount(mp, mntflags, td)
return (error);
}
}
- vinvalbuf(ump->um_devvp, V_SAVE, td, 0, 0);
DROP_GIANT();
g_topology_lock();
g_vfs_close(ump->um_cp, td);
diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
index 7db044c..4cebcd2 100644
--- a/sys/ufs/ufs/ufs_inode.c
+++ b/sys/ufs/ufs/ufs_inode.c
@@ -173,12 +173,12 @@ ufs_reclaim(ap)
}
}
#endif
+ vnode_destroy_vobject(vp);
#ifdef UFS_DIRHASH
if (ip->i_dirhash != NULL)
ufsdirhash_free(ip);
#endif
UFS_IFREE(ump, ip);
vp->v_data = 0;
- vnode_destroy_vobject(vp);
return (0);
}
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 0f9c3eb..af483ed 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -158,6 +158,7 @@ vnode_destroy_vobject(struct vnode *vp)
obj = vp->v_object;
if (obj == NULL)
return;
+ VOP_LOCK(vp, LK_EXCLUSIVE, curthread);
vp->v_object = NULL;
VM_OBJECT_LOCK(obj);
if (obj->ref_count == 0) {
@@ -180,6 +181,7 @@ vnode_destroy_vobject(struct vnode *vp)
vm_pager_deallocate(obj);
VM_OBJECT_UNLOCK(obj);
}
+ VOP_UNLOCK(vp, 0, curthread);
}
OpenPOWER on IntegriCloud