diff options
-rw-r--r-- | sys/kern/vfs_conf.c | 3 | ||||
-rw-r--r-- | sys/nfs/nfs_bio.c | 28 | ||||
-rw-r--r-- | sys/nfs/nfs_node.c | 4 | ||||
-rw-r--r-- | sys/nfs/nfs_subs.c | 168 | ||||
-rw-r--r-- | sys/nfs/nfs_var.h | 9 | ||||
-rw-r--r-- | sys/nfs/nfs_vnops.c | 51 | ||||
-rw-r--r-- | sys/nfs/nfsnode.h | 17 |
7 files changed, 264 insertions, 16 deletions
diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index 7ed2a32012b..895452bbde8 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_conf.c,v 1.23 2004/04/13 00:15:28 tedu Exp $ */ +/* $OpenBSD: vfs_conf.c,v 1.24 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: vfs_conf.c,v 1.21.4.1 1995/11/01 00:06:26 jtc Exp $ */ /* @@ -60,6 +60,7 @@ #endif #ifdef NFSCLIENT +#include <sys/rwlock.h> /* XXX*/ #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfs/nfsnode.h> diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c index 53caf23abcf..3630b55ab33 100644 --- a/sys/nfs/nfs_bio.c +++ b/sys/nfs/nfs_bio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_bio.c,v 1.39 2004/07/21 17:30:55 marius Exp $ */ +/* $OpenBSD: nfs_bio.c,v 1.40 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: nfs_bio.c,v 1.25.4.2 1996/07/08 20:47:04 jtc Exp $ */ /* @@ -35,7 +35,6 @@ * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 */ - #include <sys/param.h> #include <sys/systm.h> #include <sys/resourcevar.h> @@ -415,7 +414,17 @@ again: * Since this block is being modified, it must be written * again and not just committed. */ - bp->b_flags &= ~B_NEEDCOMMIT; + + if (NFS_ISV3(vp)) { + rw_enter_write(&np->n_commitlock); + if (bp->b_flags & B_NEEDCOMMIT) { + bp->b_flags &= ~B_NEEDCOMMIT; + nfs_del_tobecommitted_range(vp, bp); + } + nfs_del_committed_range(vp, bp); + rw_exit_write(&np->n_commitlock); + } else + bp->b_flags &= ~B_NEEDCOMMIT; /* * If the lease is non-cachable or IO_SYNC do bwrite(). @@ -670,7 +679,7 @@ nfs_doio(bp, p) error = nfs_readlinkrpc(vp, uiop, curproc->p_ucred); break; default: - printf("nfs_doio: type %x unexpected\n",vp->v_type); + printf("nfs_doio: type %x unexpected\n", vp->v_type); break; }; if (error) { @@ -695,10 +704,17 @@ nfs_doio(bp, p) vp, bp, bp->b_dirtyoff, bp->b_dirtyend); #endif error = nfs_writerpc(vp, uiop, &iomode, &must_commit); - if (!error && iomode == NFSV3WRITE_UNSTABLE) + + rw_enter_write(&np->n_commitlock); + if (!error && iomode == NFSV3WRITE_UNSTABLE) { bp->b_flags |= B_NEEDCOMMIT; - else + nfs_add_tobecommitted_range(vp, bp); + } else { bp->b_flags &= ~B_NEEDCOMMIT; + nfs_del_committed_range(vp, bp); + } + rw_exit_write(&np->n_commitlock); + bp->b_flags &= ~B_WRITEINPROG; /* diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c index 4e8ded5cb6e..026ec6149c1 100644 --- a/sys/nfs/nfs_node.c +++ b/sys/nfs/nfs_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_node.c,v 1.26 2003/06/02 23:28:19 millert Exp $ */ +/* $OpenBSD: nfs_node.c,v 1.27 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */ /* @@ -128,6 +128,8 @@ loop: vp->v_data = np; np->n_vnode = vp; + rw_init(&np->n_commitlock); + /* * Are we getting the root? If so, make sure the vnode flags * are correct diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c index 6cd3d3290c7..a93418d73fa 100644 --- a/sys/nfs/nfs_subs.c +++ b/sys/nfs/nfs_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_subs.c,v 1.49 2004/08/03 06:58:40 miod Exp $ */ +/* $OpenBSD: nfs_subs.c,v 1.50 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */ /* @@ -1744,6 +1744,172 @@ loop: splx(s); } +void +nfs_merge_commit_ranges(vp) + struct vnode *vp; +{ + struct nfsnode *np = VTONFS(vp); + + if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) { + np->n_pushedlo = np->n_pushlo; + np->n_pushedhi = np->n_pushhi; + np->n_commitflags |= NFS_COMMIT_PUSHED_VALID; + } else { + if (np->n_pushlo < np->n_pushedlo) + np->n_pushedlo = np->n_pushlo; + if (np->n_pushhi > np->n_pushedhi) + np->n_pushedhi = np->n_pushhi; + } + + np->n_pushlo = np->n_pushhi = 0; + np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID; +} + +int +nfs_in_committed_range(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + struct nfsnode *np = VTONFS(vp); + off_t lo, hi; + + if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) + return 0; + lo = (off_t)bp->b_blkno * DEV_BSIZE; + hi = lo + bp->b_dirtyend; + + return (lo >= np->n_pushedlo && hi <= np->n_pushedhi); +} + +int +nfs_in_tobecommitted_range(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + struct nfsnode *np = VTONFS(vp); + off_t lo, hi; + + if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) + return 0; + lo = (off_t)bp->b_blkno * DEV_BSIZE; + hi = lo + bp->b_dirtyend; + + return (lo >= np->n_pushlo && hi <= np->n_pushhi); +} + +void +nfs_add_committed_range(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + struct nfsnode *np = VTONFS(vp); + off_t lo, hi; + + lo = (off_t)bp->b_blkno * DEV_BSIZE; + hi = lo + bp->b_dirtyend; + + if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) { + np->n_pushedlo = lo; + np->n_pushedhi = hi; + np->n_commitflags |= NFS_COMMIT_PUSHED_VALID; + } else { + if (hi > np->n_pushedhi) + np->n_pushedhi = hi; + if (lo < np->n_pushedlo) + np->n_pushedlo = lo; + } +} + +void +nfs_del_committed_range(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + struct nfsnode *np = VTONFS(vp); + off_t lo, hi; + + if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) + return; + + lo = (off_t)bp->b_blkno * DEV_BSIZE; + hi = lo + bp->b_dirtyend; + + if (lo > np->n_pushedhi || hi < np->n_pushedlo) + return; + if (lo <= np->n_pushedlo) + np->n_pushedlo = hi; + else if (hi >= np->n_pushedhi) + np->n_pushedhi = lo; + else { + /* + * XXX There's only one range. If the deleted range + * is in the middle, pick the largest of the + * contiguous ranges that it leaves. + */ + if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi)) + np->n_pushedhi = lo; + else + np->n_pushedlo = hi; + } +} + +void +nfs_add_tobecommitted_range(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + struct nfsnode *np = VTONFS(vp); + off_t lo, hi; + + lo = (off_t)bp->b_blkno * DEV_BSIZE; + hi = lo + bp->b_dirtyend; + + if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) { + np->n_pushlo = lo; + np->n_pushhi = hi; + np->n_commitflags |= NFS_COMMIT_PUSH_VALID; + } else { + if (lo < np->n_pushlo) + np->n_pushlo = lo; + if (hi > np->n_pushhi) + np->n_pushhi = hi; + } +} + +void +nfs_del_tobecommitted_range(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + struct nfsnode *np = VTONFS(vp); + off_t lo, hi; + + if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) + return; + + lo = (off_t)bp->b_blkno * DEV_BSIZE; + hi = lo + bp->b_dirtyend; + + if (lo > np->n_pushhi || hi < np->n_pushlo) + return; + + if (lo <= np->n_pushlo) + np->n_pushlo = hi; + else if (hi >= np->n_pushhi) + np->n_pushhi = lo; + else { + /* + * XXX There's only one range. If the deleted range + * is in the middle, pick the largest of the + * contiguous ranges that it leaves. + */ + if ((np->n_pushlo - lo) > (hi - np->n_pushhi)) + np->n_pushhi = lo; + else + np->n_pushlo = hi; + } +} + /* * Map errnos to NFS error numbers. For Version 3 also filter out error * numbers not specified for the associated procedure. diff --git a/sys/nfs/nfs_var.h b/sys/nfs/nfs_var.h index e5a6a45d3b2..fc7bb9d506a 100644 --- a/sys/nfs/nfs_var.h +++ b/sys/nfs/nfs_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_var.h,v 1.22 2004/07/21 17:30:56 marius Exp $ */ +/* $OpenBSD: nfs_var.h,v 1.23 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: nfs_var.h,v 1.3 1996/02/18 11:53:54 fvdl Exp $ */ /* @@ -257,6 +257,13 @@ int nfsrv_fhtovp(fhandle_t *, int, struct vnode **, struct ucred *, struct nfssvc_sock *, struct mbuf *, int *, int); int netaddr_match(int, union nethostaddr *, struct mbuf *); void nfs_clearcommit(struct mount *); +int nfs_in_committed_range(struct vnode *, struct buf *); +int nfs_in_tobecommitted_range(struct vnode *, struct buf *); +void nfs_add_committed_range(struct vnode *, struct buf *); +void nfs_del_committed_range(struct vnode *, struct buf *); +void nfs_add_tobecommitted_range(struct vnode *, struct buf *); +void nfs_del_tobecommitted_range(struct vnode *, struct buf *); +void nfs_merge_commit_ranges(struct vnode *); int nfsrv_errmap(struct nfsrv_descript *, int); void nfsrvw_sort(gid_t *, int); void nfsrv_setcred(struct ucred *, struct ucred *); diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index f1a28db9e48..01ae894082b 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_vnops.c,v 1.62 2004/07/21 17:30:56 marius Exp $ */ +/* $OpenBSD: nfs_vnops.c,v 1.63 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */ /* @@ -2989,11 +2989,17 @@ nfs_writebp(bp, force) int oldflags = bp->b_flags, retv = 1; struct proc *p = curproc; /* XXX */ off_t off; + size_t cnt; int s; + struct vnode *vp; + struct nfsnode *np; if(!(bp->b_flags & B_BUSY)) panic("bwrite: buffer is not busy???"); + vp = bp->b_vp; + np = VTONFS(vp); + #ifdef fvdl_debug printf("nfs_writebp(%x): vp %x voff %d vend %d doff %d dend %d\n", bp, bp->b_vp, bp->b_validoff, bp->b_validend, bp->b_dirtyoff, @@ -3017,10 +3023,45 @@ nfs_writebp(bp, force) */ if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) { off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; - bp->b_flags |= B_WRITEINPROG; - retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff, - bp->b_proc); - bp->b_flags &= ~B_WRITEINPROG; + cnt = bp->b_dirtyend - bp->b_dirtyoff; + + rw_enter_write(&np->n_commitlock); + if (!(bp->b_flags & B_NEEDCOMMIT)) { + rw_exit_write(&np->n_commitlock); + return (0); + } + + /* + * If it's already been commited by somebody else, + * bail. + */ + if (!nfs_in_committed_range(vp, bp)) { + int pushedrange = 0; + /* + * Since we're going to do this, push as much + * as we can. + */ + + if (nfs_in_tobecommitted_range(vp, bp)) { + pushedrange = 1; + off = np->n_pushlo; + cnt = np->n_pushhi - np->n_pushlo; + } + + bp->b_flags |= B_WRITEINPROG; + retv = nfs_commit(bp->b_vp, off, cnt, 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); + } + } else + retv = 0; /* It has already been commited. */ + + rw_exit_write(&np->n_commitlock); if (!retv) { bp->b_dirtyoff = bp->b_dirtyend = 0; bp->b_flags &= ~B_NEEDCOMMIT; diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h index a0d49d6c3cd..ef09b6ff6a1 100644 --- a/sys/nfs/nfsnode.h +++ b/sys/nfs/nfsnode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfsnode.h,v 1.21 2004/04/26 18:57:36 millert Exp $ */ +/* $OpenBSD: nfsnode.h,v 1.22 2004/08/03 17:11:48 marius Exp $ */ /* $NetBSD: nfsnode.h,v 1.16 1996/02/18 11:54:04 fvdl Exp $ */ /* @@ -43,6 +43,8 @@ #include <nfs/nfs.h> #endif +#include <sys/rwlock.h> + /* * Silly rename structure that hangs off the nfsnode until the name * can be removed by nfs_inactive() @@ -115,8 +117,21 @@ struct nfsnode { nfsfh_t n_fh; /* Small File Handle */ struct ucred *n_rcred; struct ucred *n_wcred; + + off_t n_pushedlo; /* 1st blk in commited range */ + off_t n_pushedhi; /* Last block in range */ + off_t n_pushlo; /* 1st block in commit range */ + off_t n_pushhi; /* Last block in range */ + struct rwlock n_commitlock; /* Serialize commits */ + int n_commitflags; }; +/* + * Values for n_commitflags + */ +#define NFS_COMMIT_PUSH_VALID 0x0001 /* push range valid */ +#define NFS_COMMIT_PUSHED_VALID 0x0002 /* pushed range valid */ + #define n_atim n_un1.nf_atim #define n_mtim n_un2.nf_mtim #define n_sillyrename n_un3.nf_silly |