Cache bypass: Remove AFS_KMAP_ATOMIC
[openafs.git] / src / afs / afs_bypasscache.c
index dc1f3bd..8d7e601 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT  ©  2000
  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
  * ALL RIGHTS RESERVED
- * 
+ *
  * Permission is granted to use, copy, create derivative works
  * and redistribute this software and such derivative works
  * for any purpose, so long as the name of The University of
  * University of Michigan is included in any copy of any
  * portion of this software, then the disclaimer below must
  * also be included.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
- * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY O 
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY O
  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
@@ -27,7 +27,7 @@
  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGES.
  */
+
  /*
  * Portions Copyright (c) 2008
  * The Linux Box Corporation
  * of any kind, either express or implied, including
  * without limitation the implied warranties of
  * merchantability and fitness for a particular purpose.  The
- * Linux Box Corporation shall not be liable for any damages, 
- * including special, indirect, incidental, or consequential 
- * damages, with respect to any claim arising out of or in 
- * connection with the use of the software, even if it has been 
+ * Linux Box Corporation shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential
+ * damages, with respect to any claim arising out of or in
+ * connection with the use of the software, even if it has been
  * or is hereafter advised of the possibility of such damages.
  */
 
 #include "afs/sysincludes.h" /* Standard vendor system headers */
 #include "afs/afsincludes.h" /* Afs-based standard headers */
 #include "afs/afs_stats.h"   /* statistics */
-#include "afs/nfsclient.h"  
+#include "afs/nfsclient.h"
 #include "rx/rx_globals.h"
 
 #if defined(AFS_LINUX26_ENV)
 #define LockPage(pp) lock_page(pp)
 #define UnlockPage(pp) unlock_page(pp)
 #endif
-#define AFS_KMAP_ATOMIC
 
 #ifndef afs_min
 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
@@ -92,7 +91,7 @@
                if(!var) \
                        RX_AFS_GLOCK(); \
        } while(0)
-       
+
 #define COND_RE_GUNLOCK(var) \
        do { \
                if(var) \
@@ -131,8 +130,8 @@ extern afs_rwlock_t afs_xcbhash;
  * times we go back and forth from caching to bypass.
  */
 void
-afs_TransitionToBypass(register struct vcache *avc,
-                      register afs_ucred_t *acred, int aflags)
+afs_TransitionToBypass(struct vcache *avc,
+                      afs_ucred_t *acred, int aflags)
 {
 
     afs_int32 code;
@@ -142,24 +141,28 @@ afs_TransitionToBypass(register struct vcache *avc,
 
     if (!avc)
        return;
-               
-    if (avc->f.states & FCSBypass)
-       osi_Panic("afs_TransitionToBypass: illegal transition to bypass--already FCSBypass\n");         
-               
+
     if (aflags & TRANSChangeDesiredBit)
        setDesire = 1;
     if (aflags & TRANSSetManualBit)
        setManual = 1;
-               
+
 #ifdef AFS_BOZONLOCK_ENV
     afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
 #else
     AFS_GLOCK();
 #endif
+
     ObtainWriteLock(&avc->lock, 925);
-       
+    /*
+     * Someone may have beat us to doing the transition - we had no lock
+     * when we checked the flag earlier.  No cause to panic, just return.
+     */
+    if (avc->f.states & FCSBypass)
+       goto done;
+
     /* If we never cached this, just change state */
-    if (setDesire && (!avc->cachingStates & FCSBypass)) {
+    if (setDesire && (!(avc->cachingStates & FCSBypass))) {
        avc->f.states |= FCSBypass;
        goto done;
     }
@@ -173,7 +176,7 @@ afs_TransitionToBypass(register struct vcache *avc,
 
 #if 0
     /* also cg2v, don't dequeue the callback */
-    ObtainWriteLock(&afs_xcbhash, 956);        
+    ObtainWriteLock(&afs_xcbhash, 956);
     afs_DequeueCallback(avc);
     ReleaseWriteLock(&afs_xcbhash);
 #endif
@@ -184,7 +187,7 @@ afs_TransitionToBypass(register struct vcache *avc,
     if (avc->linkData && !(avc->f.states & CCore)) {
        afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
        avc->linkData = NULL;
-    }          
+    }
 
     avc->cachingStates |= FCSBypass;    /* Set the bypass flag */
     if(setDesire)
@@ -210,8 +213,8 @@ done:
  * the number of times we go back and forth from caching to bypass.
  */
 void
-afs_TransitionToCaching(register struct vcache *avc,
-                       register afs_ucred_t *acred,
+afs_TransitionToCaching(struct vcache *avc,
+                       afs_ucred_t *acred,
                        int aflags)
 {
     int resetDesire = 0;
@@ -220,9 +223,6 @@ afs_TransitionToCaching(register struct vcache *avc,
     if (!avc)
        return;
 
-    if (!avc->f.states & FCSBypass)
-       osi_Panic("afs_TransitionToCaching: illegal transition to caching--already caching\n");         
-               
     if (aflags & TRANSChangeDesiredBit)
        resetDesire = 1;
     if (aflags & TRANSSetManualBit)
@@ -234,6 +234,12 @@ afs_TransitionToCaching(register struct vcache *avc,
     AFS_GLOCK();
 #endif
     ObtainWriteLock(&avc->lock, 926);
+    /*
+     * Someone may have beat us to doing the transition - we had no lock
+     * when we checked the flag earlier.  No cause to panic, just return.
+     */
+    if (!(avc->f.states & FCSBypass))
+       goto done;
 
     /* Ok, we actually do need to flush */
     ObtainWriteLock(&afs_xcbhash, 957);
@@ -247,7 +253,7 @@ afs_TransitionToCaching(register struct vcache *avc,
        afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
        avc->linkData = NULL;
     }
-               
+
     avc->cachingStates &= ~(FCSBypass);    /* Reset the bypass flag */
     if (resetDesire)
        avc->cachingStates &= ~(FCSDesireBypass);
@@ -255,6 +261,7 @@ afs_TransitionToCaching(register struct vcache *avc,
        avc->cachingStates |= FCSManuallySet;
     avc->cachingTransitions++;
 
+done:
     ReleaseWriteLock(&avc->lock);
 #ifdef AFS_BOZONLOCK_ENV
     afs_BozonUnlock(&avc->pvnLock, avc);
@@ -268,7 +275,7 @@ afs_TransitionToCaching(register struct vcache *avc,
  * to be unlocked.
  */
 #if defined(AFS_LINUX24_ENV)
-#define unlock_pages(auio) \
+#define unlock_and_release_pages(auio) \
     do { \
        struct iovec *ciov;     \
        struct page *pp; \
@@ -277,21 +284,22 @@ afs_TransitionToCaching(register struct vcache *avc,
        ciov = auio->uio_iov; \
        iovmax = auio->uio_iovcnt - 1;  \
        pp = (struct page*) ciov->iov_base;     \
-       afs_warn("BYPASS: Unlocking pages..."); \
        while(1) { \
-           if(pp != NULL && PageLocked(pp)) \
-               UnlockPage(pp); \
+           if (pp) { \
+               if (PageLocked(pp)) \
+                   UnlockPage(pp);     \
+               put_page(pp); /* decrement refcount */ \
+           } \
            iovno++; \
            if(iovno > iovmax) \
                break; \
            ciov = (auio->uio_iov + iovno);     \
            pp = (struct page*) ciov->iov_base; \
        } \
-       afs_warn("Pages Unlocked.\n"); \
     } while(0)
 #else
 #ifdef UKERNEL
-#define unlock_pages(auio) \
+#define unlock_and_release_pages(auio) \
         do { } while(0)
 #else
 #error AFS_CACHE_BYPASS not implemented on this platform
@@ -300,9 +308,9 @@ afs_TransitionToCaching(register struct vcache *avc,
 
 /* no-cache prefetch routine */
 static afs_int32
-afs_NoCacheFetchProc(register struct rx_call *acall, 
-                     register struct vcache *avc, 
-                                        register uio_t *auio, 
+afs_NoCacheFetchProc(struct rx_call *acall,
+                     struct vcache *avc,
+                                        uio_t *auio,
                      afs_int32 release_pages,
                     afs_int32 size)
 {
@@ -313,16 +321,12 @@ afs_NoCacheFetchProc(register struct rx_call *acall,
     struct iovec *ciov;
     struct page *pp;
     char *address;
-#ifdef AFS_KMAP_ATOMIC
     char *page_buffer = osi_Alloc(PAGE_SIZE);
-#else
-    char *page_buffer = NULL;
-#endif
 
     ciov = auio->uio_iov;
     pp = (struct page*) ciov->iov_base;
     iovmax = auio->uio_iovcnt - 1;
-    iovno = iovoff = result = 0;       
+    iovno = iovoff = result = 0;
     do {
 
        COND_GUNLOCK(locked);
@@ -332,20 +336,27 @@ afs_NoCacheFetchProc(register struct rx_call *acall,
        if (code != sizeof(afs_int32)) {
            result = 0;
            afs_warn("Preread error. code: %d instead of %d\n",
-               code, sizeof(afs_int32));
-           unlock_pages(auio);
+               code, (int)sizeof(afs_int32));
+           unlock_and_release_pages(auio);
            goto done;
        } else
-           length = ntohl(length);             
+           length = ntohl(length);
 
        if (length > size) {
            result = EIO;
            afs_warn("Preread error. Got length %d, which is greater than size %d\n",
                     length, size);
-           unlock_pages(auio);
+           unlock_and_release_pages(auio);
+           goto done;
+       }
+
+       /* If we get a 0 length reply, time to cleanup and return */
+       if (length == 0) {
+           unlock_and_release_pages(auio);
+           result = 0;
            goto done;
        }
-                                       
+
        /*
         * The fetch protocol is extended for the AFS/DFS translator
         * to allow multiple blocks of data, each with its own length,
@@ -361,27 +372,13 @@ afs_NoCacheFetchProc(register struct rx_call *acall,
        } else {
            moredata = 0;
        }
-                               
+
        while (length > 0) {
 
-           clen = ciov->iov_len - iovoff; 
+           clen = ciov->iov_len - iovoff;
            tlen = afs_min(length, clen);
 #ifdef AFS_LINUX24_ENV
-#ifndef AFS_KMAP_ATOMIC
-           if(pp)
-               address = kmap(pp);
-           else { 
-               /* rx doesn't provide an interface to simply advance
-                  or consume n bytes.  for now, allocate a PAGE_SIZE 
-                  region of memory to receive bytes in the case that 
-                  there were holes in readpages */
-               if(page_buffer == NULL)
-                   page_buffer = osi_Alloc(PAGE_SIZE);
-                   address = page_buffer;
-               }
-#else
            address = page_buffer;
-#endif
 #else
 #ifndef UKERNEL
 #error AFS_CACHE_BYPASS not implemented on this platform
@@ -390,33 +387,31 @@ afs_NoCacheFetchProc(register struct rx_call *acall,
            COND_GUNLOCK(locked);
            code = rx_Read(acall, address, tlen);
            COND_RE_GLOCK(locked);
-               
+
            if (code < 0) {
                afs_warn("afs_NoCacheFetchProc: rx_Read error. Return code was %d\n", code);
                result = 0;
-               unlock_pages(auio);
+               unlock_and_release_pages(auio);
                goto done;
            } else if (code == 0) {
                result = 0;
                afs_warn("afs_NoCacheFetchProc: rx_Read returned zero. Aborting.\n");
-               unlock_pages(auio);
+               unlock_and_release_pages(auio);
                goto done;
            }
            length -= code;
            tlen -= code;
-               
+
            if(tlen > 0) {
                iovoff += code;
                address += code;
            } else {
 #ifdef AFS_LINUX24_ENV
-#ifdef AFS_KMAP_ATOMIC
                if(pp) {
                    address = kmap_atomic(pp, KM_USER0);
                    memcpy(address, page_buffer, PAGE_SIZE);
                    kunmap_atomic(address, KM_USER0);
                }
-#endif
 #else
 #ifndef UKERNEL
 #error AFS_CACHE_BYPASS not implemented on this platform
@@ -427,14 +422,12 @@ afs_NoCacheFetchProc(register struct rx_call *acall,
                    /* this is appropriate when no caller intends to unlock
                     * and release the page */
 #ifdef AFS_LINUX24_ENV
-                   SetPageUptodate(pp);
-                   if(PageLocked(pp))
-                       UnlockPage(pp);
-                   else
-                       afs_warn("afs_NoCacheFetchProc: page not locked at iovno %d!\n", iovno);
-#ifndef AFS_KMAP_ATOMIC
-                   kunmap(pp);
-#endif
+                    SetPageUptodate(pp);
+                    if(PageLocked(pp))
+                        UnlockPage(pp);
+                    else
+                        afs_warn("afs_NoCacheFetchProc: page not locked at iovno %d!\n", iovno);
+                    put_page(pp); /* decrement refcount */
 #else
 #ifndef UKERNEL
 #error AFS_CACHE_BYPASS not implemented on this platform
@@ -445,14 +438,14 @@ afs_NoCacheFetchProc(register struct rx_call *acall,
                iovno++;
                if (iovno > iovmax)
                    goto done;
-                       
+
                ciov = (auio->uio_iov + iovno);
                pp = (struct page*) ciov->iov_base;
                iovoff = 0;
            }
        }
     } while (moredata);
-       
+
 done:
     if(page_buffer)
        osi_Free(page_buffer, PAGE_SIZE);
@@ -462,18 +455,18 @@ done:
 
 /* dispatch a no-cache read request */
 afs_int32
-afs_ReadNoCache(register struct vcache *avc, 
-               register struct nocache_read_request *bparms,
+afs_ReadNoCache(struct vcache *avc,
+               struct nocache_read_request *bparms,
                afs_ucred_t *acred)
 {
     afs_int32 code;
     afs_int32 bcnt;
     struct brequest *breq;
     struct vrequest *areq;
-               
+
     /* the reciever will free this */
     areq = osi_Alloc(sizeof(struct vrequest));
-       
+
     if (avc && avc->vc_error) {
        code = EIO;
        afs_warn("afs_ReadNoCache VCache Error!\n");
@@ -484,24 +477,24 @@ afs_ReadNoCache(register struct vcache *avc,
        goto cleanup;
     }
 
-    AFS_GLOCK();               
+    AFS_GLOCK();
     code = afs_VerifyVCache(avc, areq);
     AFS_GUNLOCK();
-       
+
     if (code) {
        code = afs_CheckCode(code, areq, 11);   /* failed to get it */
        afs_warn("afs_ReadNoCache Failed to verify VCache!\n");
        goto cleanup;
     }
-       
+
     bparms->areq = areq;
-       
+
     /* and queue this one */
     bcnt = 1;
     AFS_GLOCK();
     while(bcnt < 20) {
        breq = afs_BQueue(BOP_FETCH_NOCACHE, avc, B_DONTWAIT, 0, acred, 1, 1,
-                         bparms);
+                         bparms, (void *)0, (void *)0);
        if(breq != 0) {
            code = 0;
            break;
@@ -509,7 +502,7 @@ afs_ReadNoCache(register struct vcache *avc,
        afs_osi_Wait(10 * bcnt, 0, 0);
     }
     AFS_GUNLOCK();
-    
+
     if(!breq) {
        code = EBUSY;
        goto cleanup;
@@ -523,7 +516,7 @@ cleanup:
      * processed, like unlocking the pages and freeing memory.
      */
 #ifdef AFS_LINUX24_ENV
-    unlock_pages(bparms->auio);
+    unlock_and_release_pages(bparms->auio);
 #else
 #ifndef UKERNEL
 #error AFS_CACHE_BYPASS not implemented on this platform
@@ -540,16 +533,19 @@ cleanup:
 
 /* Cannot have static linkage--called from BPrefetch (afs_daemons) */
 afs_int32
-afs_PrefetchNoCache(register struct vcache *avc, 
-                   register afs_ucred_t *acred,
-                   register struct nocache_read_request *bparms)
+afs_PrefetchNoCache(struct vcache *avc,
+                   afs_ucred_t *acred,
+                   struct nocache_read_request *bparms)
 {
     uio_t *auio;
     struct iovec *iovecp;
     struct vrequest *areq;
-    afs_int32 code, length_hi, bytes, locked;    
-       
-    register struct afs_conn *tc;
+    afs_int32 code = 0;
+#ifdef AFS_64BIT_CLIENT
+    afs_int32 length_hi, bytes, locked;
+#endif
+
+    struct afs_conn *tc;
     afs_int32 i;
     struct rx_call *tcall;
     struct tlocal1 {
@@ -557,12 +553,12 @@ afs_PrefetchNoCache(register struct vcache *avc,
        struct AFSFetchStatus OutStatus;
        struct AFSCallBack CallBack;
     };
-    struct tlocal1 *tcallspec; 
-                       
+    struct tlocal1 *tcallspec;
+
     auio = bparms->auio;
     areq = bparms->areq;
-    iovecp = auio->uio_iov;    
-       
+    iovecp = auio->uio_iov;
+
     tcallspec = (struct tlocal1 *) osi_Alloc(sizeof(struct tlocal1));
     do {
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK /* ignored */);
@@ -581,7 +577,7 @@ afs_PrefetchNoCache(register struct vcache *avc,
                    bytes = rx_Read(tcall, (char *)&length_hi,
                                    sizeof(afs_int32));
                    COND_RE_GLOCK(locked);
-                                       
+
                    if (bytes != sizeof(afs_int32)) {
                        length_hi = 0;
                        code = rx_Error(tcall);
@@ -591,23 +587,23 @@ afs_PrefetchNoCache(register struct vcache *avc,
                        tcall = NULL;
                    }
                }
-               if (code == RXGEN_OPCODE || afs_serverHasNo64Bit(tc)) {
-                   if (auio->uio_offset > 0x7FFFFFFF) {
-                       code = EFBIG;
-                   } else {
-                       afs_int32 pos;
-                       pos = auio->uio_offset;
-                       COND_GUNLOCK(locked);
-                       if (!tcall)
-                           tcall = rx_NewCall(tc->id);
-                       code = StartRXAFS_FetchData(tcall,
-                                             (struct AFSFid *) &avc->f.fid.Fid,
-                                             pos, bparms->length);
-                       COND_RE_GLOCK(locked);
-                   }
-                   afs_serverSetNo64Bit(tc);
-               }
            } /* afs_serverHasNo64Bit */
+           if (code == RXGEN_OPCODE || afs_serverHasNo64Bit(tc)) {
+               if (auio->uio_offset > 0x7FFFFFFF) {
+                   code = EFBIG;
+               } else {
+                   afs_int32 pos;
+                   pos = auio->uio_offset;
+                   COND_GUNLOCK(locked);
+                   if (!tcall)
+                       tcall = rx_NewCall(tc->id);
+                   code = StartRXAFS_FetchData(tcall,
+                                       (struct AFSFid *) &avc->f.fid.Fid,
+                                       pos, bparms->length);
+                   COND_RE_GLOCK(locked);
+               }
+               afs_serverSetNo64Bit(tc);
+           }
 #else
            code = StartRXAFS_FetchData(tcall,
                                        (struct AFSFid *) &avc->f.fid.Fid,
@@ -619,7 +615,7 @@ afs_PrefetchNoCache(register struct vcache *avc,
                                            bparms->length);
            } else {
                afs_warn("BYPASS: StartRXAFS_FetchData failed: %d\n", code);
-               unlock_pages(auio);
+               unlock_and_release_pages(auio);
                goto done;
            }
            if (code == 0) {
@@ -634,7 +630,7 @@ afs_PrefetchNoCache(register struct vcache *avc,
            afs_warn("BYPASS: No connection.\n");
            code = -1;
 #ifdef AFS_LINUX24_ENV
-           unlock_pages(auio);
+           unlock_and_release_pages(auio);
 #else
 #ifndef UKERNEL
 #error AFS_CACHE_BYPASS not implemented on this platform
@@ -654,7 +650,7 @@ done:
 
     osi_Free(areq, sizeof(struct vrequest));
     osi_Free(tcallspec, sizeof(struct tlocal1));
-    osi_Free(iovecp, auio->uio_iovcnt * sizeof(struct iovec)); 
+    osi_Free(iovecp, auio->uio_iovcnt * sizeof(struct iovec));
     osi_Free(bparms, sizeof(struct nocache_read_request));
     osi_Free(auio, sizeof(uio_t));
     return code;