X-Git-Url: https://git.openafs.org/?p=openafs.git;a=blobdiff_plain;f=src%2Fafs%2Fafs_bypasscache.c;h=bb1baf469c4fa84fcd1da7a0cc080f53e33b7bd9;hp=9decac0031e96a5c8bc0524a3d32de2b3a044203;hb=4a2d1973fc5c2aac05beef5d64e7a486757c54af;hpb=00d56c519be35f690e4cf26eddc8143304d38bdd diff --git a/src/afs/afs_bypasscache.c b/src/afs/afs_bypasscache.c index 9decac0..bb1baf4 100644 --- a/src/afs/afs_bypasscache.c +++ b/src/afs/afs_bypasscache.c @@ -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 @@ -13,10 +13,10 @@ * 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 @@ -50,10 +50,10 @@ * 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. */ @@ -61,7 +61,7 @@ #include #include "afs/param.h" -#if defined(AFS_CACHE_BYPASS) +#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV) #include "afs/afs_bypasscache.h" @@ -72,15 +72,9 @@ #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) #endif @@ -92,7 +86,7 @@ if(!var) \ RX_AFS_GLOCK(); \ } while(0) - + #define COND_RE_GUNLOCK(var) \ do { \ if(var) \ @@ -131,8 +125,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 +136,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 +171,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 +182,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 +208,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 +218,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 +229,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 +248,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 +256,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); @@ -267,8 +269,7 @@ afs_TransitionToCaching(register struct vcache *avc, * afs_PrefetchNoCache, all of the pages they've been passed need * 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,75 +278,74 @@ 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)) \ + unlock_page(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) \ - do { } while(0) -#else -#error AFS_CACHE_BYPASS not implemented on this platform -#endif -#endif /* 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) { afs_int32 length; afs_int32 code; - int tlen; - int moredata, iovno, iovoff, iovmax, clen, result, locked; + int moredata, iovno, iovoff, iovmax, result, locked; struct iovec *ciov; + struct iovec *rxiov; + int nio; struct page *pp; char *address; -#ifdef AFS_KMAP_ATOMIC - char *page_buffer = osi_Alloc(PAGE_SIZE); -#else - char *page_buffer = NULL; -#endif + int curpage, bytes; + int pageoff; + + rxiov = osi_AllocSmallSpace(sizeof(struct iovec) * RX_MAXIOVECS); ciov = auio->uio_iov; pp = (struct page*) ciov->iov_base; iovmax = auio->uio_iovcnt - 1; - iovno = iovoff = result = 0; - do { + iovno = iovoff = result = 0; + do { COND_GUNLOCK(locked); code = rx_Read(acall, (char *)&length, sizeof(afs_int32)); COND_RE_GLOCK(locked); - 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,119 +361,90 @@ afs_NoCacheFetchProc(register struct rx_call *acall, } else { moredata = 0; } - - while (length > 0) { - - 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; + + for (curpage = 0; curpage <= iovmax; curpage++) { + pageoff = 0; + while (pageoff < 4096) { + /* If no more iovs, issue new read. */ + if (iovno >= nio) { + COND_GUNLOCK(locked); + bytes = rx_Readv(acall, rxiov, &nio, RX_MAXIOVECS, length); + COND_RE_GLOCK(locked); + if (bytes < 0) { + afs_warn("afs_NoCacheFetchProc: rx_Read error. Return code was %d\n", bytes); + result = 0; + unlock_and_release_pages(auio); + goto done; + } else if (bytes == 0) { + result = 0; + afs_warn("afs_NoCacheFetchProc: rx_Read returned zero. Aborting.\n"); + unlock_and_release_pages(auio); + goto done; + } + length -= bytes; + iovno = 0; } -#else - address = page_buffer; -#endif -#else -#ifndef UKERNEL -#error AFS_CACHE_BYPASS not implemented on this platform -#endif -#endif /* LINUX24 */ - 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); - goto done; - } else if (code == 0) { - result = 0; - afs_warn("afs_NoCacheFetchProc: rx_Read returned zero. Aborting.\n"); - unlock_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); + pp = (struct page *)auio->uio_iov[curpage].iov_base; + if (pageoff + (rxiov[iovno].iov_len - iovoff) <= PAGE_CACHE_SIZE) { + /* Copy entire (or rest of) current iovec into current page */ + if (pp) { + address = kmap_atomic(pp, KM_USER0); + memcpy(address + pageoff, rxiov[iovno].iov_base + iovoff, + rxiov[iovno].iov_len - iovoff); + kunmap_atomic(address, KM_USER0); + } + pageoff += rxiov[iovno].iov_len - iovoff; + iovno++; + iovoff = 0; + } else { + /* Copy only what's needed to fill current page */ + if (pp) { + address = kmap_atomic(pp, KM_USER0); + memcpy(address + pageoff, rxiov[iovno].iov_base + iovoff, + PAGE_CACHE_SIZE - pageoff); + kunmap_atomic(address, KM_USER0); + } + iovoff += PAGE_CACHE_SIZE - pageoff; + pageoff = PAGE_CACHE_SIZE; } -#endif -#else -#ifndef UKERNEL -#error AFS_CACHE_BYPASS not implemented on this platform -#endif -#endif /* LINUX 24 */ - /* we filled a page, conditionally release it */ - if (release_pages && ciov->iov_base) { + /* we filled a page, or this is the last page. conditionally release it */ + if (pp && ((pageoff == PAGE_CACHE_SIZE && release_pages) + || (length == 0 && iovno >= nio))) { /* 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 -#else -#ifndef UKERNEL -#error AFS_CACHE_BYPASS not implemented on this platform -#endif -#endif /* LINUX24 */ + SetPageUptodate(pp); + if(PageLocked(pp)) + unlock_page(pp); + else + afs_warn("afs_NoCacheFetchProc: page not locked!\n"); + put_page(pp); /* decrement refcount */ } - /* and carry uio_iov */ - iovno++; - if (iovno > iovmax) + if (length == 0 && iovno >= nio) 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); + osi_FreeSmallSpace(rxiov); return result; } /* 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,18 +455,18 @@ 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(); @@ -509,7 +480,7 @@ afs_ReadNoCache(register struct vcache *avc, afs_osi_Wait(10 * bcnt, 0, 0); } AFS_GUNLOCK(); - + if(!breq) { code = EBUSY; goto cleanup; @@ -522,13 +493,7 @@ cleanup: * do everything that would normally happen when the request was * processed, like unlocking the pages and freeing memory. */ -#ifdef AFS_LINUX24_ENV - unlock_pages(bparms->auio); -#else -#ifndef UKERNEL -#error AFS_CACHE_BYPASS not implemented on this platform -#endif -#endif + unlock_and_release_pages(bparms->auio); osi_Free(areq, sizeof(struct vrequest)); osi_Free(bparms->auio->uio_iov, bparms->auio->uio_iovcnt * sizeof(struct iovec)); @@ -540,16 +505,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 +525,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 +549,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 +559,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 +587,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) { @@ -633,13 +601,7 @@ afs_PrefetchNoCache(register struct vcache *avc, } else { afs_warn("BYPASS: No connection.\n"); code = -1; -#ifdef AFS_LINUX24_ENV - unlock_pages(auio); -#else -#ifndef UKERNEL -#error AFS_CACHE_BYPASS not implemented on this platform -#endif -#endif + unlock_and_release_pages(auio); goto done; } } while (afs_Analyze(tc, code, &avc->f.fid, areq, @@ -654,10 +616,10 @@ 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; } -#endif /* AFS_CACHE_BYPASS */ +#endif /* AFS_CACHE_BYPASS && AFS_LINUX24_ENV */