libafs: Remove afs_read duplication
[openafs.git] / src / afs / VNOPS / afs_vnop_read.c
index b63517e..dfdf343 100644 (file)
  * Implements:
  * afs_MemRead
  * afs_PrefetchChunk
- * afs_UFSReadFast
  * afs_UFSRead
  * 
  */
 
 #include <afsconfig.h>
-#include "../afs/param.h"
+#include "afs/param.h"
 
-RCSID("$Header$");
 
-#include "../afs/sysincludes.h"        /* Standard vendor system headers */
-#include "../afs/afsincludes.h"        /* Afs-based standard headers */
-#include "../afs/afs_stats.h" /* statistics */
-#include "../afs/afs_cbqueue.h"
-#include "../afs/nfsclient.h"
-#include "../afs/afs_osidnlc.h"
+#include "afs/sysincludes.h"   /* Standard vendor system headers */
+#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afs_stats.h"     /* statistics */
+#include "afs/afs_cbqueue.h"
+#include "afs/nfsclient.h"
+#include "afs/afs_osidnlc.h"
+#include "afs/afs_osi.h"
 
 
 extern char afs_zeros[AFS_ZEROS];
 
-afs_int32 maxIHint;
-afs_int32 nihints;                           /* # of above actually in-use */
-afs_int32 usedihint;
-
-
 /* Imported variables */
 extern afs_rwlock_t afs_xdcache;
 extern unsigned char *afs_indexFlags;
-extern afs_hyper_t *afs_indexTimes;          /* Dcache entry Access times */
-extern afs_hyper_t afs_indexCounter;         /* Fake time for marking index */
+extern afs_hyper_t *afs_indexTimes;    /* Dcache entry Access times */
+extern afs_hyper_t afs_indexCounter;   /* Fake time for marking index */
 
 
 /* Forward declarations */
 void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
-                             struct AFS_UCRED *acred, struct vrequest *areq);
-
-afs_MemRead(avc, auio, acred, albn, abpp, noLock)
-    register struct vcache *avc;
-    struct uio *auio;
-    struct AFS_UCRED *acred;
-    daddr_t albn;
-    int noLock;
-    struct buf **abpp; 
+                      afs_ucred_t *acred, struct vrequest *areq);
+
+int
+afs_read(struct vcache *avc, struct uio *auio, afs_ucred_t *acred,
+        daddr_t albn, struct buf **abpp, int noLock)
 {
     afs_size_t totalLength;
     afs_size_t transferLength;
     afs_size_t filePos;
     afs_size_t offset, len, tlen;
     afs_int32 trimlen;
-    struct dcache *tdc=0;
-    afs_int32 error, trybusy=1;
+    struct dcache *tdc = 0;
+    afs_int32 error, trybusy = 1;
+#ifdef AFS_DARWIN80_ENV
+    uio_t tuiop = NULL;
+#else
     struct uio tuio;
-    struct iovec *tvec;
-    char *tfile;
+    struct uio *tuiop = &tuio;
+    struct iovec *tvec = NULL;
+#endif
     afs_int32 code;
     struct vrequest treq;
 
-    AFS_STATCNT(afs_MemRead);
+    AFS_STATCNT(afs_read);
+
     if (avc->vc_error)
        return EIO;
 
+    AFS_DISCON_LOCK();
+
     /* check that we have the latest status info in the vnode cache */
-    if (code = afs_InitReq(&treq, acred)) return code;
+    if ((code = afs_InitReq(&treq, acred)))
+       goto out;
+
     if (!noLock) {
+       if (!avc)
+           osi_Panic("null avc in afs_GenericRead");
+
        code = afs_VerifyVCache(avc, &treq);
        if (code) {
-         code = afs_CheckCode(code, &treq, 8); /* failed to get it */
-         return code;
+           code = afs_CheckCode(code, &treq, 8);       /* failed to get it */
+           goto out;
        }
     }
-
 #ifndef        AFS_VM_RDWR_ENV
     if (AFS_NFSXLATORREQ(acred)) {
-       if (!afs_AccessOK(avc, PRSFS_READ, &treq,
-                         CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
-           return afs_CheckCode(EACCES, &treq, 9);
+       if (!afs_AccessOK
+           (avc, PRSFS_READ, &treq,
+            CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
+           code = afs_CheckCode(EACCES, &treq, 9);
+           goto out;
        }
     }
 #endif
 
-    tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
-    totalLength = auio->afsio_resid;
-    filePos = auio->afsio_offset;
-    afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
-               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
-               ICL_TYPE_INT32, totalLength,
-               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
+#ifndef AFS_DARWIN80_ENV
+    tvec = osi_AllocSmallSpace(sizeof(struct iovec));
+#endif
+    totalLength = AFS_UIO_RESID(auio);
+    filePos = AFS_UIO_OFFSET(auio);
+    afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc,
+              ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos), ICL_TYPE_INT32,
+              totalLength, ICL_TYPE_OFFSET,
+              ICL_HANDLE_OFFSET(avc->f.m.Length));
     error = 0;
     transferLength = 0;
     if (!noLock)
        ObtainReadLock(&avc->lock);
 #if    defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
     if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
-       hset(avc->flushDV, avc->m.DataVersion);
+       hset(avc->flushDV, avc->f.m.DataVersion);
     }
 #endif
-    while (totalLength > 0) {
+
+    /*
+     * Locks held:
+     * avc->lock(R)
+     */
+    if (filePos >= avc->f.m.Length) {
+       if (len > AFS_ZEROS)
+           len = sizeof(afs_zeros);    /* and in 0 buffer */
+       len = 0;
+#ifdef AFS_DARWIN80_ENV
+       trimlen = len;
+       tuiop = afsio_darwin_partialcopy(auio, trimlen);
+#else
+       afsio_copy(auio, &tuio, tvec);
+       trimlen = len;
+       afsio_trim(&tuio, trimlen);
+#endif
+       AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
+    }
+
+    while (avc->f.m.Length > 0 && totalLength > 0) {
        /* read all of the cached info */
-       if (filePos >= avc->m.Length) break;    /* all done */
+       if (filePos >= avc->f.m.Length)
+           break;              /* all done */
        if (noLock) {
-           if (tdc) afs_PutDCache(tdc);
+           if (tdc) {
+               ReleaseReadLock(&tdc->lock);
+               afs_PutDCache(tdc);
+           }
            tdc = afs_FindDCache(avc, filePos);
            if (tdc) {
+               ObtainReadLock(&tdc->lock);
                offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
-               len = tdc->f.chunkBytes - offset;
+               len = tdc->validPos - filePos;
            }
        } else {
            /* a tricky question: does the presence of the DFFetching flag
-              mean that we're fetching the latest version of the file?  No.
-              The server could update the file as soon as the fetch responsible
-              for the setting of the DFFetching flag completes.
-           
-              However, the presence of the DFFetching flag (visible under a
-              read lock since it is set and cleared only under a write lock)
-              means that we're fetching as good a version as was known to this
-              client at the time of the last call to afs_VerifyVCache, since
-              the latter updates the stat cache's m.DataVersion field under a
-              write lock, and from the time that the DFFetching flag goes on
-              (before the fetch starts), to the time it goes off (after the
-              fetch completes), afs_GetDCache keeps at least a read lock
-              (actually it keeps an S lock) on the cache entry.
-           
-              This means that if the DFFetching flag is set, we can use that
-              data for any reads that must come from the current version of
-              the file (current == m.DataVersion).
-            
-              Another way of looking at this same point is this: if we're
-              fetching some data and then try do an afs_VerifyVCache, the
-              VerifyVCache operation will not complete until after the
-              DFFetching flag is turned off and the dcache entry's f.versionNo
-              field is updated.
-            
-              Note, by the way, that if DFFetching is set,
-              m.DataVersion > f.versionNo (the latter is not updated until
-              after the fetch completes).
+            * mean that we're fetching the latest version of the file?  No.
+            * The server could update the file as soon as the fetch responsible
+            * for the setting of the DFFetching flag completes.
+            * 
+            * However, the presence of the DFFetching flag (visible under
+            * a dcache read lock since it is set and cleared only under a
+            * dcache write lock) means that we're fetching as good a version
+            * as was known to this client at the time of the last call to
+            * afs_VerifyVCache, since the latter updates the stat cache's
+            * m.DataVersion field under a vcache write lock, and from the
+            * time that the DFFetching flag goes on in afs_GetDCache (before
+            * the fetch starts), to the time it goes off (after the fetch
+            * completes), afs_GetDCache keeps at least a read lock on the
+            * vcache entry.
+            * 
+            * This means that if the DFFetching flag is set, we can use that
+            * data for any reads that must come from the current version of
+            * the file (current == m.DataVersion).
+            * 
+            * Another way of looking at this same point is this: if we're
+            * fetching some data and then try do an afs_VerifyVCache, the
+            * VerifyVCache operation will not complete until after the
+            * DFFetching flag is turned off and the dcache entry's f.versionNo
+            * field is updated.
+            * 
+            * Note, by the way, that if DFFetching is set,
+            * m.DataVersion > f.versionNo (the latter is not updated until
+            * after the fetch completes).
             */
-           if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
+           if (tdc) {
+               ReleaseReadLock(&tdc->lock);
+               afs_PutDCache(tdc);     /* before reusing tdc */
+           }
            tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
+           if (!tdc) {
+               error = ENETDOWN;
+               break;
+           }
+
+           ObtainReadLock(&tdc->lock);
            /* now, first try to start transfer, if we'll need the data.  If
             * data already coming, we don't need to do this, obviously.  Type
             * 2 requests never return a null dcache entry, btw.
             */
-           if (!(tdc->flags & DFFetching)
-               && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
+           if (!(tdc->dflags & DFFetching)
+               && !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
                /* have cache entry, it is not coming in now,
                 * and we'll need new data */
-tagain:
+             tagain:
                if (trybusy && !afs_BBusy()) {
                    struct brequest *bp;
                    /* daemon is not busy */
-                   if (!(tdc->flags & DFFetchReq)) {
+                   ObtainSharedLock(&tdc->mflock, 665);
+                   if (!(tdc->mflags & DFFetchReq)) {
                        /* start the daemon (may already be running, however) */
-                       tdc->flags |= DFFetchReq;
+                       UpgradeSToWLock(&tdc->mflock, 666);
+                       tdc->mflags |= DFFetchReq;
                        bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
-                                       (afs_size_t)filePos, (afs_size_t) 0,
-                                       tdc);
+                                       (afs_size_t) filePos, (afs_size_t) 0,
+                                       tdc, NULL, NULL);
                        if (!bp) {
-                           tdc->flags &= ~DFFetchReq;
+                           /* Bkg table full; retry deadlocks */
+                           tdc->mflags &= ~DFFetchReq;
                            trybusy = 0;        /* Avoid bkg daemon since they're too busy */
+                           ReleaseWriteLock(&tdc->mflock);
                            goto tagain;
                        }
+                       ConvertWToSLock(&tdc->mflock);
                        /* don't use bp pointer! */
                    }
-                   while (tdc->flags & DFFetchReq) {
+                   code = 0;
+                   ConvertSToRLock(&tdc->mflock);
+                   while (!code && tdc->mflags & DFFetchReq) {
+                       afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
+                                  ICL_TYPE_STRING, __FILE__, ICL_TYPE_INT32,
+                                  __LINE__, ICL_TYPE_POINTER, tdc,
+                                  ICL_TYPE_INT32, tdc->dflags);
                        /* don't need waiting flag on this one */
+                       ReleaseReadLock(&tdc->mflock);
+                       ReleaseReadLock(&tdc->lock);
                        ReleaseReadLock(&avc->lock);
-                       afs_osi_Sleep(&tdc->validPos);
+                       code = afs_osi_SleepSig(&tdc->validPos);
                        ObtainReadLock(&avc->lock);
+                       ObtainReadLock(&tdc->lock);
+                       ObtainReadLock(&tdc->mflock);
+                   }
+                   ReleaseReadLock(&tdc->mflock);
+                   if (code) {
+                       error = code;
+                       break;
                    }
                }
            }
            /* now data may have started flowing in (if DFFetching is on).  If
-            * data is now streaming in, then wait for some interesting stuff. */
-           while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
-               /* too early: wait for DFFetching flag to vanish, or data to appear */
-               afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
-                               ICL_TYPE_STRING, __FILE__,
-                               ICL_TYPE_INT32, __LINE__,
-                               ICL_TYPE_POINTER, tdc,
-                               ICL_TYPE_INT32, tdc->flags);
-               tdc->flags |= DFWaiting;
+            * data is now streaming in, then wait for some interesting stuff.
+            */
+           code = 0;
+           while (!code && (tdc->dflags & DFFetching)
+                  && tdc->validPos <= filePos) {
+               /* too early: wait for DFFetching flag to vanish,
+                * or data to appear */
+               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);
+               code = afs_osi_SleepSig(&tdc->validPos);
                ObtainReadLock(&avc->lock);
+               ObtainReadLock(&tdc->lock);
            }
-           /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
-           if (tdc->flags & DFFetching) {
-               /* still fetching, some new data is here: compute length and offset */
+           if (code) {
+               error = code;
+               break;
+           }
+           /* fetching flag gone, data is here, or we never tried 
+            * (BBusy for instance) */
+           if (tdc->dflags & DFFetching) {
+               /* still fetching, some new data is here: 
+                * compute length and offset */
                offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
                len = tdc->validPos - filePos;
-           }
-           else {
-               /* no longer fetching, verify data version (avoid new GetDCache call) */
-               if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
+           } else {
+               /* no longer fetching, verify data version 
+                * (avoid new GetDCache call) */
+               if (hsame(avc->f.m.DataVersion, tdc->f.versionNo)
+                   && ((len = tdc->validPos - filePos) > 0)) {
                    offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
-                   len = tdc->f.chunkBytes - offset;
-               }
-               else {
+               } else {
                    /* don't have current data, so get it below */
+                   afs_Trace3(afs_iclSetp, CM_TRACE_VERSIONNO,
+                              ICL_TYPE_INT64, ICL_HANDLE_OFFSET(filePos),
+                              ICL_TYPE_HYPER, &avc->f.m.DataVersion,
+                              ICL_TYPE_HYPER, &tdc->f.versionNo);
+                   ReleaseReadLock(&tdc->lock);
                    afs_PutDCache(tdc);
-                   tdc = (struct dcache *) 0;
+                   tdc = NULL;
                }
            }
 
            if (!tdc) {
+               /* If we get, it was not possible to start the
+                * background daemon. With flag == 1 afs_GetDCache
+                * does the FetchData rpc synchronously.
+                */
                ReleaseReadLock(&avc->lock);
                tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
                ObtainReadLock(&avc->lock);
+               if (tdc)
+                   ObtainReadLock(&tdc->lock);
            }
        }
 
+       afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD, ICL_TYPE_POINTER, tdc,
+                  ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
+                  ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
        if (!tdc) {
            error = EIO;
            break;
        }
-       if (len > totalLength) len = totalLength;   /* will read len bytes */
-       if (len <= 0) { /* shouldn't get here if DFFetching is on */
+
+       /*
+        * Locks held:
+        * avc->lock(R)
+        * tdc->lock(R)
+        */
+
+       if (len > totalLength)
+           len = totalLength;  /* will read len bytes */
+       if (len <= 0) {         /* shouldn't get here if DFFetching is on */
            /* read past the end of a chunk, may not be at next chunk yet, and yet
-               also not at eof, so may have to supply fake zeros */
-           len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
-           if (len > totalLength) len = totalLength;   /* and still within xfr request */
-           tlen = avc->m.Length - offset; /* and still within file */ 
-           if (len > tlen) len = tlen;
-           if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
+            * also not at eof, so may have to supply fake zeros */
+           len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset;       /* bytes left in chunk addr space */
+           if (len > totalLength)
+               len = totalLength;      /* and still within xfr request */
+           tlen = avc->f.m.Length - offset;    /* and still within file */
+           if (len > tlen)
+               len = tlen;
+           if (len > AFS_ZEROS)
+               len = sizeof(afs_zeros);        /* and in 0 buffer */
+#ifdef AFS_DARWIN80_ENV
+           trimlen = len;
+            tuiop = afsio_darwin_partialcopy(auio, trimlen);
+#else
            afsio_copy(auio, &tuio, tvec);
            trimlen = len;
            afsio_trim(&tuio, trimlen);
-           AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
+#endif
+           AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, tuiop, code);
            if (code) {
                error = code;
                break;
            }
-       }
-       else {
-           /* get the data from the mem cache */
+       } else {
+           /* get the data from the cache */
 
            /* mung uio structure to be right for this transfer */
+#ifdef AFS_DARWIN80_ENV
+           trimlen = len;
+            tuiop = afsio_darwin_partialcopy(auio, trimlen);
+           uio_setoffset(tuiop, offset);
+#else
            afsio_copy(auio, &tuio, tvec);
            trimlen = len;
            afsio_trim(&tuio, trimlen);
            tuio.afsio_offset = offset;
+#endif
 
-           code = afs_MemReadUIO(tdc->f.inode, &tuio);
+           code = (*(afs_cacheType->vreadUIO))(&tdc->f.inode, tuiop);
 
            if (code) {
                error = code;
@@ -261,34 +365,59 @@ tagain:
            }
        }
        /* otherwise we've read some, fixup length, etc and continue with next seg */
-       len = len - tuio.afsio_resid; /* compute amount really transferred */
+       len = len - AFS_UIO_RESID(tuiop);       /* compute amount really transferred */
        trimlen = len;
-       afsio_skip(auio, trimlen);          /* update input uio structure */
+       afsio_skip(auio, trimlen);      /* update input uio structure */
        totalLength -= len;
        transferLength += len;
        filePos += len;
 
-       if (len <= 0) break;    /* surprise eof */
-    }  /* the whole while loop */
+       if (len <= 0)
+           break;              /* surprise eof */
+#ifdef AFS_DARWIN80_ENV
+       if (tuiop) {
+           uio_free(tuiop);
+           tuiop = 0;
+       }
+#endif
+    }                          /* the whole while loop */
+
+    /*
+     * Locks held:
+     * avc->lock(R)
+     * tdc->lock(R) if tdc
+     */
 
     /* if we make it here with tdc non-zero, then it is the last chunk we
      * dealt with, and we have to release it when we're done.  We hold on
      * to it in case we need to do a prefetch.
      */
     if (tdc) {
-#ifndef        AFS_VM_RDWR_ENV
+       ReleaseReadLock(&tdc->lock);
+#if !defined(AFS_VM_RDWR_ENV)
        /* try to queue prefetch, if needed */
-       if (!(tdc->flags & DFNextStarted) && !noLock) {
-           afs_PrefetchChunk(avc, tdc, acred, &treq);
+       if (!noLock) {
+           if (!(tdc->mflags &DFNextStarted))
+               afs_PrefetchChunk(avc, tdc, acred, &treq);
        }
 #endif
        afs_PutDCache(tdc);
     }
     if (!noLock)
        ReleaseReadLock(&avc->lock);
+
+    code = afs_CheckCode(error, &treq, 10);
+
+#ifdef AFS_DARWIN80_ENV
+    if (tuiop)
+       uio_free(tuiop);
+#else
     osi_FreeSmallSpace(tvec);
-    error = afs_CheckCode(error, &treq, 10);
-    return error;
+#endif
+
+out:
+    AFS_DISCON_UNLOCK();
+    return code;
 }
 
 /* called with the dcache entry triggering the fetch, the vcache entry involved,
@@ -297,450 +426,104 @@ tagain:
  * flag in the prefetched block, so that the next call to read knows to wait
  * for the daemon to start doing things.
  *
- * This function must be called with the vnode at least read-locked
- * because it plays around with dcache entries.
+ * This function must be called with the vnode at least read-locked, and
+ * no locks on the dcache, because it plays around with dcache entries.
  */
-void afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
-                             struct AFS_UCRED *acred, struct vrequest *areq)
+void
+afs_PrefetchChunk(struct vcache *avc, struct dcache *adc,
+                 afs_ucred_t *acred, struct vrequest *areq)
 {
-    register struct dcache *tdc;
+    struct dcache *tdc;
     afs_size_t offset;
-    afs_size_t j1, j2; /* junk vbls for GetDCache to trash */
-
-    offset = adc->f.chunk+1;           /* next chunk we'll need */
-    offset = AFS_CHUNKTOBASE(offset);   /* base of next chunk */
-    if (offset < avc->m.Length && !afs_BBusy()) {
+    afs_size_t j1, j2;         /* junk vbls for GetDCache to trash */
+
+    offset = adc->f.chunk + 1; /* next chunk we'll need */
+    offset = AFS_CHUNKTOBASE(offset);  /* base of next chunk */
+    ObtainReadLock(&adc->lock);
+    ObtainSharedLock(&adc->mflock, 662);
+    if (offset < avc->f.m.Length && !(adc->mflags & DFNextStarted)
+       && !afs_BBusy()) {
        struct brequest *bp;
-       adc->flags |= DFNextStarted;    /* we've tried to prefetch for this guy */
+
+       UpgradeSToWLock(&adc->mflock, 663);
+       adc->mflags |= DFNextStarted;   /* we've tried to prefetch for this guy */
+       ReleaseWriteLock(&adc->mflock);
+       ReleaseReadLock(&adc->lock);
+
        tdc = afs_GetDCache(avc, offset, areq, &j1, &j2, 2);    /* type 2 never returns 0 */
-       if (!(tdc->flags & DFFetchReq)) {
+        /*
+         * In disconnected mode, type 2 can return 0 because it doesn't
+         * make any sense to allocate a dcache we can never fill
+         */
+         if (tdc == NULL)
+             return;
+
+       ObtainSharedLock(&tdc->mflock, 651);
+       if (!(tdc->mflags & DFFetchReq)) {
            /* ask the daemon to do the work */
-           tdc->flags |= DFFetchReq;   /* guaranteed to be cleared by BKG or GetDCache */
+           UpgradeSToWLock(&tdc->mflock, 652);
+           tdc->mflags |= DFFetchReq;  /* guaranteed to be cleared by BKG or GetDCache */
            /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done,
             * since we don't want to wait for it to finish before doing so ourselves.
             */
-#ifdef AFS_SUN5_ENVX
-           mutex_exit(&tdc->lock);
-#endif
-            bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
-                               (afs_size_t) offset, (afs_size_t) 1, tdc);
+           bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
+                           (afs_size_t) offset, (afs_size_t) 1, tdc,
+                           (void *)0, (void *)0);
            if (!bp) {
                /* Bkg table full; just abort non-important prefetching to avoid deadlocks */
-               tdc->flags &= ~(DFNextStarted | DFFetchReq);
+               tdc->mflags &= ~DFFetchReq;
+               ReleaseWriteLock(&tdc->mflock);
                afs_PutDCache(tdc);
-               return;
-           }
-       }
-       else
-           afs_PutDCache(tdc);
-    }
-}
-
-
-/* if the vcache is up-to-date, and the request fits entirely into the chunk
- * that the hint here references, then we just use it quickly, otherwise we
- * have to call the slow read.
- *
- * This could be generalized in several ways to take advantage of partial 
- * state even when all the chips don't fall the right way.  For instance,
- * if the hint is good and the first part of the read request can be 
- * satisfied from the chunk, then just do the read.  After the read has
- * completed, check to see if there's more. (Chances are there won't be.)
- * If there is more, then just call afs_UFSReadSlow and let it do the rest.
- *
- * For the time being, I'm ignoring quick.f, but it should be used at
- * some future date.
- * do this in the future avc->quick.f = tfile; but I think it
- * has to be done under a write lock, but don't want to wait on the
- * write lock
- */
-    /* everywhere that a dcache can be freed (look for NULLIDX) 
-     * probably does it under a write lock on xdcache.  Need to invalidate
-     * stamp there, too.  
-     * Also need to worry about DFFetching, and IFFree, I think. */
-static struct dcache *savedc = 0;
-
-afs_UFSReadFast(avc, auio, acred, albn, abpp, noLock)
-    register struct vcache *avc;
-    struct uio *auio;
-    struct AFS_UCRED *acred;
-    int noLock;
-    daddr_t albn;
-    struct buf **abpp; 
-{
-    struct vrequest treq;
-    int offDiff;
-    struct dcache *tdc;
-    struct vnode *vp;
-    struct osi_file *tfile;
-    afs_int32 code = 0;
-
-    if (!noLock)
-       ObtainReadLock(&avc->lock);  
-    ObtainReadLock(&afs_xdcache);
-
-    if ((avc->states & CStatd)                                /* up to date */
-       && (tdc = avc->quick.dc) && (tdc->index != NULLIDX) 
-       && !(afs_indexFlags[tdc->index] & IFFree))   {
-
-       tdc->refCount++;
-       ReleaseReadLock(&afs_xdcache);
-
-       if ((tdc->stamp == avc->quick.stamp)                /* hint matches */
-           && ((offDiff = (auio->afsio_offset - avc->quick.minLoc)) >= 0)
-           && (tdc->f.chunkBytes >= auio->afsio_resid + offDiff)
-           && !(tdc->flags & DFFetching)) { /* fits in chunk */
-
-           auio->afsio_offset -= avc->quick.minLoc;
-
-           afs_Trace4(afs_iclSetp, CM_TRACE_READFAST, ICL_TYPE_POINTER, avc,
-                       ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(auio->afsio_offset),
-                       ICL_TYPE_INT32, auio->afsio_resid,
-                       ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
-
-           tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
-
-#ifdef AFS_AIX_ENV
-#ifdef AFS_AIX41_ENV
-           AFS_GUNLOCK();
-           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL, NULL, &afs_osi_cred);
-           AFS_GLOCK();
-#else
-#ifdef AFS_AIX32_ENV
-           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, auio, NULL, NULL);
-#else
-           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&auio->afsio_offset, auio, NULL, NULL, -1);
-#endif
-#endif
-#else
-#ifdef AFS_SUN5_ENV
-           AFS_GUNLOCK();
-           VOP_RWLOCK(tfile->vnode, 0);
-           code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
-           VOP_RWUNLOCK(tfile->vnode, 0);
-           AFS_GLOCK();
-#else
-#if defined(AFS_SGI_ENV)
-            AFS_GUNLOCK();
-            AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
-            AFS_VOP_READ(tfile->vnode, auio, IO_ISLOCKED, &afs_osi_cred, code);
-            AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
-            AFS_GLOCK();
-#else
-#ifdef AFS_OSF_ENV
-           auio->uio_rw = UIO_READ;
-           AFS_GUNLOCK();
-           VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred, code);
-           AFS_GLOCK();
-#else  /* AFS_OSF_ENV */
-#if defined(AFS_HPUX100_ENV)
-           AFS_GUNLOCK();
-           code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
-            AFS_GLOCK();
-#else
-#if defined(AFS_LINUX20_ENV)
-           AFS_GUNLOCK();
-           code = osi_file_uio_rdwr(tfile, auio, UIO_READ);
-           AFS_GLOCK();
-#else
-#if defined(AFS_DARWIN_ENV)
-            AFS_GUNLOCK();
-            VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
-            code = VOP_READ(tfile->vnode, auio, 0, &afs_osi_cred);
-            VOP_UNLOCK(tfile->vnode, 0, current_proc());
-            AFS_GLOCK();
-#else
-           code = VOP_RDWR(tfile->vnode, auio, UIO_READ, 0, &afs_osi_cred);
-#endif
-#endif
-#endif
-#endif
-#endif
-#endif
-#endif
-           auio->afsio_offset += avc->quick.minLoc;
-           osi_UFSClose(tfile);
-           /* Fix up LRU info */
-           hset(afs_indexTimes[tdc->index], afs_indexCounter);
-           hadd32(afs_indexCounter, 1);
 
-           if (!noLock) {
-#ifndef        AFS_VM_RDWR_ENV
-               if (!(code = afs_InitReq(&treq, acred))&& (!(tdc->flags & DFNextStarted)))
-                   afs_PrefetchChunk(avc, tdc, acred, &treq);
-#endif
-               ReleaseReadLock(&avc->lock);
+               /*
+                * DCLOCKXXX: This is a little sketchy, since someone else
+                * could have already started a prefetch..  In practice,
+                * this probably doesn't matter; at most it would cause an
+                * extra slot in the BKG table to be used up when someone
+                * prefetches this for the second time.
+                */
+               ObtainReadLock(&adc->lock);
+               ObtainWriteLock(&adc->mflock, 664);
+               adc->mflags &= ~DFNextStarted;
+               ReleaseWriteLock(&adc->mflock);
+               ReleaseReadLock(&adc->lock);
+           } else {
+               ReleaseWriteLock(&tdc->mflock);
            }
-           tdc->refCount--;
-           return (code);
-       }
-       if (!tdc->f.chunkBytes) {   /* debugging f.chunkBytes == 0 problem */
-           savedc = tdc;
+       } else {
+           ReleaseSharedLock(&tdc->mflock);
+           afs_PutDCache(tdc);
        }
-       tdc->refCount--;
     } else {
-       ReleaseReadLock(&afs_xdcache);
+       ReleaseSharedLock(&adc->mflock);
+       ReleaseReadLock(&adc->lock);
     }
-
-    /* come here if fast path doesn't work for some reason or other */
-    if (!noLock)
-       ReleaseReadLock(&avc->lock);
-    return afs_UFSRead(avc, auio, acred, albn, abpp, noLock);
 }
 
-afs_UFSRead(avc, auio, acred, albn, abpp, noLock)
-    struct vcache *avc;
-    struct uio *auio;
-    struct AFS_UCRED *acred;
-    daddr_t albn;
-    int noLock;
-    struct buf **abpp; 
+int
+afs_UFSReadUIO(afs_dcache_id_t *cacheId, struct uio *tuiop)
 {
-    afs_size_t totalLength;
-    afs_size_t transferLength;
-    afs_size_t filePos;
-    afs_size_t offset, len, tlen;
-    afs_int32 trimlen;
-    struct dcache *tdc=0;
-    afs_int32 error;
-    struct uio tuio;
-    struct iovec *tvec;
+    int code;
     struct osi_file *tfile;
-    afs_int32 code;
-    int munlocked, trybusy=1;
-    struct vnode *vp;
-    struct vrequest treq;
-
-    AFS_STATCNT(afs_UFSRead);
-    if (avc->vc_error)
-       return EIO;
-
-    /* check that we have the latest status info in the vnode cache */
-    if (code = afs_InitReq(&treq, acred)) return code;
-    if (!noLock) {
-      if (!avc) 
-       osi_Panic ("null avc in afs_UFSRead");
-      else {
-       code = afs_VerifyVCache(avc, &treq);
-       if (code) {
-         code = afs_CheckCode(code, &treq, 11); /* failed to get it */
-         return code;
-       }
-      }
-    }
 
-#ifndef        AFS_VM_RDWR_ENV
-    if (AFS_NFSXLATORREQ(acred)) {
-       if (!afs_AccessOK(avc, PRSFS_READ, &treq,
-                         CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
-           return afs_CheckCode(EACCES, &treq, 12);
-       }
-    }
-#endif
-
-    tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
-    totalLength = auio->afsio_resid;
-    filePos = auio->afsio_offset;
-    afs_Trace4(afs_iclSetp, CM_TRACE_READ, ICL_TYPE_POINTER, avc, 
-               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
-               ICL_TYPE_INT32, totalLength,
-               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
-    error = 0;
-    transferLength = 0;
-    if (!noLock)
-       ObtainReadLock(&avc->lock);
-#if    defined(AFS_TEXT_ENV) && !defined(AFS_VM_RDWR_ENV)
-    if (avc->flushDV.high == AFS_MAXDV && avc->flushDV.low == AFS_MAXDV) {
-       hset(avc->flushDV, avc->m.DataVersion);
-    }
-#endif
-    
-    while (totalLength > 0) {
-       /* read all of the cached info */
-       if (filePos >= avc->m.Length) break;    /* all done */
-       if (noLock) {
-           if (tdc) afs_PutDCache(tdc);
-           tdc = afs_FindDCache(avc, filePos);
-           if (tdc) {
-               offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
-               len = tdc->f.chunkBytes - offset;
-           }
-       } else {
-           /* a tricky question: does the presence of the DFFetching flag
-              mean that we're fetching the latest version of the file?  No.
-              The server could update the file as soon as the fetch responsible
-              for the setting of the DFFetching flag completes.
-           
-              However, the presence of the DFFetching flag (visible under a
-              read lock since it is set and cleared only under a write lock)
-              means that we're fetching as good a version as was known to this
-              client at the time of the last call to afs_VerifyVCache, since
-              the latter updates the stat cache's m.DataVersion field under a
-              write lock, and from the time that the DFFetching flag goes on
-              (before the fetch starts), to the time it goes off (after the
-              fetch completes), afs_GetDCache keeps at least a read lock
-              (actually it keeps an S lock) on the cache entry.
-           
-              This means that if the DFFetching flag is set, we can use that
-              data for any reads that must come from the current version of
-              the file (current == m.DataVersion).
-            
-              Another way of looking at this same point is this: if we're
-              fetching some data and then try do an afs_VerifyVCache, the
-              VerifyVCache operation will not complete until after the
-              DFFetching flag is turned off and the dcache entry's f.versionNo
-              field is updated.
-            
-              Note, by the way, that if DFFetching is set,
-              m.DataVersion > f.versionNo (the latter is not updated until
-              after the fetch completes).
-            */
-           if (tdc) afs_PutDCache(tdc);        /* before reusing tdc */
-           munlocked = 0;
-           tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 2);
-           if (tdc == savedc) {
-               savedc = 0;
-           }
-           /* now, first try to start transfer, if we'll need the data.  If
-            * data already coming, we don't need to do this, obviously.  Type
-            * 2 requests never return a null dcache entry, btw. */
-           if (!(tdc->flags & DFFetching)
-               && !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
-               /* have cache entry, it is not coming in now, and we'll need new data */
-tagain:
-               if (trybusy && !afs_BBusy()) {
-                   struct brequest *bp;
-                   /* daemon is not busy */
-                   if (!(tdc->flags & DFFetchReq)) {
-                       tdc->flags |= DFFetchReq;
-#ifdef AFS_SUN5_ENVX
-                       mutex_exit(&tdc->lock);
-                       munlocked = 1;
-#endif
-                       bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
-                                       (afs_size_t)filePos, (afs_size_t) 0,
-                                       tdc);
-                       if (!bp) {
-                           /* Bkg table full; retry deadlocks */
-                           tdc->flags &= ~DFFetchReq;
-                           trybusy = 0;        /* Avoid bkg daemon since they're too busy */
-                           goto tagain;
-                       }
-                   }
-                   while (tdc->flags & DFFetchReq) {
-                       /* don't need waiting flag on this one */
-                       ReleaseReadLock(&avc->lock);
-                       afs_osi_Sleep(&tdc->validPos);
-                       ObtainReadLock(&avc->lock);
-                   }
-               }
-           }
-           /* now data may have started flowing in (if DFFetching is on).  If
-            * data is now streaming in, then wait for some interesting stuff. */
-           while ((tdc->flags & DFFetching) && tdc->validPos <= filePos) {
-               /* too early: wait for DFFetching flag to vanish, or data to appear */
-               afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
-                               ICL_TYPE_STRING, __FILE__,
-                               ICL_TYPE_INT32, __LINE__,
-                               ICL_TYPE_POINTER, tdc,
-                               ICL_TYPE_INT32, tdc->flags);
-               tdc->flags |= DFWaiting;
-               ReleaseReadLock(&avc->lock);
-               afs_osi_Sleep(&tdc->validPos);
-               ObtainReadLock(&avc->lock);
-           }
-           /* fetching flag gone, data is here, or we never tried (BBusy for instance) */
-           if (tdc->flags & DFFetching) {
-               /* still fetching, some new data is here: compute length and offset */
-               offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
-               len = tdc->validPos - filePos;
-           }
-           else {
-               /* no longer fetching, verify data version (avoid new GetDCache call) */
-               if (hsame(avc->m.DataVersion, tdc->f.versionNo)) {
-                   offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
-                   len = tdc->f.chunkBytes - offset;
-               }
-               else {
-                   /* don't have current data, so get it below */
-                   afs_PutDCache(tdc);
-                   tdc = (struct dcache *) 0;
-               }
-           }
-
-           if (!tdc) {
-               ReleaseReadLock(&avc->lock);
-               tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 1);
-               ObtainReadLock(&avc->lock);
-           }
-       }
-       
-       afs_Trace3(afs_iclSetp, CM_TRACE_VNODEREAD,
-                       ICL_TYPE_POINTER, tdc,
-                       ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(offset),
-                       ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(len));
-       if (!tdc) {
-           error = EIO;
-           break;
-       }
-       if (len > totalLength) len = totalLength;   /* will read len bytes */
-       if (len <= 0) { /* shouldn't get here if DFFetching is on */
-           /* read past the end of a chunk, may not be at next chunk yet, and yet
-               also not at eof, so may have to supply fake zeros */
-           len = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; /* bytes left in chunk addr space */
-           if (len > totalLength) len = totalLength;   /* and still within xfr request */
-           tlen = avc->m.Length - offset; /* and still within file */
-           if (len > tlen) len = tlen;
-           if (len > AFS_ZEROS) len = sizeof(afs_zeros);   /* and in 0 buffer */
-           afsio_copy(auio, &tuio, tvec);
-           trimlen = len;
-           afsio_trim(&tuio, trimlen);
-           AFS_UIOMOVE(afs_zeros, trimlen, UIO_READ, &tuio, code);
-           if (code) {
-               error = code;
-               break;
-           }
-       }
-       else {
-           /* get the data from the file */
-#ifdef IHINT
-         if (tfile = tdc->ihint) {
-             if (tdc->f.inode != tfile->inum){ 
-                    afs_warn( "afs_UFSRead: %x hint mismatch tdc %d inum %d\n",
-                        tdc, tdc->f.inode, tfile->inum );
-                    osi_UFSClose(tfile);
-                   tdc->ihint = tfile = 0;
-                   nihints--;
-                 }
-          }
-         if (tfile != 0) {
-           usedihint++;
-         }
-         else
-#endif /* IHINT */
-
-           tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
-           /* mung uio structure to be right for this transfer */
-           afsio_copy(auio, &tuio, tvec);
-           trimlen = len;
-           afsio_trim(&tuio, trimlen);
-           tuio.afsio_offset = offset;
-#ifdef AFS_AIX_ENV
-#ifdef AFS_AIX41_ENV
-         AFS_GUNLOCK();
-         code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL,
-                          NULL, &afs_osi_cred);
-         AFS_GLOCK();
-#else
-#ifdef AFS_AIX32_ENV
-           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, &tuio, NULL, NULL);
-         /* Flush all JFS pages now for big performance gain in big file cases
-          * If we do something like this, must check to be sure that AFS file 
-          * isn't mmapped... see afs_gn_map() for why.
-         */
-/*
-         if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
- many different ways to do similar things:
+    tfile = (struct osi_file *) osi_UFSOpen(cacheId);
+
+#if defined(AFS_AIX41_ENV)
+    AFS_GUNLOCK();
+    code =
+       VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, tuiop, NULL, NULL,
+                 NULL, afs_osi_credp);
+    AFS_GLOCK();
+#elif defined(AFS_AIX32_ENV)
+    code =
+       VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, tuiop, NULL, NULL);
+    /* Flush all JFS pages now for big performance gain in big file cases
+     * If we do something like this, must check to be sure that AFS file
+     * isn't mmapped... see afs_gn_map() for why.
+     */
+    /*
+   if (tfile->vnode->v_gnode && tfile->vnode->v_gnode->gn_seg) {
+   any different ways to do similar things:
    so far, the best performing one is #2, but #1 might match it if we
    straighten out the confusion regarding which pages to flush.  It 
    really does matter.
@@ -758,103 +541,78 @@ tagain:
                        (len + PAGESIZE-1)/PAGESIZE);
          }     
 */
+#elif defined(AFS_AIX_ENV)
+    code =
+       VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t) & offset,
+                 tuiop, NULL, NULL, -1);
+#elif defined(AFS_SUN5_ENV)
+    AFS_GUNLOCK();
+#ifdef AFS_SUN510_ENV
+    {
+       caller_context_t ct;
+       VOP_RWLOCK(tfile->vnode, 0, &ct);
+       code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp, &ct);
+       VOP_RWUNLOCK(tfile->vnode, 0, &ct);
+    }
 #else
-           code = VNOP_RDWR(tfile->vnode, UIO_READ, FREAD, (off_t)&offset, &tuio, NULL, NULL, -1);
-#endif
+    VOP_RWLOCK(tfile->vnode, 0);
+    code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp);
+    VOP_RWUNLOCK(tfile->vnode, 0);
 #endif
+    AFS_GLOCK();
+#elif defined(AFS_SGI_ENV)
+    AFS_GUNLOCK();
+    AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
+    AFS_VOP_READ(tfile->vnode, tuiop, IO_ISLOCKED, afs_osi_credp,
+                code);
+    AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
+    AFS_GLOCK();
+#elif defined(AFS_HPUX100_ENV)
+    AFS_GUNLOCK();
+    code = VOP_RDWR(tfile->vnode, tuiop, UIO_READ, 0, afs_osi_credp);
+    AFS_GLOCK();
+#elif defined(AFS_LINUX20_ENV)
+    AFS_GUNLOCK();
+    code = osi_rdwr(tfile, tuiop, UIO_READ);
+    AFS_GLOCK();
+#elif defined(AFS_DARWIN80_ENV)
+    AFS_GUNLOCK();
+    code = VNOP_READ(tfile->vnode, tuiop, 0, afs_osi_ctxtp);
+    AFS_GLOCK();
+#elif defined(AFS_DARWIN_ENV)
+    AFS_GUNLOCK();
+    VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
+    code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp);
+    VOP_UNLOCK(tfile->vnode, 0, current_proc());
+    AFS_GLOCK();
+#elif defined(AFS_FBSD80_ENV)
+    AFS_GUNLOCK();
+    VOP_LOCK(tfile->vnode, LK_EXCLUSIVE);
+    code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp);
+    VOP_UNLOCK(tfile->vnode, 0);
+    AFS_GLOCK();
+#elif defined(AFS_FBSD_ENV)
+    AFS_GUNLOCK();
+    VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
+    code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp);
+    VOP_UNLOCK(tfile->vnode, 0, curthread);
+    AFS_GLOCK();
+#elif defined(AFS_NBSD_ENV)
+    AFS_GUNLOCK();
+    VOP_LOCK(tfile->vnode, LK_EXCLUSIVE);
+    code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp);
+    VOP_UNLOCK(tfile->vnode, 0);
+    AFS_GLOCK();
+#elif defined(AFS_XBSD_ENV)
+    AFS_GUNLOCK();
+    VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
+    code = VOP_READ(tfile->vnode, tuiop, 0, afs_osi_credp);
+    VOP_UNLOCK(tfile->vnode, 0, curproc);
+    AFS_GLOCK();
 #else
-#ifdef AFS_SUN5_ENV
-         AFS_GUNLOCK();
-           VOP_RWLOCK(tfile->vnode, 0);
-           code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
-           VOP_RWUNLOCK(tfile->vnode, 0);
-         AFS_GLOCK();
-#else
-#if defined(AFS_SGI_ENV)
-           AFS_GUNLOCK();
-           AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_READ);
-           AFS_VOP_READ(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred,
-                        code);
-           AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_READ);
-           AFS_GLOCK();
-#else
-#ifdef AFS_OSF_ENV
-           tuio.uio_rw = UIO_READ;
-           AFS_GUNLOCK();
-           VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
-           AFS_GLOCK();
-#else  /* AFS_OSF_ENV */
-#ifdef AFS_SUN_ENV
-           code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
-#else
-#if    defined(AFS_HPUX100_ENV)
-           AFS_GUNLOCK();
-           code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
-           AFS_GLOCK();
-#else
-#if defined(AFS_LINUX20_ENV)
-           AFS_GUNLOCK();
-           code = osi_file_uio_rdwr(tfile, &tuio, UIO_READ);
-           AFS_GLOCK();
-#else
-#if defined(AFS_DARWIN_ENV)
-            AFS_GUNLOCK();
-            VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
-            code = VOP_READ(tfile->vnode, &tuio, 0, &afs_osi_cred);
-            VOP_UNLOCK(tfile->vnode, 0, current_proc());
-            AFS_GLOCK();
-#else
-           code = VOP_RDWR(tfile->vnode, &tuio, UIO_READ, 0, &afs_osi_cred);
-#endif
-#endif
+    code = VOP_RDWR(tfile->vnode, tuiop, UIO_READ, 0, afs_osi_credp);
 #endif
-#endif
-#endif
-#endif
-#endif
-#endif
-
-#ifdef IHINT
-            if (!tdc->ihint && nihints < maxIHint) {
-              tdc->ihint = tfile;
-              nihints++;
-            }
-            else
-#endif /* IHINT */
-              osi_UFSClose(tfile);
-
-           if (code) {
-               error = code;
-               break;
-           }
-       }
-       /* otherwise we've read some, fixup length, etc and continue with next seg */
-       len = len - tuio.afsio_resid; /* compute amount really transferred */
-       trimlen = len;
-       afsio_skip(auio, trimlen);          /* update input uio structure */
-       totalLength -= len;
-       transferLength += len;
-       filePos += len;
-       if (len <= 0) break;    /* surprise eof */
-    }
-
-    /* if we make it here with tdc non-zero, then it is the last chunk we
-     * dealt with, and we have to release it when we're done.  We hold on
-     * to it in case we need to do a prefetch, obviously.
-     */
-    if (tdc) {
-#ifndef        AFS_VM_RDWR_ENV
-       /* try to queue prefetch, if needed */
-       if (!(tdc->flags & DFNextStarted) && !noLock) {
-           afs_PrefetchChunk(avc, tdc, acred, &treq);
-       }
-#endif
-       afs_PutDCache(tdc);
-    }
-    if (!noLock)
-       ReleaseReadLock(&avc->lock);
+    osi_UFSClose(tfile);
 
-    osi_FreeSmallSpace(tvec);
-    error = afs_CheckCode(error, &treq, 13);
-    return error;
+    return code;
 }