Move handling of B_NEEDCOMMIT buffers to nfs_doio, so that bawrite() calls

for them are actually done asynchronously. Idea taken from FreeBSD.

Do away with nfs_writebp completely, it's not needed anymore.

Keep an eye on the range of a file that needs to be committed, and
do it in heaps.
This commit is contained in:
fvdl 2000-09-19 22:11:47 +00:00
parent 7f432c74ab
commit 899fb781e0
1 changed files with 87 additions and 19 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_bio.c,v 1.51 2000/09/19 17:04:50 bjh21 Exp $ */
/* $NetBSD: nfs_bio.c,v 1.52 2000/09/19 22:11:47 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -731,7 +731,15 @@ again:
* Since this block is being modified, it must be written
* again and not just committed.
*/
if (NFS_ISV3(vp)) {
lockmgr(&np->n_commitlock, LK_EXCLUSIVE, NULL);
if (bp->b_flags & B_NEEDCOMMIT) {
bp->b_flags &= ~B_NEEDCOMMIT;
nfs_del_tobecommitted_range(vp, bp);
}
nfs_del_committed_range(vp, bp);
lockmgr(&np->n_commitlock, LK_RELEASE, NULL);
}
/*
* If the lease is non-cachable or IO_SYNC do bwrite().
@ -749,8 +757,7 @@ again:
} else if ((n + on) == biosize &&
(nmp->nm_flag & NFSMNT_NQNFS) == 0) {
bp->b_proc = (struct proc *)0;
bp->b_flags |= B_ASYNC;
(void)nfs_writebp(bp, 0);
bawrite(bp);
} else {
bdwrite(bp);
}
@ -962,9 +969,12 @@ nfs_doio(bp, cr, p)
struct vnode *vp;
struct nfsnode *np;
struct nfsmount *nmp;
int error = 0, diff, len, iomode, must_commit = 0, s;
int error = 0, diff, len, iomode, must_commit = 0, s, retv = 0;
int pushedrange;
unsigned cnt;
struct uio uio;
struct iovec io;
off_t off;
vp = bp->b_vp;
np = VTONFS(vp);
@ -1071,6 +1081,61 @@ nfs_doio(bp, cr, p)
bp->b_error = error;
}
} else {
/*
* If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
* an actual write will have to be scheduled.
*/
if (bp->b_flags & B_NEEDCOMMIT) {
/*
* If the buffer is in the range that we already committed,
* there's nothing to do.
*
* If it's in the range that we need to commit, push the
* whole range at once. Else only push the buffer. In
* both these cases, acquire the commit lock to avoid
* other processes modifying the range. Normally the
* vnode lock should have handled this, but there are
* no proper vnode locks for NFS yet (XXX).
*/
lockmgr(&np->n_commitlock, LK_EXCLUSIVE, NULL);
if (!(bp->b_flags & B_NEEDCOMMIT)) {
lockmgr(&np->n_commitlock, LK_RELEASE, NULL);
goto dowrite;
}
if (!nfs_in_committed_range(vp, bp)) {
if (nfs_in_tobecommitted_range(vp, bp)) {
pushedrange = 1;
off = np->n_pushlo;
/* XXX will be too big if > 2G buffer cache */
cnt = np->n_pushhi - np->n_pushlo;
} else {
pushedrange = 0;
off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE;
cnt = bp->b_dirtyend;
}
bp->b_flags |= B_WRITEINPROG;
retv = nfs_commit(bp->b_vp, off, cnt,
bp->b_wcred, bp->b_proc);
bp->b_flags &= ~B_WRITEINPROG;
if (retv == 0) {
if (pushedrange) {
nfs_merge_commit_ranges(vp);
}
else
nfs_add_committed_range(vp, bp);
}
}
lockmgr(&np->n_commitlock, LK_RELEASE, NULL);
if (!retv) {
bp->b_resid = bp->b_dirtyoff = bp->b_dirtyend = 0;
bp->b_flags &= ~B_NEEDCOMMIT;
biodone(bp);
return (0);
} else if (retv == NFSERR_STALEWRITEVERF)
nfs_clearcommit(bp->b_vp->v_mount);
}
dowrite:
io.iov_len = uiop->uio_resid = bp->b_dirtyend
- bp->b_dirtyoff;
uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE
@ -1082,18 +1147,23 @@ nfs_doio(bp, cr, p)
iomode = NFSV3WRITE_UNSTABLE;
else
iomode = NFSV3WRITE_FILESYNC;
bp->b_flags |= B_WRITEINPROG;
#ifdef fvdl_debug
printf("nfs_doio(%p): bp %p doff %d dend %d\n",
vp, bp, bp->b_dirtyoff, bp->b_dirtyend);
#endif
error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit);
s = splbio();
if (!error && iomode == NFSV3WRITE_UNSTABLE)
if (!error && iomode == NFSV3WRITE_UNSTABLE) {
bp->b_flags |= B_NEEDCOMMIT;
else
lockmgr(&np->n_commitlock, LK_EXCLUSIVE, NULL);
nfs_add_tobecommitted_range(vp, bp);
lockmgr(&np->n_commitlock, LK_RELEASE, NULL);
} else if (!error && bp->b_flags & B_NEEDCOMMIT) {
bp->b_flags &= ~B_NEEDCOMMIT;
bp->b_flags &= ~B_WRITEINPROG;
lockmgr(&np->n_commitlock, LK_EXCLUSIVE, NULL);
nfs_del_committed_range(vp, bp);
lockmgr(&np->n_commitlock, LK_RELEASE, NULL);
}
/* XXX the use of NOCACHE is a hack */
bp->b_flags &= ~(B_WRITEINPROG|B_NOCACHE);
/*
* For an interrupted write, the buffer is still valid and the
@ -1109,15 +1179,13 @@ nfs_doio(bp, cr, p)
*/
if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
bp->b_flags |= B_DELWRI;
/*
* Since for the B_ASYNC case, nfs_bwrite() has reassigned the
* buffer to the clean list, we have to reassign it back to the
* dirty one. Ugh.
* A B_ASYNC block still needs to be committed, so put
* it back on the dirty list.
*/
if (bp->b_flags & B_ASYNC) {
if (bp->b_flags & B_ASYNC)
reassignbuf(bp, vp);
} else if (error)
else if (error)
bp->b_flags |= B_EINTR;
} else {
if (error) {