afs: Clarify vcache->mvid accesses
[openafs.git] / src / afs / VNOPS / afs_vnop_readdir.c
index 92758b6..7892982 100644 (file)
  * afs_readdir_move
  * afs_bulkstat_send
  * afs_readdir/afs_readdir2(HP)
- * afs_readdir1 - HP and DUX NFS versions
+ * afs_readdir1 - HP NFS version
  * 
  */
 
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
 #include "afsincludes.h"       /* Afs-based standard headers */
@@ -32,27 +30,18 @@ RCSID
 #include "afs/nfsclient.h"
 #include "afs/afs_osidnlc.h"
 
-
-#if    defined(AFS_HPUX1122_ENV)
+#if defined(AFS_HPUX1122_ENV)
+#define DIRPAD 7
+#elif defined(AFS_NBSD40_ENV)
 #define DIRPAD 7
 #else
 #define DIRPAD 3
 #endif
-/**
- * A few definitions. This is until we have a proper header file
- * which ahs prototypes for all functions
- */
 
-extern struct DirEntry *afs_dir_GetBlob();
 /*
  * AFS readdir vnodeop and bulk stat support.
  */
 
-/* Saber C hates negative inode #s.  We're not going to talk about software
- * that could fail if it sees a negative inode #.
- */
-#define FIXUPSTUPIDINODE(a)    ((a) &= 0x7fffffff)
-
 /* BlobScan is supposed to ensure that the blob reference refers to a valid
     directory entry.  It consults the allocation map in the page header
     to determine whether a blob is actually in use or not.
@@ -66,37 +55,25 @@ extern struct DirEntry *afs_dir_GetBlob();
     BlobScan is used by the Linux port in a separate file, so it should not
     become static.
 */
-#if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
 int
-BlobScan(ino64_t * afile, afs_int32 ablob)
-#else
-#if defined(AFS_HPUX1123_ENV)
-/*DEE should use afs_inode_t for all */
-int 
-BlobScan(ino_t *afile, afs_int32 ablob)
-#else
-#ifdef AFS_LINUX_64BIT_KERNEL
-int
-BlobScan(long *afile, afs_int32 ablob)
-#else
-int
-BlobScan(afs_int32 * afile, afs_int32 ablob)
-#endif
-#endif
-#endif
+BlobScan(struct dcache * afile, afs_int32 ablob)
 {
-    register afs_int32 relativeBlob;
+    afs_int32 relativeBlob;
     afs_int32 pageBlob;
-    register struct PageHeader *tpe;
-    register afs_int32 i;
+    struct PageHeader *tpe;
+    struct DirBuffer headerbuf;
+    afs_int32 i;
+    int code;
 
     AFS_STATCNT(BlobScan);
     /* advance ablob over free and header blobs */
     while (1) {
        pageBlob = ablob & ~(EPP - 1);  /* base blob in same page */
-       tpe = (struct PageHeader *)afs_dir_GetBlob(afile, pageBlob);
-       if (!tpe)
-           return 0;           /* we've past the end */
+       code = afs_dir_GetBlob(afile, pageBlob, &headerbuf);
+       if (code)
+           return 0;
+       tpe = (struct PageHeader *)headerbuf.data;
+
        relativeBlob = ablob - pageBlob;        /* relative to page's first blob */
        /* first watch for headers */
        if (pageBlob == 0) {    /* first dir page has extra-big header */
@@ -114,7 +91,7 @@ BlobScan(afs_int32 * afile, afs_int32 ablob)
        }
        /* now relativeBlob is the page-relative first allocated blob,
         * or EPP (if there are none in this page). */
-       DRelease((struct buffer *)tpe, 0);
+       DRelease(&headerbuf, 0);
        if (i != EPP)
            return i + pageBlob;
        ablob = pageBlob + EPP; /* go around again */
@@ -122,6 +99,7 @@ BlobScan(afs_int32 * afile, afs_int32 ablob)
     /* never get here */
 }
 
+
 #if !defined(AFS_LINUX20_ENV)
 /* Changes to afs_readdir which affect dcache or vcache handling or use of
  * bulk stat data should also be reflected in the Linux specific verison of
@@ -159,33 +137,39 @@ struct irix5_min_dirent { /* miniature dirent structure */
 #else
 struct min_direct {            /* miniature direct structure */
     /* If struct direct changes, this must too */
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if defined(AFS_DARWIN80_ENV)
+    ino_t d_fileno;
+    u_short d_reclen;
+    u_char d_type;
+    u_char d_namlen;
+#elif defined(AFS_NBSD40_ENV)
+    ino_t d_fileno;            /* file number of entry */
+    uint16_t d_reclen;         /* length of this record */
+    uint16_t d_namlen;         /* length of string in d_name */
+    uint8_t  d_type;           /* file type, see below */
+#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     afs_uint32 d_fileno;
     u_short d_reclen;
     u_char d_type;
     u_char d_namlen;
-#else
-#ifdef AFS_SUN5_ENV
+#elif defined(AFS_SUN5_ENV)
     afs_uint32 d_fileno;
     afs_int32 d_off;
     u_short d_reclen;
 #else
-#if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV)
+#if defined(AFS_AIX32_ENV)
     afs_int32 d_off;
-    afs_uint32 d_fileno;
-#endif
-#if     defined(AFS_HPUX100_ENV)
+#elif defined(AFS_HPUX100_ENV)
     unsigned long long d_off;
-    afs_uint32 d_fileno;
 #endif
+    afs_uint32 d_fileno;
     u_short d_reclen;
     u_short d_namlen;
 #endif
-#endif
 };
 #endif /* AFS_SGI_ENV */
 
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
+#if    defined(AFS_HPUX_ENV)
 struct minnfs_direct {
     afs_int32 d_off;           /* XXX */
     afs_uint32 d_fileno;
@@ -223,11 +207,12 @@ int afs_rd_stash_i = 0;
 #define DIRSIZ_LEN(len) \
     ((sizeof (struct __dirent) - (_MAXNAMLEN+1)) + (((len)+1 + DIRPAD) &~ DIRPAD))
 #else
-#if    defined(AFS_SUN56_ENV)
+#if    defined(AFS_SUN5_ENV)
 #define DIRSIZ_LEN(len) ((18 + (len) + 1 + 7) & ~7 )
 #else
-#ifdef AFS_SUN5_ENV
-#define DIRSIZ_LEN(len)        ((10 + (len) + 1 + (NBPW-1)) & ~(NBPW-1))
+#ifdef AFS_NBSD40_ENV
+#define DIRSIZ_LEN(len) \
+    ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((len)+1 + 7) & ~7))
 #else
 #ifdef AFS_DIRENT
 #define DIRSIZ_LEN(len) \
@@ -243,30 +228,31 @@ int afs_rd_stash_i = 0;
     ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((len)+1 + 3) &~ 3))
 #endif /* AFS_SGI_ENV */
 #endif /* AFS_DIRENT */
+#endif /* AFS_NBSD40_ENV */
 #endif /* AFS_SUN5_ENV */
-#endif /* AFS_SUN56_ENV */
 #endif /* AFS_HPUX100_ENV */
 
 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 int
-afs_readdir_type(avc, ade)
-     struct DirEntry *ade;
-     struct vcache *avc;
+afs_readdir_type(struct vcache *avc, struct DirEntry *ade)
 {
     struct VenusFid tfid;
     struct vcache *tvc;
     int vtype;
-    tfid.Cell = avc->fid.Cell;
-    tfid.Fid.Volume = avc->fid.Fid.Volume;
+    tfid.Cell = avc->f.fid.Cell;
+    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
     tfid.Fid.Vnode = ntohl(ade->fid.vnode);
     tfid.Fid.Unique = ntohl(ade->fid.vunique);
-    if ((avc->states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
+    if ((avc->f.states & CForeign) == 0 && (ntohl(ade->fid.vnode) & 1)) {
        return DT_DIR;
-    } else if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
-       if (tvc->mvstat) {
+    }
+    ObtainReadLock(&afs_xvcache);
+    if ((tvc = afs_FindVCache(&tfid, 0, 0))) {
+        ReleaseReadLock(&afs_xvcache);
+       if (tvc->mvstat != AFS_MVSTAT_FILE) {
            afs_PutVCache(tvc);
            return DT_DIR;
-       } else if (((tvc->states) & (CStatd | CTruth))) {
+       } else if (((tvc->f.states) & (CStatd | CTruth))) {
            /* CTruth will be set if the object has
             *ever* been statd */
            vtype = vType(tvc);
@@ -276,12 +262,14 @@ afs_readdir_type(avc, ade)
            else if (vtype == VREG)
                return DT_REG;
            /* Don't do this until we're sure it can't be a mtpt */
-           /* else if (vtype == VLNK)
-            * type=DT_LNK; */
+           /* if we're CStatd and CTruth and mvstat==AFS_MVSTAT_FILE, it's a link */
+           else if (vtype == VLNK)
+               return DT_LNK;
            /* what other types does AFS support? */
        } else
            afs_PutVCache(tvc);
-    }
+    } else
+        ReleaseReadLock(&afs_xvcache);
     return DT_UNKNOWN;
 }
 #endif
@@ -295,32 +283,105 @@ afs_readdir_type(avc, ade)
 #endif
 char bufofzeros[64];           /* gotta fill with something */
 
-int
-afs_readdir_move(de, vc, auio, slen, rlen, off)
-     struct DirEntry *de;
-     struct vcache *vc;
-     struct uio *auio;
-     int slen;
 #ifdef AFS_SGI65_ENV
-     ssize_t rlen;
+int
+afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio, 
+                int slen, ssize_t rlen, afs_size_t off)
 #else
-     int rlen;
+int
+afs_readdir_move(struct DirEntry *de, struct vcache *vc, struct uio *auio, 
+                int slen, int rlen, afs_size_t off)
 #endif
-     afs_size_t off;
 {
     int code = 0;
-#if    defined(AFS_SUN56_ENV)
+    struct volume *tvp;
+    afs_uint32 Volume = vc->f.fid.Fid.Volume;
+    afs_uint32 Vnode  = de->fid.vnode;
+#if    defined(AFS_SUN5_ENV)
     struct dirent64 *direntp;
 #else
-#if  defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
+#if  (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
     struct dirent *direntp;
 #endif
-#endif /* AFS_SUN56_ENV */
+#endif /* AFS_SUN5_ENV */
 #ifndef        AFS_SGI53_ENV
     struct min_direct sdirEntry;
 #endif /* AFS_SGI53_ENV */
 
     AFS_STATCNT(afs_readdir_move);
+
+#define READDIR_CORRECT_INUMS
+#ifdef READDIR_CORRECT_INUMS
+    if (de->name[0] == '.' && !de->name[1]) {
+       /* This is the '.' entry; if we are a volume root, we need to
+        * ignore the directory and use the inum for the mount point.
+        */
+       if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
+           Volume = 0;
+           Vnode  = 2;
+       } else if (vc->mvstat == AFS_MVSTAT_ROOT) {
+           tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
+           if (tvp) {
+               Volume = tvp->mtpoint.Fid.Volume;
+               Vnode  = tvp->mtpoint.Fid.Vnode;
+               afs_PutVolume(tvp, READ_LOCK);
+           }
+       }
+    }
+    else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) {
+       /* This is the '..' entry.  Getting this right is very tricky,
+        * because we might be a volume root (so our parent is in a
+        * different volume), or our parent might be a volume root
+        * (so we actually want the mount point) or BOTH! */
+       if (!FidCmp(&afs_rootFid, &vc->f.fid)) {
+           /* We are the root of the AFS root, and thus our own parent */
+           Volume = 0;
+           Vnode  = 2;
+       } else if (vc->mvstat == AFS_MVSTAT_ROOT) {
+           /* We are a volume root, which means our parent is in another
+            * volume.  Luckily, we should have his fid cached... */
+           if (vc->mvid.parent) {
+               if (!FidCmp(&afs_rootFid, vc->mvid.parent)) {
+                   /* Parent directory is the root of the AFS root */
+                   Volume = 0;
+                   Vnode  = 2;
+               } else if (vc->mvid.parent->Fid.Vnode == 1
+                          && vc->mvid.parent->Fid.Unique == 1) {
+                   /* XXX The above test is evil and probably breaks DFS */
+                   /* Parent directory is the target of a mount point */
+                   tvp = afs_GetVolume(vc->mvid.parent, 0, READ_LOCK);
+                   if (tvp) {
+                       Volume = tvp->mtpoint.Fid.Volume;
+                       Vnode  = tvp->mtpoint.Fid.Vnode;
+                       afs_PutVolume(tvp, READ_LOCK);
+                   }
+               } else {
+                   /* Parent directory is not a volume root */
+                   Volume = vc->mvid.parent->Fid.Volume;
+                   Vnode  = vc->mvid.parent->Fid.Vnode;
+               }
+           }
+       } else if (de->fid.vnode == 1 && de->fid.vunique == 1) {
+           /* XXX The above test is evil and probably breaks DFS */
+           /* Parent directory is a volume root; use the right inum */
+           tvp = afs_GetVolume(&vc->f.fid, 0, READ_LOCK);
+           if (tvp) {
+               if (tvp->cell == afs_rootFid.Cell
+                   && tvp->volume == afs_rootFid.Fid.Volume) {
+                   /* Parent directory is the root of the AFS root */
+                   Volume = 0;
+                   Vnode  = 2;
+               } else {
+                   /* Parent directory is the target of a mount point */
+                   Volume = tvp->mtpoint.Fid.Volume;
+                   Vnode  = tvp->mtpoint.Fid.Vnode;
+               }
+               afs_PutVolume(tvp, READ_LOCK);
+           }
+       }
+    }
+#endif
+
 #ifdef AFS_SGI53_ENV
     {
        afs_int32 use64BitDirent;
@@ -345,9 +406,8 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
 
        if (use64BitDirent) {
            struct min_dirent sdirEntry;
-           sdirEntry.d_fileno =
-               (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
-           FIXUPSTUPIDINODE(sdirEntry.d_fileno);
+           sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell,
+                                              Volume, ntohl(Vnode));
            sdirEntry.d_reclen = rlen;
            sdirEntry.d_off = (off_t) off;
            AFS_UIOMOVE(&sdirEntry, AFS_DIRENT64BASESIZE, UIO_READ, auio,
@@ -369,9 +429,8 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
            }
        } else {
            struct irix5_min_dirent sdirEntry;
-           sdirEntry.d_fileno =
-               (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
-           FIXUPSTUPIDINODE(sdirEntry.d_fileno);
+           sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell,
+                                              Volume, ntohl(Vnode));
            sdirEntry.d_reclen = rlen;
            sdirEntry.d_off = (afs_int32) off;
            AFS_UIOMOVE(&sdirEntry, AFS_DIRENT32BASESIZE, UIO_READ, auio,
@@ -396,13 +455,8 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
     }
 #else /* AFS_SGI53_ENV */
 #if  defined(AFS_SUN5_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
-#if    defined(AFS_SUN56_ENV)
-    direntp = (struct dirent64 *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-#else
-    direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-#endif
-    direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
-    FIXUPSTUPIDINODE(direntp->d_ino);
+    direntp = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    direntp->d_ino = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
     direntp->d_offset = off;
     direntp->d_namlen = slen;
@@ -415,13 +469,12 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
     osi_FreeLargeSpace((char *)direntp);
 #else /* AFS_SUN5_ENV */
     /* Note the odd mechanism for building the inode number */
-    sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
-    FIXUPSTUPIDINODE(sdirEntry.d_fileno);
+    sdirEntry.d_fileno = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
     sdirEntry.d_reclen = rlen;
 #if !defined(AFS_SGI_ENV)
     sdirEntry.d_namlen = slen;
 #endif
-#if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
+#if defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV)
     sdirEntry.d_off = off;
 #endif
 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
@@ -438,20 +491,37 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
                    auio, code);
 #else /* AFS_SGI_ENV */
     AFS_MOVE_UNLOCK();
-    AFS_UIOMOVE((char *)&sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
-
+#if defined(AFS_NBSD40_ENV)
+    {
+       struct dirent *dp;
+       dp = osi_AllocLargeSpace(sizeof(struct dirent));
+       memset(dp, 0, sizeof(struct dirent));
+        dp->d_ino = afs_calc_inum(vc->f.fid.Cell, Volume, ntohl(Vnode));
+        dp->d_namlen = slen;
+        dp->d_type = afs_readdir_type(vc, de);
+        strcpy(dp->d_name, de->name);
+        dp->d_reclen = _DIRENT_SIZE(dp) /* rlen */;
+       if ((afs_debug & AFSDEB_VNLAYER) != 0) {
+           afs_warn("%s: %s type %d slen %d rlen %d act. rlen %zu\n", __func__,
+               dp->d_name, dp->d_type, slen, rlen, _DIRENT_SIZE(dp));
+       }
+        AFS_UIOMOVE(dp, dp->d_reclen, UIO_READ, auio, code);
+        osi_FreeLargeSpace((char *)dp);
+    }
+#else
+    AFS_UIOMOVE((char *) &sdirEntry, sizeof(sdirEntry), UIO_READ, auio, code);
     if (code == 0) {
        AFS_UIOMOVE(de->name, slen, UIO_READ, auio, code);
     }
-
     /* pad out the remaining characters with zeros */
     if (code == 0) {
        AFS_UIOMOVE(bufofzeros, ((slen + 1 + DIRPAD) & ~DIRPAD) - slen,
                    UIO_READ, auio, code);
     }
+#endif
     AFS_MOVE_LOCK();
 #endif /* AFS_SGI_ENV */
-
+#if !defined(AFS_NBSD_ENV)
     /* pad out the difference between rlen and slen... */
     if (DIRSIZ_LEN(slen) < rlen) {
        AFS_MOVE_UNLOCK();
@@ -464,6 +534,7 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
        }
        AFS_MOVE_LOCK();
     }
+#endif
 #endif /* AFS_SUN5_ENV */
 #endif /* AFS_SGI53_ENV */
     return (code);
@@ -487,9 +558,7 @@ afs_readdir_move(de, vc, auio, slen, rlen, off)
  */
 
 void
-afs_bulkstat_send(avc, req)
-     struct vcache *avc;
-     struct vrequest *req;
+afs_bulkstat_send(struct vcache *avc, struct vrequest *req)
 {
     afs_rd_stash_i = 0;
 }
@@ -500,25 +569,23 @@ afs_bulkstat_send(avc, req)
 */
 
 int
-#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-afs_readdir(OSI_VC_ARG(avc), auio, acred, eofp)
-     int *eofp;
+#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred, 
+           int *eofp)
 #else
 #if defined(AFS_HPUX100_ENV)
-afs_readdir2(OSI_VC_ARG(avc), auio, acred)
+afs_readdir2(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
 #else
-afs_readdir(OSI_VC_ARG(avc), auio, acred)
+afs_readdir(OSI_VC_DECL(avc), struct uio *auio, afs_ucred_t *acred)
 #endif
 #endif
-    OSI_VC_DECL(avc);
-     struct uio *auio;
-     struct AFS_UCRED *acred;
 {
-    struct vrequest treq;
-    register struct dcache *tdc;
+    struct vrequest *treq = NULL;
+    struct dcache *tdc;
     afs_size_t origOffset, tlen;
     afs_int32 len;
     int code = 0;
+    struct DirBuffer oldEntry, nextEntry;
     struct DirEntry *ode = 0, *nde = 0;
     int o_slen = 0, n_slen = 0;
     afs_uint32 us;
@@ -526,15 +593,15 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #if defined(AFS_SGI53_ENV)
     afs_int32 use64BitDirent, dirsiz;
 #endif /* defined(AFS_SGI53_ENV) */
-    OSI_VC_CONVERT(avc)
-#ifdef AFS_HPUX_ENV
-       /*
-        * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
-        * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
-        * translator side XXX
-        */
-    struct min_direct *sdirEntry =
-       (struct min_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
+#ifndef        AFS_HPUX_ENV
+    OSI_VC_CONVERT(avc);
+#else
+    /*
+     * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
+     * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
+     * translator side XXX
+     */
+    struct min_direct *sdirEntry = osi_AllocSmallSpace(sizeof(struct min_direct));
     afs_int32 rlen;
 #endif
 
@@ -546,6 +613,9 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
      */
     AFS_STATCNT(afs_readdir);
 
+    memset(&oldEntry, 0, sizeof(struct DirBuffer));
+    memset(&nextEntry, 0, sizeof(struct DirBuffer));
+
 #if defined(AFS_SGI53_ENV)
 #ifdef AFS_SGI61_ENV
 #ifdef AFS_SGI62_ENV
@@ -565,16 +635,18 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #endif /* AFS_SGI61_ENV */
 #endif /* defined(AFS_SGI53_ENV) */
 
-#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     /* Not really used by the callee so we ignore it for now */
     if (eofp)
        *eofp = 0;
 #endif
+#ifndef AFS_64BIT_CLIENT
     if (AfsLargeFileUio(auio)  /* file is large than 2 GB */
-       ||AfsLargeFileSize(auio->uio_offset, auio->uio_resid))
+       ||AfsLargeFileSize(AFS_UIO_OFFSET(auio), AFS_UIO_RESID(auio)))
        return EFBIG;
+#endif
 
-    if ((code = afs_InitReq(&treq, acred))) {
+    if ((code = afs_CreateReq(&treq, acred))) {
 #ifdef AFS_HPUX_ENV
        osi_FreeSmallSpace((char *)sdirEntry);
 #endif
@@ -582,16 +654,18 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
     }
     /* update the cache entry */
     afs_InitFakeStat(&fakestate);
-    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+
+    AFS_DISCON_LOCK();
+
+    code = afs_EvalFakeStat(&avc, &fakestate, treq);
     if (code)
        goto done;
   tagain:
-    code = afs_VerifyVCache(avc, &treq);
+    code = afs_VerifyVCache(avc, treq);
     if (code)
        goto done;
     /* get a reference to the entire directory */
-    tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
-    len = tlen;
+    tdc = afs_GetDCache(avc, (afs_size_t) 0, treq, &origOffset, &tlen, 1);
     if (!tdc) {
        code = ENOENT;
        goto done;
@@ -605,9 +679,9 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
      * 1. The cache data is being fetched by another process.
      * 2. The cache data is no longer valid
      */
-    while ((avc->states & CStatd)
+    while ((avc->f.states & CStatd)
           && (tdc->dflags & DFFetching)
-          && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
+          && hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
        afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
                   __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
                   ICL_TYPE_INT32, tdc->dflags);
@@ -617,8 +691,8 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
        ObtainReadLock(&avc->lock);
        ObtainReadLock(&tdc->lock);
     }
-    if (!(avc->states & CStatd)
-       || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
+    if (!(avc->f.states & CStatd)
+       || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
        ReleaseReadLock(&tdc->lock);
        ReleaseReadLock(&avc->lock);
        afs_PutDCache(tdc);
@@ -655,21 +729,26 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
     auio->uio_fpflags = 0;
 #endif
     while (code == 0) {
-       origOffset = auio->afsio_offset;
+       origOffset = AFS_UIO_OFFSET(auio);
        /* scan for the next interesting entry scan for in-use blob otherwise up point at
         * this blob note that ode, if non-zero, also represents a held dir page */
-       if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)))
-           || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f.inode, us))) {
+       us = BlobScan(tdc, (origOffset >> 5));
+
+       if (us)
+          code = afs_dir_GetVerifiedBlob(tdc, us, &nextEntry);
+
+       if (us == 0 || code != 0) {
+           code = 0; /* Reset code - keep old failure behaviour */
            /* failed to setup nde, return what we've got, and release ode */
            if (len) {
                /* something to hand over. */
 #ifdef AFS_HPUX_ENV
-               sdirEntry->d_fileno =
-                   (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-               FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-               sdirEntry->d_reclen = rlen = auio->afsio_resid;
+               sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
+                                                   avc->f.fid.Fid.Volume,
+                                                   ntohl(ode->fid.vnode));
+               sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
                sdirEntry->d_namlen = o_slen;
-#if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
                sdirEntry->d_off = origOffset;
 #endif
                AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
@@ -694,28 +773,27 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
                }
 #else
                code = afs_readdir_move(ode, avc, auio, o_slen,
-#if defined(AFS_SUN5_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
                                        len, origOffset);
 #else
-                                       auio->afsio_resid, origOffset);
+                                       AFS_UIO_RESID(auio), origOffset);
 #endif
 #endif /* AFS_HPUX_ENV */
-#if !defined(AFS_SUN5_ENV)
-               auio->afsio_resid = 0;
+#if !defined(AFS_SUN5_ENV) && !defined(AFS_NBSD_ENV)
+               AFS_UIO_SETRESID(auio, 0);
 #endif
            } else {
                /* nothin to hand over */
            }
-#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
            if (eofp)
                *eofp = 1;      /* Set it properly */
 #endif
-           if (ode)
-               DRelease((struct buffer *)ode, 0);
+           DRelease(&oldEntry, 0);
            goto dirend;
        }
-       /* by here nde is set */
-
+       nde = (struct DirEntry *)nextEntry.data;
+       
        /* Do we have enough user space to carry out our mission? */
 #if defined(AFS_SGI_ENV)
        n_slen = strlen(nde->name) + 1; /* NULL terminate */
@@ -725,20 +803,20 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #ifdef AFS_SGI53_ENV
        dirsiz =
            use64BitDirent ? DIRENTSIZE(n_slen) : IRIX5_DIRENTSIZE(n_slen);
-       if (dirsiz >= (auio->afsio_resid - len)) {
+       if (dirsiz >= (AFS_UIO_RESID(auio) - len)) {
 #else
-       if (DIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
+       if (DIRSIZ_LEN(n_slen) >= (AFS_UIO_RESID(auio) - len)) {
 #endif /* AFS_SGI53_ENV */
            /* No can do no more now; ya know... at this time */
-           DRelease((struct buffer *)nde, 0);  /* can't use this one. */
+           DRelease(&nextEntry, 0);    /* can't use this one. */
            if (len) {
 #ifdef AFS_HPUX_ENV
-               sdirEntry->d_fileno =
-                   (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-               FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-               sdirEntry->d_reclen = rlen = auio->afsio_resid;
+               sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
+                                                   avc->f.fid.Fid.Volume,
+                                                   ntohl(ode->fid.vnode));
+               sdirEntry->d_reclen = rlen = AFS_UIO_RESID(auio);
                sdirEntry->d_namlen = o_slen;
-#if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
                sdirEntry->d_off = origOffset;
 #endif
                AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
@@ -764,12 +842,14 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #else /* AFS_HPUX_ENV */
                code =
                    afs_readdir_move(ode, avc, auio, o_slen,
-                                    auio->afsio_resid, origOffset);
+                                    AFS_UIO_RESID(auio), origOffset);
 #endif /* AFS_HPUX_ENV */
                /* this next line used to be AFSVFS40 or AIX 3.1, but is
                 * really generic */
-               auio->afsio_offset = origOffset;
-               auio->afsio_resid = 0;
+               AFS_UIO_SETOFFSET(auio, origOffset);
+#if !defined(AFS_NBSD_ENV)
+               AFS_UIO_SETRESID(auio, 0);
+#endif
            } else {            /* trouble, can't give anything to the user! */
                /* even though he has given us a buffer, 
                 * even though we have something to give us,
@@ -777,8 +857,7 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
                 */
                code = EINVAL;
            }
-           if (ode)
-               DRelease((struct buffer *)ode, 0);
+           DRelease(&oldEntry, 0);
            goto dirend;
        }
 
@@ -788,12 +867,12 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
         */
        if (len) {
 #ifdef AFS_HPUX_ENV
-           sdirEntry->d_fileno =
-               (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-           FIXUPSTUPIDINODE(sdirEntry->d_fileno);
+           sdirEntry->d_fileno = afs_calc_inum(avc->f.fid.Cell,
+                                               avc->f.fid.Fid.Volume,
+                                               ntohl(ode->fid.vnode));
            sdirEntry->d_reclen = rlen = len;
            sdirEntry->d_namlen = o_slen;
-#if defined(AFS_SUN_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_HPUX100_ENV)
            sdirEntry->d_off = origOffset;
 #endif
            AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
@@ -827,14 +906,14 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #else
        len = DIRSIZ_LEN(o_slen = n_slen);
 #endif /* AFS_SGI53_ENV */
-       if (ode)
-           DRelease((struct buffer *)ode, 0);
+       
+       DRelease(&oldEntry, 0);
+       oldEntry = nextEntry;
        ode = nde;
-       auio->afsio_offset =
-           (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5);
+       AFS_UIO_SETOFFSET(auio, (afs_int32) ((us + afs_dir_NameBlobs(nde->name)) << 5));
     }
-    if (ode)
-       DRelease((struct buffer *)ode, 0);
+    
+    DRelease(&oldEntry, 0);
 
   dirend:
     ReleaseReadLock(&tdc->lock);
@@ -845,277 +924,11 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
 #ifdef AFS_HPUX_ENV
     osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+    AFS_DISCON_UNLOCK();
     afs_PutFakeStat(&fakestate);
-    code = afs_CheckCode(code, &treq, 28);
-    return code;
-}
-
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
-#ifdef AFS_OSF_ENV
-afs1_readdir(avc, auio, acred, eofp)
-     int *eofp;
-#else
-afs1_readdir(avc, auio, acred)
-#endif
-     struct vcache *avc;
-     struct uio *auio;
-     struct AFS_UCRED *acred;
-{
-    struct vrequest treq;
-    register struct dcache *tdc;
-    afs_size_t origOffset, len;
-    int code = 0;
-    struct DirEntry *ode = 0, *nde = 0;
-    int o_slen = 0, n_slen = 0;
-    afs_uint32 us;
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
-    /*
-     * XXX All the hacks for alloced sdirEntry and inlining of afs_readdir_move instead of calling
-     * it is necessary for hpux due to stack problems that seem to occur when coming thru the nfs
-     * translator side XXX
-     */
-    struct minnfs_direct *sdirEntry = (struct minnfs_direct *)
-       osi_AllocSmallSpace(sizeof(struct min_direct));
-    afs_int32 rlen;
-#endif
-    struct afs_fakestat_state fakestate;
-
-    AFS_STATCNT(afs_readdir);
-#if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
-    if (eofp)
-       *eofp = 0;
-#endif
-    if (code = afs_InitReq(&treq, acred)) {
-#ifdef AFS_HPUX_ENV
-       osi_FreeSmallSpace((char *)sdirEntry);
-#endif
-       return code;
-    }
-    afs_InitFakeStat(&fakestate);
-    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
-    if (code) {
-#ifdef AFS_HPUX_ENV
-       osi_FreeSmallSpace((char *)sdirEntry);
-#endif
-       afs_PutFakeStat(&fakestate);
-       return code;
-    }
-    /* update the cache entry */
-  tagain:
-    code = afs_VerifyVCache(avc, &treq);
-    if (code)
-       goto done;
-    /* get a reference to the entire directory */
-    tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &len, 1);
-    if (!tdc) {
-       code = ENOENT;
-       goto done;
-    }
-    ObtainReadLock(&avc->lock);
-    ObtainReadLock(&tdc->lock);
-
-    /*
-     * Make sure that the data in the cache is current. There are two
-     * cases we need to worry about:
-     * 1. The cache data is being fetched by another process.
-     * 2. The cache data is no longer valid
-     */
-    while ((avc->states & CStatd)
-          && (tdc->dflags & DFFetching)
-          && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
-       afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
-                  __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, tdc,
-                  ICL_TYPE_INT32, tdc->dflags);
-       ReleaseReadLock(&tdc->lock);
-       ReleaseReadLock(&avc->lock);
-       afs_osi_Sleep(&tdc->validPos);
-       ObtainReadLock(&avc->lock);
-       ObtainReadLock(&tdc->lock);
-    }
-    if (!(avc->states & CStatd)
-       || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
-       ReleaseReadLock(&tdc->lock);
-       ReleaseReadLock(&avc->lock);
-       afs_PutDCache(tdc);
-       goto tagain;
-    }
-
-    len = 0;
-#ifdef AFS_HPUX_ENV
-    auio->uio_fpflags = 0;
-#endif
-    while (code == 0) {
-       origOffset = auio->afsio_offset;
-
-       /* scan for the next interesting entry scan for in-use blob otherwise up point at
-        * this blob note that ode, if non-zero, also represents a held dir page */
-       if (!(us = BlobScan(&tdc->f.inode, (origOffset >> 5)))
-           || !(nde = (struct DirEntry *)afs_dir_GetBlob(&tdc->f.inode, us))) {
-           /* failed to setup nde, return what we've got, and release ode */
-           if (len) {
-               /* something to hand over. */
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
-               sdirEntry->d_fileno =
-                   (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-               FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-               sdirEntry->d_reclen = rlen = auio->afsio_resid;
-               sdirEntry->d_namlen = o_slen;
-               sdirEntry->d_off = origOffset;
-               AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
-                           auio, code);
-               if (code == 0) {
-                   AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
-               }
-               /* pad out the remaining characters with zeros */
-               if (code == 0) {
-                   AFS_UIOMOVE(bufofzeros,
-                               ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
-                               UIO_READ, auio, code);
-               }
-               /* pad out the difference between rlen and slen... */
-               if (NDIRSIZ_LEN(o_slen) < rlen) {
-                   while (NDIRSIZ_LEN(o_slen) < rlen) {
-                       int minLen = rlen - NDIRSIZ_LEN(o_slen);
-                       if (minLen > sizeof(bufofzeros))
-                           minLen = sizeof(bufofzeros);
-                       AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
-                       rlen -= minLen;
-                   }
-               }
-#else
-               code =
-                   afs_readdir_move(ode, avc, auio, o_slen,
-                                    auio->afsio_resid, origOffset);
-#endif /* AFS_HPUX_ENV */
-               auio->afsio_resid = 0;
-           } else {
-               /* nothin to hand over */
-           }
-#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
-           if (eofp)
-               *eofp = 1;
-#endif
-           if (ode)
-               DRelease(ode, 0);
-           goto dirend;
-       }
-       /* by here nde is set */
-
-       /* Do we have enough user space to carry out our mission? */
-#if defined(AFS_SGI_ENV)
-       n_slen = strlen(nde->name) + 1; /* NULL terminate */
-#else
-       n_slen = strlen(nde->name);
-#endif
-       if (NDIRSIZ_LEN(n_slen) >= (auio->afsio_resid - len)) {
-           /* No can do no more now; ya know... at this time */
-           DRelease(nde, 0);   /* can't use this one. */
-           if (len) {
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
-               sdirEntry->d_fileno =
-                   (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-               FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-               sdirEntry->d_reclen = rlen = auio->afsio_resid;
-               sdirEntry->d_namlen = o_slen;
-               sdirEntry->d_off = origOffset;
-               AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ,
-                           auio, code);
-               if (code == 0)
-                   AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
-               /* pad out the remaining characters with zeros */
-               if (code == 0) {
-                   AFS_UIOMOVE(bufofzeros,
-                               ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
-                               UIO_READ, auio, code);
-               }
-               /* pad out the difference between rlen and slen... */
-               if (NDIRSIZ_LEN(o_slen) < rlen) {
-                   while (NDIRSIZ_LEN(o_slen) < rlen) {
-                       int minLen = rlen - NDIRSIZ_LEN(o_slen);
-                       if (minLen > sizeof(bufofzeros))
-                           minLen = sizeof(bufofzeros);
-                       AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
-                       rlen -= minLen;
-                   }
-               }
-#else
-               code =
-                   afs_readdir_move(ode, avc, auio, o_slen,
-                                    auio->afsio_resid, origOffset);
-#endif /* AFS_HPUX_ENV */
-               /* this next line used to be AFSVFS40 or AIX 3.1, but is really generic */
-               auio->afsio_offset = origOffset;
-               auio->afsio_resid = 0;
-           } else {            /* trouble, can't give anything to the user! */
-               /* even though he has given us a buffer, 
-                * even though we have something to give us,
-                * Looks like we lost something somewhere.
-                */
-               code = EINVAL;
-           }
-           if (ode)
-               DRelease(ode, 0);
-           goto dirend;
-       }
-
-       /*
-        * In any event, we move out the LAST de entry, getting ready
-        * to set up for the next one.
-        */
-       if (len) {
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
-           sdirEntry->d_fileno =
-               (avc->fid.Fid.Volume << 16) + ntohl(ode->fid.vnode);
-           FIXUPSTUPIDINODE(sdirEntry->d_fileno);
-           sdirEntry->d_reclen = rlen = len;
-           sdirEntry->d_namlen = o_slen;
-           sdirEntry->d_off = origOffset;
-           AFS_UIOMOVE((char *)sdirEntry, sizeof(*sdirEntry), UIO_READ, auio,
-                       code);
-           if (code == 0)
-               AFS_UIOMOVE(ode->name, o_slen, UIO_READ, auio, code);
-           /* pad out the remaining characters with zeros */
-           if (code == 0) {
-               AFS_UIOMOVE(bufofzeros,
-                           ((o_slen + 1 + DIRPAD) & ~DIRPAD) - o_slen,
-                           UIO_READ, auio, code);
-           }
-           /* pad out the difference between rlen and slen... */
-           if (NDIRSIZ_LEN(o_slen) < rlen) {
-               while (NDIRSIZ_LEN(o_slen) < rlen) {
-                   int minLen = rlen - NDIRSIZ_LEN(o_slen);
-                   if (minLen > sizeof(bufofzeros))
-                       minLen = sizeof(bufofzeros);
-                   AFS_UIOMOVE(bufofzeros, minLen, UIO_READ, auio, code);
-                   rlen -= minLen;
-               }
-           }
-#else
-           code = afs_readdir_move(ode, avc, auio, o_slen, len, origOffset);
-#endif /* AFS_HPUX_ENV */
-       }
-       len = NDIRSIZ_LEN(o_slen = n_slen);
-       if (ode)
-           DRelease(ode, 0);
-       ode = nde;
-       auio->afsio_offset = ((us + afs_dir_NameBlobs(nde->name)) << 5);
-    }
-    if (ode)
-       DRelease(ode, 0);
-
-  dirend:
-    ReleaseReadLock(&tdc->lock);
-    afs_PutDCache(tdc);
-    ReleaseReadLock(&avc->lock);
-
-  done:
-#if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
-    osi_FreeSmallSpace((char *)sdirEntry);
-#endif
-    afs_PutFakeStat(&fakestate);
-    code = afs_CheckCode(code, &treq, 29);
+    code = afs_CheckCode(code, treq, 28);
+    afs_DestroyReq(treq);
     return code;
 }
 
-#endif
 #endif /* !AFS_LINUX20_ENV */