readdir fixes from Rick Macklem
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Tue, 6 Mar 1990 11:38:19 +0000 (03:38 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Tue, 6 Mar 1990 11:38:19 +0000 (03:38 -0800)
SCCS-vsn: sys/nfs/nfs.h 7.6
SCCS-vsn: sys/nfs/nfs_vnops.c 7.32
SCCS-vsn: sys/nfs/nfs_node.c 7.23
SCCS-vsn: sys/nfs/nfs_serv.c 7.15
SCCS-vsn: sys/nfs/nfsnode.h 7.9

usr/src/sys/nfs/nfs.h
usr/src/sys/nfs/nfs_node.c
usr/src/sys/nfs/nfs_serv.c
usr/src/sys/nfs/nfs_vnops.c
usr/src/sys/nfs/nfsnode.h

index b95db4d..914bffe 100644 (file)
@@ -17,7 +17,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)nfs.h       7.5 (Berkeley) %G%
+ *     @(#)nfs.h       7.6 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -88,6 +88,8 @@ struct nfsstats {
        int     attrcache_misses;
        int     lookupcache_hits;
        int     lookupcache_misses;
        int     attrcache_misses;
        int     lookupcache_hits;
        int     lookupcache_misses;
+       int     direofcache_hits;
+       int     direofcache_misses;
        int     biocache_reads;
        int     read_bios;
        int     read_physios;
        int     biocache_reads;
        int     read_bios;
        int     read_physios;
index f119fba..68a3793 100644 (file)
@@ -17,7 +17,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)nfs_node.c  7.22 (Berkeley) %G%
+ *     @(#)nfs_node.c  7.23 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -139,6 +139,7 @@ loop:
        nfs_lock(vp);
        bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
        np->n_attrstamp = 0;
        nfs_lock(vp);
        bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
        np->n_attrstamp = 0;
+       np->n_direofstamp = 0;
        np->n_sillyrename = (struct sillyrename *)0;
        np->n_size = 0;
        np->n_mtime = 0;
        np->n_sillyrename = (struct sillyrename *)0;
        np->n_size = 0;
        np->n_mtime = 0;
index 9b794e7..af88a0a 100644 (file)
@@ -17,7 +17,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)nfs_serv.c  7.14 (Berkeley) %G%
+ *     @(#)nfs_serv.c  7.15 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -1028,7 +1028,7 @@ nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat)
        fhandle_t *fhp;
        struct uio io;
        struct iovec iv;
        fhandle_t *fhp;
        struct uio io;
        struct iovec iv;
-       int siz, cnt, fullsiz;
+       int siz, cnt, fullsiz, eofflag;
        u_long on;
        char *rbuf;
        off_t off, toff;
        u_long on;
        char *rbuf;
        off_t off, toff;
@@ -1061,7 +1061,7 @@ again:
        io.uio_resid = fullsiz;
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
        io.uio_resid = fullsiz;
        io.uio_segflg = UIO_SYSSPACE;
        io.uio_rw = UIO_READ;
-       error = VOP_READDIR(vp, &io, cred);
+       error = VOP_READDIR(vp, &io, cred, &eofflag);
        off = io.uio_offset;
        if (error) {
                vrele(vp);
        off = io.uio_offset;
        if (error) {
                vrele(vp);
@@ -1172,7 +1172,10 @@ again:
        *p = nfs_false;
        bp += NFSX_UNSIGNED;
        nfsm_clget;
        *p = nfs_false;
        bp += NFSX_UNSIGNED;
        nfsm_clget;
-       *p = nfs_false;
+       if (eofflag)
+               *p = nfs_true;
+       else
+               *p = nfs_false;
        bp += NFSX_UNSIGNED;
        if (bp < be)
                mp->m_len = bp-mtod(mp, caddr_t);
        bp += NFSX_UNSIGNED;
        if (bp < be)
                mp->m_len = bp-mtod(mp, caddr_t);
index bb2df28..12663f8 100644 (file)
@@ -17,7 +17,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)nfs_vnops.c 7.31 (Berkeley) %G%
+ *     @(#)nfs_vnops.c 7.32 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -29,6 +29,7 @@
 #include "param.h"
 #include "user.h"
 #include "proc.h"
 #include "param.h"
 #include "user.h"
 #include "proc.h"
+#include "kernel.h"
 #include "mount.h"
 #include "buf.h"
 #include "vm.h"
 #include "mount.h"
 #include "buf.h"
 #include "vm.h"
@@ -752,6 +753,7 @@ nfs_create(ndp, vap)
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_CREATE]);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_CREATE]);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
+       VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
        nfs_nput(ndp->ni_dvp);
        return (error);
 }
        nfs_nput(ndp->ni_dvp);
        return (error);
 }
@@ -808,6 +810,7 @@ nfs_remove(ndp)
                nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
                nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
                nfsm_reqdone;
                nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
                nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
                nfsm_reqdone;
+               VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
                /*
                 * Kludge City: If the first reply to the remove rpc is lost..
                 *   the reply to the retransmitted request will be ENOENT
                /*
                 * Kludge City: If the first reply to the remove rpc is lost..
                 *   the reply to the retransmitted request will be ENOENT
@@ -847,6 +850,7 @@ nfs_removeit(ndp)
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
        nfsm_reqdone;
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
        nfsm_reqdone;
+       VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -874,6 +878,8 @@ nfs_rename(sndp, tndp)
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
        nfsm_reqdone;
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
        nfsm_reqdone;
+       VTONFS(sndp->ni_dvp)->n_direofstamp = 0;
+       VTONFS(tndp->ni_dvp)->n_direofstamp = 0;
        if (sndp->ni_vp->v_type == VDIR) {
                if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
                        cache_purge(tndp->ni_dvp);
        if (sndp->ni_vp->v_type == VDIR) {
                if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
                        cache_purge(tndp->ni_dvp);
@@ -913,6 +919,8 @@ nfs_renameit(sndp, tndp)
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
        nfsm_reqdone;
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
        nfsm_reqdone;
+       VTONFS(sndp->ni_dvp)->n_direofstamp = 0;
+       VTONFS(tndp->ni_dvp)->n_direofstamp = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -942,6 +950,7 @@ nfs_link(vp, ndp)
        nfsm_request(vp, nonidempotent[NFSPROC_LINK]);
        nfsm_reqdone;
        VTONFS(vp)->n_attrstamp = 0;
        nfsm_request(vp, nonidempotent[NFSPROC_LINK]);
        nfsm_reqdone;
        VTONFS(vp)->n_attrstamp = 0;
+       VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
        if (ndp->ni_dvp != vp)
                nfs_unlock(vp);
        nfs_nput(ndp->ni_dvp);
        if (ndp->ni_dvp != vp)
                nfs_unlock(vp);
        nfs_nput(ndp->ni_dvp);
@@ -985,6 +994,7 @@ nfs_symlink(ndp, vap, nm)
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]);
        nfsm_reqdone;
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]);
        nfsm_reqdone;
+       VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
        nfs_nput(ndp->ni_dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
        nfs_nput(ndp->ni_dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
@@ -1025,6 +1035,7 @@ nfs_mkdir(ndp, vap)
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_MKDIR]);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_MKDIR]);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
+       VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
        nfs_nput(ndp->ni_dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
        nfs_nput(ndp->ni_dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
@@ -1060,6 +1071,7 @@ nfs_rmdir(ndp)
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_RMDIR]);
        nfsm_reqdone;
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
        nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_RMDIR]);
        nfsm_reqdone;
+       VTONFS(ndp->ni_dvp)->n_direofstamp = 0;
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_vp);
        nfs_nput(ndp->ni_vp);
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_vp);
        nfs_nput(ndp->ni_vp);
@@ -1078,10 +1090,11 @@ nfs_rmdir(ndp)
  * order so that it looks more sensible. This appears consistent with the
  * Ultrix implementation of NFS.
  */
  * order so that it looks more sensible. This appears consistent with the
  * Ultrix implementation of NFS.
  */
-nfs_readdir(vp, uiop, cred)
+nfs_readdir(vp, uiop, cred, eofflagp)
        register struct vnode *vp;
        struct uio *uiop;
        struct ucred *cred;
        register struct vnode *vp;
        struct uio *uiop;
        struct ucred *cred;
+       int *eofflagp;
 {
        register long len;
        register struct direct *dp;
 {
        register long len;
        register struct direct *dp;
@@ -1096,77 +1109,124 @@ nfs_readdir(vp, uiop, cred)
        struct mbuf *md2;
        caddr_t dpos2;
        int siz;
        struct mbuf *md2;
        caddr_t dpos2;
        int siz;
-       int more_dirs;
+       int more_dirs = 1;
        off_t off, savoff;
        struct direct *savdp;
        off_t off, savoff;
        struct direct *savdp;
+       struct nfsmount *nmp;
+       struct nfsnode *np = VTONFS(vp);
+       long tresid;
 
 
-       nfsstats.rpccnt[NFSPROC_READDIR]++;
-       nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
-       nfsm_fhtom(vp);
-       nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
-       *p++ = txdr_unsigned(uiop->uio_offset);
-       *p = txdr_unsigned(uiop->uio_resid);
-       nfsm_request(vp, nonidempotent[NFSPROC_READDIR]);
-       siz = 0;
-       nfsm_disect(p, u_long *, NFSX_UNSIGNED);
-       more_dirs = fxdr_unsigned(int, *p);
-
-       /* Save the position so that we can do nfsm_mtouio() later */
-       dpos2 = dpos;
-       md2 = md;
-
-       /* loop thru the dir entries, doctoring them to 4bsd form */
-       savoff = off = 0;
-       savdp = dp = NULL;
-       while (more_dirs && siz < uiop->uio_resid) {
-               savoff = off;           /* Hold onto offset and dp */
-               savdp = dp;
-               nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
-               dp = (struct direct *)p;
-               dp->d_ino = fxdr_unsigned(u_long, *p++);
-               len = fxdr_unsigned(int, *p);
-               if (len <= 0 || len > NFS_MAXNAMLEN) {
-                       error = EBADRPC;
-                       m_freem(mrep);
-                       goto nfsmout;
-               }
-               dp->d_namlen = (u_short)len;
-               nfsm_adv(len);          /* Point past name */
-               tlen = nfsm_rndup(len);
-               if (tlen != len) {      /* If name not on rounded boundary */
-                       *dpos = '\0';   /* Null-terminate */
-                       nfsm_adv(tlen - len);
-                       len = tlen;
-               }
-               nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
-               off = fxdr_unsigned(off_t, *p);
-               *p++ = 0;               /* Ensures null termination of name */
-               more_dirs = fxdr_unsigned(int, *p);
-               dp->d_reclen = len+4*NFSX_UNSIGNED;
-               siz += dp->d_reclen;
-       }
        /*
        /*
-        * If at end of rpc data, get the eof boolean
+        * First, check for hit on the EOF offset cache
         */
         */
-       if (!more_dirs)
-               nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
+       if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset &&
+           (time.tv_sec - np->n_direofstamp) < NFS_ATTRTIMEO) {
+               *eofflagp = 1;
+               nfsstats.direofcache_hits++;
+               return (0);
+       }
+
+       nmp = vfs_to_nfs(vp->v_mount);
+       tresid = uiop->uio_resid;
        /*
        /*
-        * If there is too much to fit in the data buffer, use savoff and
-        * savdp to trim off the last record.
-        * --> we are not at eof
+        * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
+        * whichever is smaller, truncated to a multiple of DIRBLKSIZ.
+        * The stopping criteria is EOF or less than DIRBLKSIZ of the
+        * request left.
         */
         */
-       if (siz > uiop->uio_resid) {
-               off = savoff;
-               siz -= dp->d_reclen;
-               dp = savdp;
+       while (more_dirs && uiop->uio_resid >= DIRBLKSIZ) {
+               nfsstats.rpccnt[NFSPROC_READDIR]++;
+               nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
+               nfsm_fhtom(vp);
+               nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
+               *p++ = txdr_unsigned(uiop->uio_offset);
+               *p = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
+                       nmp->nm_rsize : uiop->uio_resid) & ~(DIRBLKSIZ-1));
+               nfsm_request(vp, nonidempotent[NFSPROC_READDIR]);
+               siz = 0;
+               nfsm_disect(p, u_long *, NFSX_UNSIGNED);
+               more_dirs = fxdr_unsigned(int, *p);
+       
+               /* Save the position so that we can do nfsm_mtouio() later */
+               dpos2 = dpos;
+               md2 = md;
+       
+               /* loop thru the dir entries, doctoring them to 4bsd form */
+               savoff = off = 0;
+               savdp = dp = NULL;
+               while (more_dirs && siz < uiop->uio_resid) {
+                       savoff = off;           /* Hold onto offset and dp */
+                       savdp = dp;
+                       nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
+                       dp = (struct direct *)p;
+                       dp->d_ino = fxdr_unsigned(u_long, *p++);
+                       len = fxdr_unsigned(int, *p);
+                       if (len <= 0 || len > NFS_MAXNAMLEN) {
+                               error = EBADRPC;
+                               m_freem(mrep);
+                               goto nfsmout;
+                       }
+                       dp->d_namlen = (u_short)len;
+                       nfsm_adv(len);          /* Point past name */
+                       tlen = nfsm_rndup(len);
+                       /*
+                        * This should not be necessary, but some servers have
+                        * broken XDR such that these bytes are not null filled.
+                        */
+                       if (tlen != len) {
+                               *dpos = '\0';   /* Null-terminate */
+                               nfsm_adv(tlen - len);
+                               len = tlen;
+                       }
+                       nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
+                       off = fxdr_unsigned(off_t, *p);
+                       *p++ = 0;       /* Ensures null termination of name */
+                       more_dirs = fxdr_unsigned(int, *p);
+                       dp->d_reclen = len+4*NFSX_UNSIGNED;
+                       siz += dp->d_reclen;
+               }
+               /*
+                * If at end of rpc data, get the eof boolean
+                */
+               if (!more_dirs) {
+                       nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
+                       more_dirs = (fxdr_unsigned(int, *p) == 0);
+
+                       /*
+                        * If at EOF, cache directory offset
+                        */
+                       if (!more_dirs) {
+                               np->n_direofoffset = off;
+                               np->n_direofstamp = time.tv_sec;
+                       }
+               }
+               /*
+                * If there is too much to fit in the data buffer, use savoff and
+                * savdp to trim off the last record.
+                * --> we are not at eof
+                */
+               if (siz > uiop->uio_resid) {
+                       off = savoff;
+                       siz -= dp->d_reclen;
+                       dp = savdp;
+                       more_dirs = 0;  /* Paranoia */
+               }
+               if (siz > 0) {
+                       md = md2;
+                       dpos = dpos2;
+                       nfsm_mtouio(uiop, siz);
+                       uiop->uio_offset = off;
+               } else
+                       more_dirs = 0;  /* Ugh, never happens, but in case.. */
+               m_freem(mrep);
        }
        }
-       if (siz > 0) {
-               md = md2;
-               dpos = dpos2;
-               nfsm_mtouio(uiop, siz);
-               uiop->uio_offset = off;
+nfsmout:
+       if (tresid == uiop->uio_resid) {
+               *eofflagp = 1;
+               nfsstats.direofcache_misses++;
+       } else {
+               *eofflagp = 0;
        }
        }
-       nfsm_reqdone;
        return (error);
 }
 
        return (error);
 }
 
index 0200573..5dd6667 100644 (file)
@@ -17,7 +17,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)nfsnode.h   7.8 (Berkeley) %G%
+ *     @(#)nfsnode.h   7.9 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -33,7 +33,7 @@ struct nfsnode {
        nfsv2fh_t n_fh;                 /* NFS File Handle */
        long    n_flag;                 /* Flag for locking.. */
        struct  vnode *n_vnode; /* vnode associated with this nfsnode */
        nfsv2fh_t n_fh;                 /* NFS File Handle */
        long    n_flag;                 /* Flag for locking.. */
        struct  vnode *n_vnode; /* vnode associated with this nfsnode */
-       long    n_attrstamp;    /* Time stamp (sec) for attributes */
+       time_t  n_attrstamp;    /* Time stamp (sec) for attributes */
        struct  vattr n_vattr;  /* Vnode attribute cache */
        struct  sillyrename *n_sillyrename;     /* Ptr to silly rename struct */
        u_long  n_size;         /* Current size of file */
        struct  vattr n_vattr;  /* Vnode attribute cache */
        struct  sillyrename *n_sillyrename;     /* Ptr to silly rename struct */
        u_long  n_size;         /* Current size of file */
@@ -42,6 +42,8 @@ struct nfsnode {
        int     n_error;        /* Save write error value */
        pid_t   n_lockholder;   /* holder of nfsnode lock */
        pid_t   n_lockwaiter;   /* most recent waiter for nfsnode lock */
        int     n_error;        /* Save write error value */
        pid_t   n_lockholder;   /* holder of nfsnode lock */
        pid_t   n_lockwaiter;   /* most recent waiter for nfsnode lock */
+       u_long  n_direofoffset; /* Dir. EOF offset cache */
+       time_t  n_direofstamp;  /* Time stamp for dir. EOF offset cache */
 };
 
 #define        n_forw          n_chain[0]
 };
 
 #define        n_forw          n_chain[0]