summaryrefslogtreecommitdiff
path: root/sys/nfs
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-06-25 02:15:49 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-06-25 02:15:49 +0000
commit35821d4b137b32915ec7997db57bbf82afcf95c9 (patch)
treed720e6cbf1406328837c164db6eea08de41b71ab /sys/nfs
parent8f2d3cfc3b4105d59367fc205296b7513725280c (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.c106
-rw-r--r--sys/nfs/nfs_nqlease.c7
-rw-r--r--sys/nfs/nfs_subs.c84
-rw-r--r--sys/nfs/nfs_var.h8
-rw-r--r--sys/nfs/nfs_vnops.c327
-rw-r--r--sys/nfs/nfsnode.h4
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 *));