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);
398 code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
401 osi_FreeSmallSpace(tiov);
405 code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
407 osi_FreeSmallSpace(tiov);
411 code = rx_Writev(acall, tiov, tnio, tlen);
414 (*abytesXferredP) += code;
415 #endif /* AFS_NOSTATS */
417 osi_FreeSmallSpace(tiov);
422 /* if file has been locked on server, can allow store to continue */
423 if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
424 *shouldWake = 0; /* only do this once */
428 osi_FreeSmallSpace(tiov);
432 afs_MemCacheFetchProc(acall, mceP, abase, adc, avc, abytesToXferP, abytesXferredP, lengthFound)
433 register struct rx_call *acall;
435 afs_size_t *abytesToXferP;
436 afs_size_t *abytesXferredP;
439 register struct memCacheEntry *mceP;
440 afs_int32 lengthFound;
442 register afs_int32 code;
445 struct iovec *tiov; /* no data copying with iovec */
446 register int tlen, offset=0;
447 int tnio; /* temp for iovec size */
449 AFS_STATCNT(afs_MemCacheFetchProc);
450 length = lengthFound;
451 afs_Trace4(afs_iclSetp, CM_TRACE_MEMFETCH,
452 ICL_TYPE_POINTER, avc,
453 ICL_TYPE_POINTER, mceP,
454 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(abase),
455 ICL_TYPE_INT32, length);
457 (*abytesToXferP) = 0;
458 (*abytesXferredP) = 0;
459 #endif /* AFS_NOSTATS */
461 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
462 * declare them on the stack - defect 11272
464 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
466 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
471 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
472 length = ntohl(length);
474 if (code != sizeof(afs_int32)) {
475 code = rx_Error(acall);
476 osi_FreeSmallSpace(tiov);
477 return (code?code:-1); /* try to return code, not -1 */
481 * The fetch protocol is extended for the AFS/DFS translator
482 * to allow multiple blocks of data, each with its own length,
483 * to be returned. As long as the top bit is set, there are more
486 * We do not do this for AFS file servers because they sometimes
487 * return large negative numbers as the transfer size.
489 if (avc->states & CForeign) {
490 moredata = length & 0x80000000;
491 length &= ~0x80000000;
496 (*abytesToXferP) += length;
497 #endif /* AFS_NOSTATS */
499 tlen = (length > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : length);
501 code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
504 (*abytesXferredP) += code;
505 #endif /* AFS_NOSTATS */
507 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
508 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
509 ICL_TYPE_INT32, length);
510 osi_FreeSmallSpace(tiov);
514 afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
518 adc->validPos = abase;
519 afs_osi_Wakeup(&adc->validPos);
522 /* max of two sizes */
523 osi_FreeSmallSpace(tiov);
528 void shutdown_memcache()
532 if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
534 memCacheBlkSize = 8192;
535 for (index = 0; index < memMaxBlkNumber; index++) {
536 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
537 afs_osi_Free((memCache+index)->data, (memCache+index)->dataSize);
539 afs_osi_Free((char *)memCache, memMaxBlkNumber * sizeof(struct memCacheEntry));