diff options
author | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-06-25 02:15:49 +0000 |
---|---|---|
committer | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-06-25 02:15:49 +0000 |
commit | 35821d4b137b32915ec7997db57bbf82afcf95c9 (patch) | |
tree | d720e6cbf1406328837c164db6eea08de41b71ab /sys/nfs | |
parent | 8f2d3cfc3b4105d59367fc205296b7513725280c (diff) |
Get rid of old directory caching scheme which caused persistent duplicates.
Still not correct for NFSv3 but that's hard.
Diffstat (limited to 'sys/nfs')
-rw-r--r-- | sys/nfs/nfs_bio.c | 106 | ||||
-rw-r--r-- | sys/nfs/nfs_nqlease.c | 7 | ||||
-rw-r--r-- | sys/nfs/nfs_subs.c | 84 | ||||
-rw-r--r-- | sys/nfs/nfs_var.h | 8 | ||||
-rw-r--r-- | sys/nfs/nfs_vnops.c | 327 | ||||
-rw-r--r-- | sys/nfs/nfsnode.h | 4 |
6 files changed, 217 insertions, 319 deletions
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c index 950fe138235..9ffdac49d79 100644 --- a/sys/nfs/nfs_bio.c +++ b/sys/nfs/nfs_bio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_bio.c,v 1.18 2001/02/23 14:52:50 csapuntz Exp $ */ +/* $OpenBSD: nfs_bio.c,v 1.19 2001/06/25 02:15:46 csapuntz Exp $ */ /* $NetBSD: nfs_bio.c,v 1.25.4.2 1996/07/08 20:47:04 jtc Exp $ */ /* @@ -77,7 +77,7 @@ nfs_bioread(vp, uio, ioflag, cred) struct ucred *cred; { register struct nfsnode *np = VTONFS(vp); - register int biosize, diff, i; + register int biosize, diff; struct buf *bp = NULL, *rabp; struct vattr vattr; struct proc *p; @@ -117,14 +117,6 @@ nfs_bioread(vp, uio, ioflag, cred) */ if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 && vp->v_type != VLNK) { if (np->n_flag & NMODIFIED) { - if (vp->v_type != VREG) { - if (vp->v_type != VDIR) - panic("nfs: bioread, not dir"); - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); - if (error) - return (error); - } np->n_attrstamp = 0; error = VOP_GETATTR(vp, &vattr, cred, p); if (error) @@ -135,8 +127,6 @@ nfs_bioread(vp, uio, ioflag, cred) if (error) return (error); if (np->n_mtime != vattr.va_mtime.tv_sec) { - if (vp->v_type == VDIR) - nfs_invaldir(vp); error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); if (error) return (error); @@ -157,20 +147,12 @@ nfs_bioread(vp, uio, ioflag, cred) if (error) return (error); if (np->n_lrev != np->n_brev || - (np->n_flag & NQNFSNONCACHE) || - ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) { - if (vp->v_type == VDIR) - nfs_invaldir(vp); + (np->n_flag & NQNFSNONCACHE)) { error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); if (error) return (error); np->n_brev = np->n_lrev; } - } else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) { - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); - if (error) - return (error); } } /* @@ -183,8 +165,6 @@ nfs_bioread(vp, uio, ioflag, cred) return (nfs_readrpc(vp, uio, cred)); case VLNK: return (nfs_readlinkrpc(vp, uio, cred)); - case VDIR: - break; default: printf(" NQNFSNONCACHE: type %x unexpected\n", vp->v_type); @@ -292,71 +272,6 @@ again: got_buf = 1; on = 0; break; - case VDIR: - if (uio->uio_resid < NFS_READDIRBLKSIZ) - return (0); - nfsstats.biocache_readdirs++; - lbn = uio->uio_offset / NFS_DIRBLKSIZ; - on = uio->uio_offset & (NFS_DIRBLKSIZ - 1); - bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, p); - if (!bp) - return (EINTR); - if ((bp->b_flags & B_DONE) == 0) { - bp->b_flags |= B_READ; - error = nfs_doio(bp, cred, p); - if (error) { - brelse(bp); - while (error == NFSERR_BAD_COOKIE) { - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, 0, cred, p, 1); - /* - * Yuck! The directory has been modified on the - * server. The only way to get the block is by - * reading from the beginning to get all the - * offset cookies. - */ - for (i = 0; i <= lbn && !error; i++) { - bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p); - if (!bp) - return (EINTR); - if ((bp->b_flags & B_DONE) == 0) { - bp->b_flags |= B_READ; - error = nfs_doio(bp, cred, p); - if (error) - brelse(bp); - } - } - } - if (error) - return (error); - } - } - - /* - * If not eof and read aheads are enabled, start one. - * (You need the current block first, so that you have the - * directory offset cookie of the next block.) - */ - if (nfs_numasync > 0 && nmp->nm_readahead > 0 && - (np->n_direofoffset == 0 || - (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) && - !(np->n_flag & NQNFSNONCACHE) && - !incore(vp, lbn + 1)) { - rabp = nfs_getcacheblk(vp, lbn + 1, NFS_DIRBLKSIZ, p); - if (rabp) { - if ((rabp->b_flags & (B_DONE | B_DELWRI)) == 0) { - rabp->b_flags |= (B_READ | B_ASYNC); - if (nfs_asyncio(rabp, cred)) { - rabp->b_flags |= B_INVAL; - brelse(rabp); - } - } else - brelse(rabp); - } - } - n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on); - got_buf = 1; - break; default: printf(" nfsbioread: type %x unexpected\n",vp->v_type); break; @@ -373,10 +288,6 @@ again: case VLNK: n = 0; break; - case VDIR: - if (np->n_flag & NQNFSNONCACHE) - bp->b_flags |= B_INVAL; - break; default: printf(" nfsbioread: type %x unexpected\n",vp->v_type); } @@ -851,17 +762,6 @@ nfs_doio(bp, cr, p) nfsstats.readlink_bios++; error = nfs_readlinkrpc(vp, uiop, cr); break; - case VDIR: - nfsstats.readdir_bios++; - uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ; - if (nmp->nm_flag & NFSMNT_RDIRPLUS) { - error = nfs_readdirplusrpc(vp, uiop, cr); - if (error == NFSERR_NOTSUPP) - nmp->nm_flag &= ~NFSMNT_RDIRPLUS; - } - if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0) - error = nfs_readdirrpc(vp, uiop, cr); - break; default: printf("nfs_doio: type %x unexpected\n",vp->v_type); break; diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c index 646c8abd523..fca4f72a782 100644 --- a/sys/nfs/nfs_nqlease.c +++ b/sys/nfs/nfs_nqlease.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_nqlease.c,v 1.15 2001/02/24 19:07:11 csapuntz Exp $ */ +/* $OpenBSD: nfs_nqlease.c,v 1.16 2001/06/25 02:15:46 csapuntz Exp $ */ /* $NetBSD: nfs_nqlease.c,v 1.14 1996/02/18 14:06:50 fvdl Exp $ */ /* @@ -1046,8 +1046,9 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p) np->n_timer.cqe_next = 0; if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) { if (np->n_flag & NQNFSEVICTED) { - if (vp->v_type == VDIR) - nfs_invaldir(vp); + if (vp->v_type == VDIR) { + np->n_direofoffset = 0; + } cache_purge(vp); (void) nfs_vinvalbuf(vp, V_SAVE, cred, p, 0); diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c index 5ab8ab8e70c..2d27874e8b9 100644 --- a/sys/nfs/nfs_subs.c +++ b/sys/nfs/nfs_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_subs.c,v 1.29 2000/06/26 22:48:15 art Exp $ */ +/* $OpenBSD: nfs_subs.c,v 1.30 2001/06/25 02:15:47 csapuntz Exp $ */ /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */ /* @@ -1807,88 +1807,6 @@ netaddr_match(family, haddr, nam) return (0); } -static nfsuint64 nfs_nullcookie = {{ 0, 0 }}; -/* - * This function finds the directory cookie that corresponds to the - * logical byte offset given. - */ -nfsuint64 * -nfs_getcookie(np, off, add) - register struct nfsnode *np; - off_t off; - int add; -{ - register struct nfsdmap *dp, *dp2; - register int pos; - - pos = off / NFS_DIRBLKSIZ; - if (pos == 0) { -#ifdef DIAGNOSTIC - if (add) - panic("nfs getcookie add at 0"); -#endif - return (&nfs_nullcookie); - } - pos--; - dp = np->n_cookies.lh_first; - if (!dp) { - if (add) { - MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), - M_NFSDIROFF, M_WAITOK); - dp->ndm_eocookie = 0; - LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); - } else - return ((nfsuint64 *)0); - } - while (pos >= NFSNUMCOOKIES) { - pos -= NFSNUMCOOKIES; - if (dp->ndm_list.le_next) { - if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && - pos >= dp->ndm_eocookie) - return ((nfsuint64 *)0); - dp = dp->ndm_list.le_next; - } else if (add) { - MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), - M_NFSDIROFF, M_WAITOK); - dp2->ndm_eocookie = 0; - LIST_INSERT_AFTER(dp, dp2, ndm_list); - dp = dp2; - } else - return ((nfsuint64 *)0); - } - if (pos >= dp->ndm_eocookie) { - if (add) - dp->ndm_eocookie = pos + 1; - else - return ((nfsuint64 *)0); - } - return (&dp->ndm_cookies[pos]); -} - -/* - * Invalidate cached directory information, except for the actual directory - * blocks (which are invalidated separately). - * Done mainly to avoid the use of stale offset cookies. - */ -void -nfs_invaldir(vp) - register struct vnode *vp; -{ -#ifdef notdef /* XXX */ - register struct nfsnode *np = VTONFS(vp); - -#ifdef DIAGNOSTIC - if (vp->v_type != VDIR) - panic("nfs: invaldir not dir"); -#endif - np->n_direofoffset = 0; - np->n_cookieverf.nfsuquad[0] = 0; - np->n_cookieverf.nfsuquad[1] = 0; - if (np->n_cookies.lh_first) - np->n_cookies.lh_first->ndm_eocookie = 0; -#endif -} - /* * The write verifier has changed (probably due to a server reboot), so all * B_NEEDCOMMIT blocks will have to be written again. Since they are on the diff --git a/sys/nfs/nfs_var.h b/sys/nfs/nfs_var.h index eb8d2f6f830..3e8c5118cfd 100644 --- a/sys/nfs/nfs_var.h +++ b/sys/nfs/nfs_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_var.h,v 1.12 2000/06/30 01:06:02 art Exp $ */ +/* $OpenBSD: nfs_var.h,v 1.13 2001/06/25 02:15:47 csapuntz Exp $ */ /* $NetBSD: nfs_var.h,v 1.3 1996/02/18 11:53:54 fvdl Exp $ */ /* @@ -116,8 +116,8 @@ int nfs_symlink __P((void *)); int nfs_mkdir __P((void *)); int nfs_rmdir __P((void *)); int nfs_readdir __P((void *)); -int nfs_readdirrpc __P((struct vnode *, struct uio *, struct ucred *)); -int nfs_readdirplusrpc __P((struct vnode *, struct uio *, struct ucred *)); +int nfs_readdirrpc(struct vnode *, struct uio *, struct ucred *, int *); +int nfs_readdirplusrpc(struct vnode *, struct uio *, struct ucred *, int *); int nfs_sillyrename __P((struct vnode *, struct vnode *, struct componentname *)); int nfs_lookitup __P((struct vnode *, char *, int, struct ucred *, @@ -289,8 +289,6 @@ void nfsm_srvfattr __P((struct nfsrv_descript *, struct vattr *, int nfsrv_fhtovp __P((fhandle_t *, int, struct vnode **, struct ucred *, struct nfssvc_sock *, struct mbuf *, int *, int)); int netaddr_match __P((int, union nethostaddr *, struct mbuf *)); -nfsuint64 *nfs_getcookie __P((struct nfsnode *, off_t off, int)); -void nfs_invaldir __P((struct vnode *)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); void nfsrvw_sort __P((gid_t *, int)); diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index 563eec090f6..131463b45c2 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_vnops.c,v 1.31 2001/06/23 02:14:26 csapuntz Exp $ */ +/* $OpenBSD: nfs_vnops.c,v 1.32 2001/06/25 02:15:48 csapuntz Exp $ */ /* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */ /* @@ -234,7 +234,6 @@ extern struct nfsstats nfsstats; extern nfstype nfsv3_type[9]; struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; int nfs_numasync = 0; -#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) /* * nfs null call from vfs. @@ -1833,6 +1832,27 @@ nfs_rmdir(v) return (error); } + +/* + * The readdir logic below has a big design bug. It stores the NFS cookie in + * the returned uio->uio_offset but does not store the verifier (it cannot). + * Instead, the code stores the verifier in the nfsnode and applies that + * verifies to all cookies, no matter what verifier was originally with + * the cookie. + * + * From a practical standpoint, this is not a problem since almost all + * NFS servers do not change the validity of cookies across deletes + * and inserts. + */ + +struct nfs_dirent { + u_int32_t cookie[2]; + struct dirent dirent; +}; + +#define NFS_DIRHDSIZ (sizeof (struct nfs_dirent) - (MAXNAMLEN + 1)) +#define NFS_DIRENT_OVERHEAD offsetof(struct nfs_dirent, dirent) + /* * nfs readdir call */ @@ -1845,23 +1865,32 @@ nfs_readdir(v) struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; - u_long *a_cookies; - int a_ncookies; + u_long **a_cookies; + int *a_ncookies; } */ *ap = v; - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - register struct uio *uio = ap->a_uio; - char *base = uio->uio_iov->iov_base; - off_t off = uio->uio_offset; + struct vnode *vp = ap->a_vp; + struct nfsnode *np = VTONFS(vp); + struct uio *uio = ap->a_uio; int tresid, error; struct vattr vattr; + u_long *cookies = NULL; + int ncookies = 0, cnt; + u_int64_t newoff = uio->uio_offset; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); + struct uio readdir_uio; + struct iovec readdir_iovec; + struct proc * p = uio->uio_procp; + int done = 0, eof = 0; + struct ucred *cred = ap->a_cred; + void *data; if (vp->v_type != VDIR) return (EPERM); /* * First, check for hit on the EOF offset cache */ - if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset && + if (np->n_direofoffset != 0 && + uio->uio_offset == np->n_direofoffset && (np->n_flag & NMODIFIED) == 0) { if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { if (NQNFS_CKCACHABLE(vp, ND_READ)) { @@ -1869,7 +1898,8 @@ nfs_readdir(v) *ap->a_eofflag = 1; return (0); } - } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && + } else if ( + VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 && np->n_mtime == vattr.va_mtime.tv_sec) { nfsstats.direofcache_hits++; *ap->a_eofflag = 1; @@ -1877,71 +1907,130 @@ nfs_readdir(v) } } - /* - * Call nfs_bioread() to do the real work. - */ + if (uio->uio_resid < NFS_FABLKSIZE) + return (EINVAL); + tresid = uio->uio_resid; - error = nfs_bioread(vp, uio, 0, ap->a_cred); - if (!error && uio->uio_resid == tresid) { - nfsstats.direofcache_misses++; - *ap->a_eofflag = 1; - return (0); - } + if (uio->uio_rw != UIO_READ) + return (EINVAL); - if (!error && ap->a_cookies) { - struct dirent *dp; - u_long *cookies; - /* XXX - over-estimate - see UFS code for how to do it - right */ - int ncookies = ((caddr_t)uio->uio_iov->iov_base - base) / 12; + if (ap->a_cookies) { + ncookies = uio->uio_resid / 20; MALLOC(cookies, u_long *, sizeof(*cookies) * ncookies, M_TEMP, M_WAITOK); - *ap->a_ncookies = ncookies; - *ap->a_cookies = cookies; + *ap->a_ncookies = ncookies; + *ap->a_cookies = cookies; + } - /* Only the NFS server and emulations use cookies, and they - * load the directory block into system space, so we can - * just look at it directly. - */ - if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) - panic("nfs_readdir: lost in space"); - while (ncookies-- && base < (caddr_t)uio->uio_iov->iov_base) { - dp = (struct dirent *) base; - if (dp->d_reclen == 0) + if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3) + (void)nfs_fsinfo(nmp, vp, cred, p); + + cnt = 5; + + MALLOC(data, void *, NFS_DIRBLKSIZ, M_TEMP, + M_WAITOK); + + do { + struct nfs_dirent *ndp = data; + + readdir_iovec.iov_len = NFS_DIRBLKSIZ; + readdir_iovec.iov_base = data; + readdir_uio.uio_offset = newoff; + readdir_uio.uio_iov = &readdir_iovec; + readdir_uio.uio_iovcnt = 1; + readdir_uio.uio_segflg = UIO_SYSSPACE; + readdir_uio.uio_rw = UIO_READ; + readdir_uio.uio_resid = NFS_DIRBLKSIZ; + + if (nmp->nm_flag & NFSMNT_RDIRPLUS) { + error = nfs_readdirplusrpc(vp, &readdir_uio, cred, + &eof); + if (error == NFSERR_NOTSUPP) + nmp->nm_flag &= ~NFSMNT_RDIRPLUS; + } + if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0) + error = nfs_readdirrpc(vp, &readdir_uio, cred, &eof); + + if (error == NFSERR_BAD_COOKIE) + error = EINVAL; + + while (error == 0 && + (ap->a_cookies == NULL || ncookies != 0) && + ndp < (struct nfs_dirent *)readdir_iovec.iov_base) { + struct dirent *dp = &ndp->dirent; + int reclen = dp->d_reclen; + + dp->d_reclen -= NFS_DIRENT_OVERHEAD; + + if (uio->uio_resid < dp->d_reclen) { + done = 1; break; - off += dp->d_reclen; - *(cookies++) = off; - base += dp->d_reclen; + } + + error = uiomove((caddr_t)dp, dp->d_reclen, uio); + if (error) + break; + + newoff = fxdr_hyper(&ndp->cookie[0]); + + if (ap->a_cookies != NULL) { + *cookies = newoff; + cookies++; + ncookies--; + } + + ndp = (struct nfs_dirent *)((u_int8_t *)ndp + reclen); } + } while (!error && !done && !eof && cnt--); + + FREE(data, M_TEMP); + data = NULL; + + if (ap->a_cookies) { + if (error) { + FREE(*ap->a_cookies, M_TEMP); + *ap->a_cookies = NULL; + *ap->a_ncookies = 0; + } else { + *ap->a_ncookies -= ncookies; + } + } + + if (!error) + uio->uio_offset = newoff; - *ap->a_ncookies -= ncookies; - uio->uio_resid += ((caddr_t)uio->uio_iov->iov_base - base); - uio->uio_iov->iov_len += ((caddr_t)uio->uio_iov->iov_base - base); - uio->uio_iov->iov_base = base; + if (!error && (eof || uio->uio_resid == tresid)) { + nfsstats.direofcache_misses++; + *ap->a_eofflag = 1; + return (0); } *ap->a_eofflag = 0; return (error); } + +/* + * The function below stuff the cookies in after the name + */ + /* * Readdir rpc call. - * Called from below the buffer cache by nfs_doio(). */ int -nfs_readdirrpc(vp, uiop, cred) - struct vnode *vp; - register struct uio *uiop; - struct ucred *cred; +nfs_readdirrpc(struct vnode *vp, + struct uio *uiop, + struct ucred *cred, + int *end_of_directory) { register int len, left; + struct nfs_dirent *ndp = NULL; register struct dirent *dp = NULL; register u_int32_t *tl; register caddr_t cp; register int32_t t1, t2; - register nfsuint64 *cookiep; caddr_t bpos, dpos, cp2; struct mbuf *mreq, *mrep, *md, *mb, *mb2; nfsuint64 cookie; @@ -1953,19 +2042,13 @@ nfs_readdirrpc(vp, uiop, cred) int v3 = NFS_ISV3(vp); #ifndef DIAGNOSTIC - if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) || + if (uiop->uio_iovcnt != 1 || (uiop->uio_resid & (NFS_DIRBLKSIZ - 1))) panic("nfs readdirrpc bad uio"); #endif - /* - * If there is no cookie, assume end of directory. - */ - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); - if (cookiep) - cookie = *cookiep; - else - return (0); + txdr_hyper(uiop->uio_offset, &cookie.nfsuquad[0]); + /* * Loop around doing readdir rpc's of size nm_readdirsize * truncated to a multiple of NFS_READDIRBLKSIZ. @@ -1980,11 +2063,17 @@ nfs_readdirrpc(vp, uiop, cred) nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = cookie.nfsuquad[0]; *tl++ = cookie.nfsuquad[1]; - *tl++ = dnp->n_cookieverf.nfsuquad[0]; - *tl++ = dnp->n_cookieverf.nfsuquad[1]; + if (cookie.nfsuquad[0] == 0 && + cookie.nfsuquad[1] == 0) { + *tl++ = 0; + *tl++ = 0; + } else { + *tl++ = dnp->n_cookieverf.nfsuquad[0]; + *tl++ = dnp->n_cookieverf.nfsuquad[1]; + } } else { nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = cookie.nfsuquad[0]; + *tl++ = cookie.nfsuquad[1]; } *tl = txdr_unsigned(nmp->nm_readdirsize); nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); @@ -2021,40 +2110,37 @@ nfs_readdirrpc(vp, uiop, cred) m_freem(mrep); goto nfsmout; } - tlen = nfsm_rndup(len); - if (tlen == len) - tlen += 4; /* To ensure null termination */ + tlen = nfsm_rndup(len + 1); left = NFS_READDIRBLKSIZ - blksiz; - if ((tlen + DIRHDSIZ) > left) { + if ((tlen + NFS_DIRHDSIZ) > left) { dp->d_reclen += left; (caddr_t)uiop->uio_iov->iov_base += left; uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; uiop->uio_resid -= left; blksiz = 0; } - if ((tlen + DIRHDSIZ) > uiop->uio_resid) + if ((tlen + NFS_DIRHDSIZ) > uiop->uio_resid) bigenough = 0; if (bigenough) { - dp = (struct dirent *)uiop->uio_iov->iov_base; + ndp = (struct nfs_dirent *) + uiop->uio_iov->iov_base; + dp = &ndp->dirent; dp->d_fileno = (int)fileno; dp->d_namlen = len; - dp->d_reclen = tlen + DIRHDSIZ; + dp->d_reclen = tlen + NFS_DIRHDSIZ; dp->d_type = DT_UNKNOWN; blksiz += dp->d_reclen; if (blksiz == NFS_READDIRBLKSIZ) blksiz = 0; - uiop->uio_offset += DIRHDSIZ; - uiop->uio_resid -= DIRHDSIZ; - (caddr_t)uiop->uio_iov->iov_base += DIRHDSIZ; - uiop->uio_iov->iov_len -= DIRHDSIZ; + uiop->uio_resid -= NFS_DIRHDSIZ; + uiop->uio_iov->iov_base += NFS_DIRHDSIZ; + uiop->uio_iov->iov_len -= NFS_DIRHDSIZ; nfsm_mtouio(uiop, len); cp = uiop->uio_iov->iov_base; tlen -= len; *cp = '\0'; /* null terminate */ (caddr_t)uiop->uio_iov->iov_base += tlen; uiop->uio_iov->iov_len -= tlen; - uiop->uio_offset += tlen; uiop->uio_resid -= tlen; } else nfsm_adv(nfsm_rndup(len)); @@ -2066,9 +2152,13 @@ nfs_readdirrpc(vp, uiop, cred) 2 * NFSX_UNSIGNED); } if (bigenough) { - cookie.nfsuquad[0] = *tl++; - if (v3) - cookie.nfsuquad[1] = *tl++; + if (v3) { + ndp->cookie[0] = cookie.nfsuquad[0] = + *tl++; + } else + ndp->cookie[0] = 0; + + ndp->cookie[1] = cookie.nfsuquad[1] = *tl++; } else if (v3) tl += 2; else @@ -2093,7 +2183,6 @@ nfs_readdirrpc(vp, uiop, cred) dp->d_reclen += left; uiop->uio_iov->iov_base += left; uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; uiop->uio_resid -= left; } @@ -2101,14 +2190,14 @@ nfs_readdirrpc(vp, uiop, cred) * We are now either at the end of the directory or have filled the * block. */ - if (bigenough) - dnp->n_direofoffset = uiop->uio_offset; - else { + if (bigenough) { + dnp->n_direofoffset = fxdr_hyper(&cookie.nfsuquad[0]); + if (end_of_directory) *end_of_directory = 1; + } else { if (uiop->uio_resid > 0) printf("EEK! readdirrpc resid > 0\n"); - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); - *cookiep = cookie; } + nfsmout: return (error); } @@ -2117,18 +2206,16 @@ nfsmout: * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc(). */ int -nfs_readdirplusrpc(vp, uiop, cred) - struct vnode *vp; - register struct uio *uiop; - struct ucred *cred; +nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, + int *end_of_directory) { register int len, left; + struct nfs_dirent *ndirp = NULL; register struct dirent *dp = NULL; register u_int32_t *tl; register caddr_t cp; register int32_t t1, t2; register struct vnode *newvp; - register nfsuint64 *cookiep; caddr_t bpos, dpos, cp2, dpossav1, dpossav2; struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2; struct nameidata nami, *ndp = &nami; @@ -2142,22 +2229,16 @@ nfs_readdirplusrpc(vp, uiop, cred) int attrflag, fhsize; #ifndef DIAGNOSTIC - if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) || + if (uiop->uio_iovcnt != 1 || (uiop->uio_resid & (NFS_DIRBLKSIZ - 1))) panic("nfs readdirplusrpc bad uio"); #endif ndp->ni_dvp = vp; newvp = NULLVP; - /* - * If there is no cookie, assume end of directory. - */ - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); - if (cookiep) - cookie = *cookiep; - else - return (0); - /* + txdr_hyper(uiop->uio_offset, &cookie.nfsuquad[0]); + + /* * Loop around doing readdir rpc's of size nm_readdirsize * truncated to a multiple of NFS_READDIRBLKSIZ. * The stopping criteria is EOF or buffer full. @@ -2170,8 +2251,14 @@ nfs_readdirplusrpc(vp, uiop, cred) nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED); *tl++ = cookie.nfsuquad[0]; *tl++ = cookie.nfsuquad[1]; - *tl++ = dnp->n_cookieverf.nfsuquad[0]; - *tl++ = dnp->n_cookieverf.nfsuquad[1]; + if (cookie.nfsuquad[0] == 0 && + cookie.nfsuquad[1] == 0) { + *tl++ = 0; + *tl++ = 0; + } else { + *tl++ = dnp->n_cookieverf.nfsuquad[0]; + *tl++ = dnp->n_cookieverf.nfsuquad[1]; + } *tl++ = txdr_unsigned(nmp->nm_readdirsize); *tl = txdr_unsigned(nmp->nm_rsize); nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred); @@ -2195,33 +2282,31 @@ nfs_readdirplusrpc(vp, uiop, cred) m_freem(mrep); goto nfsmout; } - tlen = nfsm_rndup(len); - if (tlen == len) - tlen += 4; /* To ensure null termination*/ + tlen = nfsm_rndup(len + 1); left = NFS_READDIRBLKSIZ - blksiz; - if ((tlen + DIRHDSIZ) > left) { + if ((tlen + NFS_DIRHDSIZ) > left) { dp->d_reclen += left; uiop->uio_iov->iov_base += left; uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; uiop->uio_resid -= left; blksiz = 0; } - if ((tlen + DIRHDSIZ) > uiop->uio_resid) + if ((tlen + NFS_DIRHDSIZ) > uiop->uio_resid) bigenough = 0; if (bigenough) { - dp = (struct dirent *)uiop->uio_iov->iov_base; + ndirp = (struct nfs_dirent *) + uiop->uio_iov->iov_base; + dp = &ndirp->dirent; dp->d_fileno = (int)fileno; dp->d_namlen = len; - dp->d_reclen = tlen + DIRHDSIZ; + dp->d_reclen = tlen + NFS_DIRHDSIZ; dp->d_type = DT_UNKNOWN; blksiz += dp->d_reclen; if (blksiz == NFS_READDIRBLKSIZ) blksiz = 0; - uiop->uio_offset += DIRHDSIZ; - uiop->uio_resid -= DIRHDSIZ; - uiop->uio_iov->iov_base += DIRHDSIZ; - uiop->uio_iov->iov_len -= DIRHDSIZ; + uiop->uio_resid -= NFS_DIRHDSIZ; + uiop->uio_iov->iov_base += NFS_DIRHDSIZ; + uiop->uio_iov->iov_len -= NFS_DIRHDSIZ; cnp->cn_nameptr = uiop->uio_iov->iov_base; cnp->cn_namelen = len; nfsm_mtouio(uiop, len); @@ -2230,14 +2315,13 @@ nfs_readdirplusrpc(vp, uiop, cred) *cp = '\0'; uiop->uio_iov->iov_base += tlen; uiop->uio_iov->iov_len -= tlen; - uiop->uio_offset += tlen; uiop->uio_resid -= tlen; } else nfsm_adv(nfsm_rndup(len)); nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); if (bigenough) { - cookie.nfsuquad[0] = *tl++; - cookie.nfsuquad[1] = *tl++; + ndirp->cookie[0] = cookie.nfsuquad[0] = *tl++; + ndirp->cookie[1] = cookie.nfsuquad[1] = *tl++; } else tl += 2; @@ -2317,7 +2401,6 @@ nfs_readdirplusrpc(vp, uiop, cred) dp->d_reclen += left; uiop->uio_iov->iov_base += left; uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; uiop->uio_resid -= left; } @@ -2325,14 +2408,14 @@ nfs_readdirplusrpc(vp, uiop, cred) * We are now either at the end of the directory or have filled the * block. */ - if (bigenough) - dnp->n_direofoffset = uiop->uio_offset; - else { + if (bigenough) { + dnp->n_direofoffset = fxdr_hyper(&cookie.nfsuquad[0]); + if (end_of_directory) *end_of_directory = 1; + } else { if (uiop->uio_resid > 0) printf("EEK! readdirplusrpc resid > 0\n"); - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); - *cookiep = cookie; } + nfsmout: if (newvp != NULLVP) vrele(newvp); diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h index 96c383429bb..27f33ffb8e8 100644 --- a/sys/nfs/nfsnode.h +++ b/sys/nfs/nfsnode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfsnode.h,v 1.8 2001/06/23 02:14:27 csapuntz Exp $ */ +/* $OpenBSD: nfsnode.h,v 1.9 2001/06/25 02:15:48 csapuntz Exp $ */ /* $NetBSD: nfsnode.h,v 1.16 1996/02/18 11:54:04 fvdl Exp $ */ /* @@ -206,8 +206,6 @@ int nfs_removeit __P((struct sillyrename *)); int nfs_nget __P((struct mount *,nfsfh_t *,int,struct nfsnode **)); int nfs_lookitup __P((struct vnode *,char *,int,struct ucred *,struct proc *,struct nfsnode **)); int nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *)); -nfsuint64 *nfs_getcookie __P((struct nfsnode *, off_t, int)); -void nfs_invaldir __P((struct vnode *)); extern int (**nfsv2_vnodeop_p) __P((void *)); |