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);
113 * this routine simulates a read in the Memory Cache
115 afs_MemReadBlk(mceP, offset, dest, size)
117 register struct memCacheEntry *mceP;
123 MObtainReadLock(&mceP->afs_memLock);
124 AFS_STATCNT(afs_MemReadBlk);
126 MReleaseReadLock(&mceP->afs_memLock);
129 /* use min of bytes in buffer or requested size */
130 bytesRead = (size < mceP->size - offset) ? size :
135 memcpy(dest, mceP->data + offset, bytesRead);
141 MReleaseReadLock(&mceP->afs_memLock);
146 * this routine simulates a readv in the Memory Cache
148 afs_MemReadvBlk(mceP, offset, iov, nio, size)
150 register struct memCacheEntry *mceP;
159 MObtainReadLock(&mceP->afs_memLock);
160 AFS_STATCNT(afs_MemReadBlk);
162 MReleaseReadLock(&mceP->afs_memLock);
165 /* use min of bytes in buffer or requested size */
166 bytesRead = (size < mceP->size - offset) ? size :
170 for (i = 0 , size = bytesRead ; i < nio && size > 0 ; i++) {
171 bytesToRead = (size < iov[i].iov_len) ? size : iov[i].iov_len;
173 memcpy(iov[i].iov_base, mceP->data + offset, bytesToRead);
175 offset += bytesToRead;
182 MReleaseReadLock(&mceP->afs_memLock);
186 afs_MemReadUIO(blkno, uioP)
190 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
191 int length = mceP->size - uioP->uio_offset;
194 AFS_STATCNT(afs_MemReadUIO);
195 MObtainReadLock(&mceP->afs_memLock);
196 length = (length < uioP->uio_resid) ? length : uioP->uio_resid;
197 AFS_UIOMOVE(mceP->data + uioP->uio_offset, length, UIO_READ, uioP, code);
198 MReleaseReadLock(&mceP->afs_memLock);
202 /*XXX: this extends a block arbitrarily to support big directories */
203 afs_MemWriteBlk(mceP, offset, src, size)
204 register struct memCacheEntry *mceP;
209 AFS_STATCNT(afs_MemWriteBlk);
210 MObtainWriteLock(&mceP->afs_memLock,560);
211 if (size + offset > mceP->dataSize) {
212 char *oldData = mceP->data;
214 if (memAllocMaySleep) {
215 mceP->data = afs_osi_Alloc(size+offset);
217 mceP->data = afs_osi_Alloc_NoSleep(size+offset);
219 if ( mceP->data == NULL ) /* no available memory */
221 mceP->data = oldData; /* revert back change that was made */
222 MReleaseWriteLock(&mceP->afs_memLock);
223 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
228 /* may overlap, but this is OK */
230 memcpy(mceP->data, oldData, mceP->size);
232 afs_osi_Free(oldData,mceP->dataSize);
233 mceP->dataSize = size+offset;
236 if (mceP->size < offset)
237 memset(mceP->data+mceP->size, 0, offset-mceP->size);
238 memcpy(mceP->data + offset, src, size);
240 mceP->size = (size+offset < mceP->size) ? mceP->size :
243 MReleaseWriteLock(&mceP->afs_memLock);
247 /*XXX: this extends a block arbitrarily to support big directories */
248 afs_MemWritevBlk(mceP, offset, iov, nio, size)
249 register struct memCacheEntry *mceP;
258 AFS_STATCNT(afs_MemWriteBlk);
259 MObtainWriteLock(&mceP->afs_memLock,561);
260 if (size + offset > mceP->dataSize) {
261 char *oldData = mceP->data;
263 mceP->data = afs_osi_Alloc(size+offset);
265 /* may overlap, but this is OK */
267 memcpy(mceP->data, oldData, mceP->size);
269 afs_osi_Free(oldData,mceP->dataSize);
270 mceP->dataSize = size+offset;
272 if (mceP->size < offset)
273 memset(mceP->data+mceP->size, 0, offset-mceP->size);
274 for (bytesWritten = 0, i = 0 ; i < nio && size > 0 ; i++) {
275 bytesToWrite = (size < iov[i].iov_len) ? size : iov[i].iov_len;
277 memcpy(mceP->data + offset, iov[i].iov_base, bytesToWrite);
279 offset += bytesToWrite;
280 bytesWritten += bytesToWrite;
281 size -= bytesToWrite;
283 mceP->size = (offset < mceP->size) ? mceP->size : offset;
285 MReleaseWriteLock(&mceP->afs_memLock);
289 afs_MemWriteUIO(blkno, uioP)
293 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
296 AFS_STATCNT(afs_MemWriteUIO);
297 MObtainWriteLock(&mceP->afs_memLock,312);
298 if(uioP->uio_resid + uioP->uio_offset > mceP->dataSize) {
299 char *oldData = mceP->data;
301 mceP->data = afs_osi_Alloc(uioP->uio_resid + uioP->uio_offset);
304 memcpy(mceP->data, oldData, mceP->size);
307 afs_osi_Free(oldData,mceP->dataSize);
308 mceP->dataSize = uioP->uio_resid + uioP->uio_offset;
310 if (mceP->size < uioP->uio_offset)
311 memset(mceP->data+mceP->size, 0, (int)(uioP->uio_offset-mceP->size));
312 AFS_UIOMOVE(mceP->data+uioP->uio_offset, uioP->uio_resid, UIO_WRITE, uioP, code);
313 if (uioP->uio_offset > mceP->size)
314 mceP->size = uioP->uio_offset;
316 MReleaseWriteLock(&mceP->afs_memLock);
320 afs_MemCacheTruncate(mceP, size)
321 register struct memCacheEntry *mceP;
324 AFS_STATCNT(afs_MemCacheTruncate);
326 MObtainWriteLock(&mceP->afs_memLock,313);
327 /* old directory entry; g.c. */
328 if(size == 0 && mceP->dataSize > memCacheBlkSize) {
329 afs_osi_Free(mceP->data, mceP->dataSize);
330 mceP->data = afs_osi_Alloc(memCacheBlkSize);
331 mceP->dataSize = memCacheBlkSize;
334 if (size < mceP->size)
337 MReleaseWriteLock(&mceP->afs_memLock);
341 afs_MemCacheStoreProc(acall, mceP, alen, avc, shouldWake, abytesToXferP, abytesXferredP)
342 register struct memCacheEntry *mceP;
343 register struct rx_call *acall;
344 register afs_int32 alen;
347 afs_int32 *abytesToXferP;
348 afs_int32 *abytesXferredP;
352 register afs_int32 code;
355 struct iovec *tiov; /* no data copying with iovec */
356 int tnio; /* temp for iovec size */
358 AFS_STATCNT(afs_MemCacheStoreProc);
361 * In this case, alen is *always* the amount of data we'll be trying
364 *(abytesToXferP) = alen;
365 *(abytesXferredP) = 0;
366 #endif /* AFS_NOSTATS */
369 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
370 * declare them on the stack - defect 11272
372 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
374 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
378 /* do this at a higher level now -- it's a parameter */
379 /* for now, only do 'continue from close' code if file fits in one
380 chunk. Could clearly do better: if only one modified chunk
381 then can still do this. can do this on *last* modified chunk */
382 tlen = avc->m.Length-1; /* byte position of last byte we'll store */
384 if (AFS_CHUNK(tlen) != 0) *shouldWake = 0;
385 else *shouldWake = 1;
390 tlen = (alen > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : alen);
391 code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
393 osi_FreeSmallSpace(tiov);
397 code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
399 osi_FreeSmallSpace(tiov);
402 code = rx_Writev(acall, tiov, tnio, tlen);
404 (*abytesXferredP) += code;
405 #endif /* AFS_NOSTATS */
407 osi_FreeSmallSpace(tiov);
412 /* if file has been locked on server, can allow store to continue */
413 if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
414 *shouldWake = 0; /* only do this once */
418 osi_FreeSmallSpace(tiov);
422 afs_MemCacheFetchProc(acall, mceP, abase, adc, avc, abytesToXferP, abytesXferredP)
423 register struct rx_call *acall;
427 register struct memCacheEntry *mceP;
428 afs_int32 *abytesToXferP;
429 afs_int32 *abytesXferredP;
433 register afs_int32 code;
434 register int tlen, offset=0;
436 struct iovec *tiov; /* no data copying with iovec */
437 int tnio; /* temp for iovec size */
439 AFS_STATCNT(afs_MemCacheFetchProc);
441 (*abytesToXferP) = 0;
442 (*abytesXferredP) = 0;
443 #endif /* AFS_NOSTATS */
445 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
446 * declare them on the stack - defect 11272
448 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
450 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
453 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
454 if (code != sizeof(afs_int32)) {
455 code = rx_Error(acall);
456 osi_FreeSmallSpace(tiov);
457 return (code?code:-1); /* try to return code, not -1 */
459 length = ntohl(length);
461 * The fetch protocol is extended for the AFS/DFS translator
462 * to allow multiple blocks of data, each with its own length,
463 * to be returned. As long as the top bit is set, there are more
466 * We do not do this for AFS file servers because they sometimes
467 * return large negative numbers as the transfer size.
469 if (avc->states & CForeign) {
470 moredata = length & 0x80000000;
471 length &= ~0x80000000;
476 (*abytesToXferP) += length;
477 #endif /* AFS_NOSTATS */
479 tlen = (length > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : length);
480 code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
482 (*abytesXferredP) += code;
483 #endif /* AFS_NOSTATS */
485 osi_FreeSmallSpace(tiov);
489 afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
493 adc->validPos = abase;
494 if (adc->flags & DFWaiting) {
495 adc->flags &= ~DFWaiting;
496 afs_osi_Wakeup(&adc->validPos);
500 /* max of two sizes */
501 osi_FreeSmallSpace(tiov);
506 void shutdown_memcache()
510 if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
512 memCacheBlkSize = 8192;
513 for (index = 0; index < memMaxBlkNumber; index++) {
514 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
515 afs_osi_Free((memCache+index)->data, (memCache+index)->dataSize);
517 afs_osi_Free((char *)memCache, memMaxBlkNumber * sizeof(struct memCacheEntry));