2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include "../afs/param.h"
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #ifndef AFS_LINUX22_ENV
17 #include "../rpc/types.h"
25 #endif /* AFS_ALPHA_ENV */
26 #include "../afs/afsincludes.h" /* Afs-based standard headers */
27 #include "../afs/afs_stats.h" /* statistics */
29 /* memory cache routines */
31 struct memCacheEntry {
32 int size; /* # of valid bytes in this entry */
33 int dataSize; /* size of allocated data area */
34 afs_lock_t afs_memLock;
35 char *data; /* bytes */
38 static struct memCacheEntry *memCache;
39 static int memCacheBlkSize = 8192;
40 static int memMaxBlkNumber = 0;
41 static int memAllocMaySleep = 0;
43 extern int cacheDiskType;
45 afs_InitMemCache(size, blkSize, flags)
52 AFS_STATCNT(afs_InitMemCache);
54 memCacheBlkSize = blkSize;
56 memMaxBlkNumber = size / memCacheBlkSize;
57 memCache = (struct memCacheEntry *)
58 afs_osi_Alloc(memMaxBlkNumber * sizeof(struct memCacheEntry));
59 if (flags & AFSCALL_INIT_MEMCACHE_SLEEP) {
63 for(index = 0; index < memMaxBlkNumber; index++) {
65 (memCache+index)->size = 0;
66 (memCache+index)->dataSize = memCacheBlkSize;
67 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
68 if (memAllocMaySleep) {
69 blk = afs_osi_Alloc(memCacheBlkSize);
71 blk = afs_osi_Alloc_NoSleep(memCacheBlkSize);
75 (memCache+index)->data = blk;
76 memset((memCache+index)->data, 0, memCacheBlkSize);
78 #if defined(AFS_SGI62_ENV) || defined(AFS_HAVE_VXFS)
79 afs_InitDualFSCacheOps((struct vnode*)0);
85 printf("afsd: memCache allocation failure at %d KB.\n",
86 (index * memCacheBlkSize) / 1024);
88 afs_osi_Free((memCache+index)->data, memCacheBlkSize);
89 (memCache+index)->data = NULL;
95 afs_MemCacheClose(file)
101 void *afs_MemCacheOpen(ino_t blkno)
103 struct memCacheEntry *mep;
105 if (blkno < 0 || blkno > memMaxBlkNumber) {
106 osi_Panic("afs_MemCacheOpen: invalid block #");
108 mep = (memCache + blkno);
109 afs_Trace4(afs_iclSetp, CM_TRACE_MEMOPEN,
110 ICL_TYPE_INT32, blkno,
111 ICL_TYPE_POINTER, mep,
112 ICL_TYPE_POINTER, mep->data,
113 ICL_TYPE_STRING, mep->data);
118 * this routine simulates a read in the Memory Cache
120 afs_MemReadBlk(mceP, offset, dest, size)
122 register struct memCacheEntry *mceP;
128 MObtainReadLock(&mceP->afs_memLock);
129 AFS_STATCNT(afs_MemReadBlk);
131 MReleaseReadLock(&mceP->afs_memLock);
134 /* use min of bytes in buffer or requested size */
135 bytesRead = (size < mceP->size - offset) ? size :
140 memcpy(dest, mceP->data + offset, bytesRead);
146 MReleaseReadLock(&mceP->afs_memLock);
151 * this routine simulates a readv in the Memory Cache
153 afs_MemReadvBlk(mceP, offset, iov, nio, size)
155 register struct memCacheEntry *mceP;
164 MObtainReadLock(&mceP->afs_memLock);
165 AFS_STATCNT(afs_MemReadBlk);
167 MReleaseReadLock(&mceP->afs_memLock);
170 /* use min of bytes in buffer or requested size */
171 bytesRead = (size < mceP->size - offset) ? size :
175 for (i = 0 , size = bytesRead ; i < nio && size > 0 ; i++) {
176 bytesToRead = (size < iov[i].iov_len) ? size : iov[i].iov_len;
178 memcpy(iov[i].iov_base, mceP->data + offset, bytesToRead);
180 offset += bytesToRead;
187 MReleaseReadLock(&mceP->afs_memLock);
191 afs_MemReadUIO(blkno, uioP)
195 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
196 int length = mceP->size - uioP->uio_offset;
199 AFS_STATCNT(afs_MemReadUIO);
200 MObtainReadLock(&mceP->afs_memLock);
201 length = (length < uioP->uio_resid) ? length : uioP->uio_resid;
202 AFS_UIOMOVE(mceP->data + uioP->uio_offset, length, UIO_READ, uioP, code);
203 MReleaseReadLock(&mceP->afs_memLock);
207 /*XXX: this extends a block arbitrarily to support big directories */
208 afs_MemWriteBlk(mceP, offset, src, size)
209 register struct memCacheEntry *mceP;
214 AFS_STATCNT(afs_MemWriteBlk);
215 MObtainWriteLock(&mceP->afs_memLock,560);
216 if (size + offset > mceP->dataSize) {
217 char *oldData = mceP->data;
219 if (memAllocMaySleep) {
220 mceP->data = afs_osi_Alloc(size+offset);
222 mceP->data = afs_osi_Alloc_NoSleep(size+offset);
224 if ( mceP->data == NULL ) /* no available memory */
226 mceP->data = oldData; /* revert back change that was made */
227 MReleaseWriteLock(&mceP->afs_memLock);
228 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
233 /* may overlap, but this is OK */
235 memcpy(mceP->data, oldData, mceP->size);
237 afs_osi_Free(oldData,mceP->dataSize);
238 mceP->dataSize = size+offset;
241 if (mceP->size < offset)
242 memset(mceP->data+mceP->size, 0, offset-mceP->size);
243 memcpy(mceP->data + offset, src, size);
245 mceP->size = (size+offset < mceP->size) ? mceP->size :
248 MReleaseWriteLock(&mceP->afs_memLock);
252 /*XXX: this extends a block arbitrarily to support big directories */
253 afs_MemWritevBlk(mceP, offset, iov, nio, size)
254 register struct memCacheEntry *mceP;
263 AFS_STATCNT(afs_MemWriteBlk);
264 MObtainWriteLock(&mceP->afs_memLock,561);
265 if (offset + size > mceP->dataSize) {
266 char *oldData = mceP->data;
268 mceP->data = afs_osi_Alloc(size+offset);
270 /* may overlap, but this is OK */
272 memcpy(mceP->data, oldData, mceP->size);
274 afs_osi_Free(oldData,mceP->dataSize);
275 mceP->dataSize = size+offset;
277 if (mceP->size < offset)
278 memset(mceP->data+mceP->size, 0, offset-mceP->size);
279 for (bytesWritten = 0, i = 0 ; i < nio && size > 0 ; i++) {
280 bytesToWrite = (size < iov[i].iov_len) ? size : iov[i].iov_len;
282 memcpy(mceP->data + offset, iov[i].iov_base, bytesToWrite);
284 offset += bytesToWrite;
285 bytesWritten += bytesToWrite;
286 size -= bytesToWrite;
288 mceP->size = (offset < mceP->size) ? mceP->size : offset;
290 MReleaseWriteLock(&mceP->afs_memLock);
294 afs_MemWriteUIO(blkno, uioP)
298 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
301 AFS_STATCNT(afs_MemWriteUIO);
302 MObtainWriteLock(&mceP->afs_memLock,312);
303 if(uioP->uio_resid + uioP->uio_offset > mceP->dataSize) {
304 char *oldData = mceP->data;
306 mceP->data = afs_osi_Alloc(uioP->uio_resid + uioP->uio_offset);
309 memcpy(mceP->data, oldData, mceP->size);
312 afs_osi_Free(oldData,mceP->dataSize);
313 mceP->dataSize = uioP->uio_resid + uioP->uio_offset;
315 if (mceP->size < uioP->uio_offset)
316 memset(mceP->data+mceP->size, 0, (int)(uioP->uio_offset-mceP->size));
317 AFS_UIOMOVE(mceP->data+uioP->uio_offset, uioP->uio_resid, UIO_WRITE, uioP, code);
318 if (uioP->uio_offset > mceP->size)
319 mceP->size = uioP->uio_offset;
321 MReleaseWriteLock(&mceP->afs_memLock);
325 afs_MemCacheTruncate(mceP, size)
326 register struct memCacheEntry *mceP;
329 AFS_STATCNT(afs_MemCacheTruncate);
331 MObtainWriteLock(&mceP->afs_memLock,313);
332 /* old directory entry; g.c. */
333 if(size == 0 && mceP->dataSize > memCacheBlkSize) {
334 afs_osi_Free(mceP->data, mceP->dataSize);
335 mceP->data = afs_osi_Alloc(memCacheBlkSize);
336 mceP->dataSize = memCacheBlkSize;
339 if (size < mceP->size)
342 MReleaseWriteLock(&mceP->afs_memLock);
346 afs_MemCacheStoreProc(acall, mceP, alen, avc, shouldWake, abytesToXferP, abytesXferredP, length)
347 register struct memCacheEntry *mceP;
348 register struct rx_call *acall;
349 register afs_int32 alen;
352 afs_size_t *abytesToXferP;
353 afs_size_t *abytesXferredP;
358 register afs_int32 code;
361 struct iovec *tiov; /* no data copying with iovec */
362 int tnio; /* temp for iovec size */
364 AFS_STATCNT(afs_MemCacheStoreProc);
367 * In this case, alen is *always* the amount of data we'll be trying
370 *(abytesToXferP) = alen;
371 *(abytesXferredP) = 0;
372 #endif /* AFS_NOSTATS */
375 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
376 * declare them on the stack - defect 11272
378 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
380 osi_Panic("afs_MemCacheStoreProc: osi_AllocSmallSpace for iovecs returned NULL\n");
384 /* do this at a higher level now -- it's a parameter */
385 /* for now, only do 'continue from close' code if file fits in one
386 chunk. Could clearly do better: if only one modified chunk
387 then can still do this. can do this on *last* modified chunk */
388 tlen = avc->m.Length-1; /* byte position of last byte we'll store */
390 if (AFS_CHUNK(tlen) != 0) *shouldWake = 0;
391 else *shouldWake = 1;
396 tlen = (alen > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : alen);
397 #ifdef RX_ENABLE_LOCKS
399 #endif /* RX_ENABLE_LOCKS */
400 code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
401 #ifdef RX_ENABLE_LOCKS
403 #endif /* RX_ENABLE_LOCKS */
405 osi_FreeSmallSpace(tiov);
409 code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
411 osi_FreeSmallSpace(tiov);
414 #ifdef RX_ENABLE_LOCKS
416 #endif /* RX_ENABLE_LOCKS */
417 code = rx_Writev(acall, tiov, tnio, tlen);
418 #ifdef RX_ENABLE_LOCKS
420 #endif /* RX_ENABLE_LOCKS */
422 (*abytesXferredP) += code;
423 #endif /* AFS_NOSTATS */
425 osi_FreeSmallSpace(tiov);
430 /* if file has been locked on server, can allow store to continue */
431 if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
432 *shouldWake = 0; /* only do this once */
436 osi_FreeSmallSpace(tiov);
440 afs_MemCacheFetchProc(acall, mceP, abase, adc, avc, abytesToXferP, abytesXferredP, lengthFound)
441 register struct rx_call *acall;
443 afs_size_t *abytesToXferP;
444 afs_size_t *abytesXferredP;
447 register struct memCacheEntry *mceP;
448 afs_int32 lengthFound;
450 register afs_int32 code;
453 struct iovec *tiov; /* no data copying with iovec */
454 register int tlen, offset=0;
455 int tnio; /* temp for iovec size */
457 AFS_STATCNT(afs_MemCacheFetchProc);
458 length = lengthFound;
459 afs_Trace4(afs_iclSetp, CM_TRACE_MEMFETCH,
460 ICL_TYPE_POINTER, avc,
461 ICL_TYPE_POINTER, mceP,
462 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(abase),
463 ICL_TYPE_INT32, length);
465 (*abytesToXferP) = 0;
466 (*abytesXferredP) = 0;
467 #endif /* AFS_NOSTATS */
469 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
470 * declare them on the stack - defect 11272
472 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
474 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
478 #ifdef RX_ENABLE_LOCKS
480 #endif /* RX_ENABLE_LOCKS */
481 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
482 length = ntohl(length);
483 #ifdef RX_ENABLE_LOCKS
485 #endif /* RX_ENABLE_LOCKS */
486 if (code != sizeof(afs_int32)) {
487 code = rx_Error(acall);
488 osi_FreeSmallSpace(tiov);
489 return (code?code:-1); /* try to return code, not -1 */
493 * The fetch protocol is extended for the AFS/DFS translator
494 * to allow multiple blocks of data, each with its own length,
495 * to be returned. As long as the top bit is set, there are more
498 * We do not do this for AFS file servers because they sometimes
499 * return large negative numbers as the transfer size.
501 if (avc->states & CForeign) {
502 moredata = length & 0x80000000;
503 length &= ~0x80000000;
508 (*abytesToXferP) += length;
509 #endif /* AFS_NOSTATS */
511 tlen = (length > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : length);
512 #ifdef RX_ENABLE_LOCKS
514 #endif /* RX_ENABLE_LOCKS */
515 code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
516 #ifdef RX_ENABLE_LOCKS
518 #endif /* RX_ENABLE_LOCKS */
520 (*abytesXferredP) += code;
521 #endif /* AFS_NOSTATS */
523 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
524 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
525 ICL_TYPE_INT32, length);
526 osi_FreeSmallSpace(tiov);
530 afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
534 adc->validPos = abase;
535 if (adc->flags & DFWaiting) {
536 adc->flags &= ~DFWaiting;
537 afs_osi_Wakeup(&adc->validPos);
541 /* max of two sizes */
542 osi_FreeSmallSpace(tiov);
547 void shutdown_memcache()
551 if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
553 memCacheBlkSize = 8192;
554 for (index = 0; index < memMaxBlkNumber; index++) {
555 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
556 afs_osi_Free((memCache+index)->data, (memCache+index)->dataSize);
558 afs_osi_Free((char *)memCache, memMaxBlkNumber * sizeof(struct memCacheEntry));