summaryrefslogtreecommitdiffstats
path: root/sys/nfs4client
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2008-03-22 09:15:16 +0000
committerjeff <jeff@FreeBSD.org>2008-03-22 09:15:16 +0000
commita9d123c3ab34baa9fe2c8c25bd9acfbfb31b381e (patch)
tree5fedc50643363d96cefce7e3cd6edbdbf2d7fb2b /sys/nfs4client
parentb283b3e59a3e18ec4e7cf225a3a9922139733a73 (diff)
downloadFreeBSD-src-a9d123c3ab34baa9fe2c8c25bd9acfbfb31b381e.zip
FreeBSD-src-a9d123c3ab34baa9fe2c8c25bd9acfbfb31b381e.tar.gz
- Complete part of the unfinished bufobj work by consistently using
BO_LOCK/UNLOCK/MTX when manipulating the bufobj. - Create a new lock in the bufobj to lock bufobj fields independently. This leaves the vnode interlock as an 'identity' lock while the bufobj is an io lock. The bufobj lock is ordered before the vnode interlock and also before the mnt ilock. - Exploit this new lock order to simplify softdep_check_suspend(). - A few sync related functions are marked with a new XXX to note that we may not properly interlock against a non-zero bv_cnt when attempting to sync all vnodes on a mountlist. I do not believe this race is important. If I'm wrong this will make these locations easier to find. Reviewed by: kib (earlier diff) Tested by: kris, pho (earlier diff)
Diffstat (limited to 'sys/nfs4client')
-rw-r--r--sys/nfs4client/nfs4_vfsops.c1
-rw-r--r--sys/nfs4client/nfs4_vnops.c52
2 files changed, 24 insertions, 29 deletions
diff --git a/sys/nfs4client/nfs4_vfsops.c b/sys/nfs4client/nfs4_vfsops.c
index e587d53..6de47a9 100644
--- a/sys/nfs4client/nfs4_vfsops.c
+++ b/sys/nfs4client/nfs4_vfsops.c
@@ -749,6 +749,7 @@ loop:
MNT_VNODE_FOREACH(vp, mp, mvp) {
VI_LOCK(vp);
MNT_IUNLOCK(mp);
+ /* XXX racy bv_cnt check. */
if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
waitfor == MNT_LAZY) {
VI_UNLOCK(vp);
diff --git a/sys/nfs4client/nfs4_vnops.c b/sys/nfs4client/nfs4_vnops.c
index 7a6db66..0d6ad9a 100644
--- a/sys/nfs4client/nfs4_vnops.c
+++ b/sys/nfs4client/nfs4_vnops.c
@@ -2486,11 +2486,12 @@ nfs4_flush(struct vnode *vp, int waitfor, struct thread *td,
int commit)
{
struct nfsnode *np = VTONFS(vp);
+ struct bufobj *bo;
struct buf *bp;
int i;
struct buf *nbp;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
- int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
+ int error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
int passone = 1;
u_quad_t off, endoff, toff;
struct ucred* wcred = NULL;
@@ -2500,6 +2501,7 @@ nfs4_flush(struct vnode *vp, int waitfor, struct thread *td,
#endif
struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
int bvecsize = 0, bveccount;
+ bo = &vp->v_bufobj;
if (nmp->nm_flag & NFSMNT_INT)
slpflag = PCATCH;
@@ -2517,15 +2519,14 @@ again:
endoff = 0;
bvecpos = 0;
if (NFS_ISV3(vp) && commit) {
- s = splbio();
if (bvec != NULL && bvec != bvec_on_stack)
free(bvec, M_TEMP);
/*
* Count up how many buffers waiting for a commit.
*/
bveccount = 0;
- VI_LOCK(vp);
- TAILQ_FOREACH_SAFE(bp, &vp->v_bufobj.bo_dirty.bv_hd, b_bobufs, nbp) {
+ BO_LOCK(bo);
+ TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
if (!BUF_ISLOCKED(bp) &&
(bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
== (B_DELWRI | B_NEEDCOMMIT))
@@ -2542,11 +2543,11 @@ again:
* Release the vnode interlock to avoid a lock
* order reversal.
*/
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
bvec = (struct buf **)
malloc(bveccount * sizeof(struct buf *),
M_TEMP, M_NOWAIT);
- VI_LOCK(vp);
+ BO_LOCK(bo);
if (bvec == NULL) {
bvec = bvec_on_stack;
bvecsize = NFS_COMMITBVECSIZ;
@@ -2556,7 +2557,7 @@ again:
bvec = bvec_on_stack;
bvecsize = NFS_COMMITBVECSIZ;
}
- TAILQ_FOREACH_SAFE(bp, &vp->v_bufobj.bo_dirty.bv_hd, b_bobufs, nbp) {
+ TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
if (bvecpos >= bvecsize)
break;
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
@@ -2569,7 +2570,7 @@ again:
nbp = TAILQ_NEXT(bp, b_bobufs);
continue;
}
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
bremfree(bp);
/*
* Work out if all buffers are using the same cred
@@ -2588,7 +2589,7 @@ again:
wcred = NOCRED;
vfs_busy_pages(bp, 1);
- VI_LOCK(vp);
+ BO_LOCK(bo);
/*
* bp is protected by being locked, but nbp is not
* and vfs_busy_pages() may sleep. We have to
@@ -2612,8 +2613,7 @@ again:
if (toff > endoff)
endoff = toff;
}
- splx(s);
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
}
if (bvecpos > 0) {
/*
@@ -2665,14 +2665,12 @@ again:
* specific. We should probably move that
* into bundirty(). XXX
*/
- s = splbio();
- bufobj_wref(&vp->v_bufobj);
+ bufobj_wref(bo);
bp->b_flags |= B_ASYNC;
bundirty(bp);
bp->b_flags &= ~B_DONE;
bp->b_ioflags &= ~BIO_ERROR;
bp->b_dirtyoff = bp->b_dirtyend = 0;
- splx(s);
bufdone(bp);
}
}
@@ -2682,17 +2680,15 @@ again:
* Start/do any write(s) that are required.
*/
loop:
- s = splbio();
- VI_LOCK(vp);
- TAILQ_FOREACH_SAFE(bp, &vp->v_bufobj.bo_dirty.bv_hd, b_bobufs, nbp) {
+ BO_LOCK(bo);
+ TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
if (waitfor != MNT_WAIT || passone)
continue;
error = BUF_TIMELOCK(bp,
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
- VI_MTX(vp), "nfsfsync", slpflag, slptimeo);
- splx(s);
+ BO_MTX(bo), "nfsfsync", slpflag, slptimeo);
if (error == 0)
panic("nfs4_fsync: inconsistent lock");
if (error == ENOLCK)
@@ -2713,27 +2709,25 @@ loop:
BUF_UNLOCK(bp);
continue;
}
- VI_UNLOCK(vp);
+ BO_LOCK(bo);
bremfree(bp);
if (passone || !commit)
bp->b_flags |= B_ASYNC;
else
bp->b_flags |= B_ASYNC;
- splx(s);
bwrite(bp);
goto loop;
}
- splx(s);
if (passone) {
passone = 0;
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
goto again;
}
if (waitfor == MNT_WAIT) {
- while (vp->v_bufobj.bo_numoutput) {
- error = bufobj_wwait(&vp->v_bufobj, slpflag, slptimeo);
+ while (bo->bo_numoutput) {
+ error = bufobj_wwait(bo, slpflag, slptimeo);
if (error) {
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
if (nfs4_sigintr(nmp, NULL, td)) {
error = EINTR;
goto done;
@@ -2742,15 +2736,15 @@ loop:
slpflag = 0;
slptimeo = 2 * hz;
}
- VI_LOCK(vp);
+ BO_LOCK(bo);
}
}
if (vp->v_bufobj.bo_dirty.bv_cnt > 0 && commit) {
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
goto loop;
}
}
- VI_UNLOCK(vp);
+ BO_UNLOCK(bo);
if (np->n_flag & NWRITEERR) {
error = np->n_error;
np->n_flag &= ~NWRITEERR;
OpenPOWER on IntegriCloud