3 * (C) Copyright 1990 Transarc Corporation
7 #include "../afs/param.h" /* Should be always first */
8 #include "../afs/sysincludes.h" /* Standard vendor system headers */
9 #ifndef AFS_LINUX22_ENV
10 #include "../rpc/types.h"
18 #endif /* AFS_ALPHA_ENV */
19 #include "../afs/afsincludes.h" /* Afs-based standard headers */
20 #include "../afs/afs_stats.h" /* statistics */
22 /* memory cache routines */
24 struct memCacheEntry {
25 int size; /* # of valid bytes in this entry */
26 int dataSize; /* size of allocated data area */
27 afs_lock_t afs_memLock;
28 char *data; /* bytes */
31 static struct memCacheEntry *memCache;
32 static int memCacheBlkSize = 8192;
33 static int memMaxBlkNumber = 0;
34 static int memAllocMaySleep = 0;
36 extern int cacheDiskType;
38 afs_InitMemCache(size, blkSize, flags)
45 AFS_STATCNT(afs_InitMemCache);
47 memCacheBlkSize = blkSize;
49 memMaxBlkNumber = size / memCacheBlkSize;
50 memCache = (struct memCacheEntry *)
51 afs_osi_Alloc(memMaxBlkNumber * sizeof(struct memCacheEntry));
52 if (flags & AFSCALL_INIT_MEMCACHE_SLEEP) {
56 for(index = 0; index < memMaxBlkNumber; index++) {
58 (memCache+index)->size = 0;
59 (memCache+index)->dataSize = memCacheBlkSize;
60 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
61 if (memAllocMaySleep) {
62 blk = afs_osi_Alloc(memCacheBlkSize);
64 blk = afs_osi_Alloc_NoSleep(memCacheBlkSize);
68 (memCache+index)->data = blk;
69 bzero((memCache+index)->data, memCacheBlkSize);
71 #if defined(AFS_SGI62_ENV) || defined(AFS_HAVE_VXFS)
72 afs_InitDualFSCacheOps((struct vnode*)0);
78 printf("afsd: memCache allocation failure at %d KB.\n",
79 (index * memCacheBlkSize) / 1024);
81 afs_osi_Free((memCache+index)->data, memCacheBlkSize);
82 (memCache+index)->data = NULL;
88 afs_MemCacheClose(file)
94 void *afs_MemCacheOpen(ino_t blkno)
96 struct memCacheEntry *mep;
98 if (blkno < 0 || blkno > memMaxBlkNumber) {
99 osi_Panic("afs_MemCacheOpen: invalid block #");
101 mep = (memCache + blkno);
106 * this routine simulates a read in the Memory Cache
108 afs_MemReadBlk(mceP, offset, dest, size)
110 register struct memCacheEntry *mceP;
116 MObtainReadLock(&mceP->afs_memLock);
117 AFS_STATCNT(afs_MemReadBlk);
119 MReleaseReadLock(&mceP->afs_memLock);
122 /* use min of bytes in buffer or requested size */
123 bytesRead = (size < mceP->size - offset) ? size :
128 bcopy(mceP->data + offset, dest, bytesRead);
134 MReleaseReadLock(&mceP->afs_memLock);
139 * this routine simulates a readv in the Memory Cache
141 afs_MemReadvBlk(mceP, offset, iov, nio, size)
143 register struct memCacheEntry *mceP;
152 MObtainReadLock(&mceP->afs_memLock);
153 AFS_STATCNT(afs_MemReadBlk);
155 MReleaseReadLock(&mceP->afs_memLock);
158 /* use min of bytes in buffer or requested size */
159 bytesRead = (size < mceP->size - offset) ? size :
163 for (i = 0 , size = bytesRead ; i < nio && size > 0 ; i++) {
164 bytesToRead = (size < iov[i].iov_len) ? size : iov[i].iov_len;
166 bcopy(mceP->data + offset, iov[i].iov_base, bytesToRead);
168 offset += bytesToRead;
175 MReleaseReadLock(&mceP->afs_memLock);
179 afs_MemReadUIO(blkno, uioP)
183 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
184 int length = mceP->size - uioP->uio_offset;
187 AFS_STATCNT(afs_MemReadUIO);
188 MObtainReadLock(&mceP->afs_memLock);
189 length = (length < uioP->uio_resid) ? length : uioP->uio_resid;
190 AFS_UIOMOVE(mceP->data + uioP->uio_offset, length, UIO_READ, uioP, code);
191 MReleaseReadLock(&mceP->afs_memLock);
195 /*XXX: this extends a block arbitrarily to support big directories */
196 afs_MemWriteBlk(mceP, offset, src, size)
197 register struct memCacheEntry *mceP;
202 AFS_STATCNT(afs_MemWriteBlk);
203 MObtainWriteLock(&mceP->afs_memLock,560);
204 if (size + offset > mceP->dataSize) {
205 char *oldData = mceP->data;
207 if (memAllocMaySleep) {
208 mceP->data = afs_osi_Alloc(size+offset);
210 mceP->data = afs_osi_Alloc_NoSleep(size+offset);
212 if ( mceP->data == NULL ) /* no available memory */
214 mceP->data = oldData; /* revert back change that was made */
215 MReleaseWriteLock(&mceP->afs_memLock);
216 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
221 /* may overlap, but this is OK */
223 bcopy(oldData, mceP->data, mceP->size);
225 afs_osi_Free(oldData,mceP->dataSize);
226 mceP->dataSize = size+offset;
229 if (mceP->size < offset)
230 bzero(mceP->data+mceP->size, offset-mceP->size);
231 bcopy(src, mceP->data + offset, size);
233 mceP->size = (size+offset < mceP->size) ? mceP->size :
236 MReleaseWriteLock(&mceP->afs_memLock);
240 /*XXX: this extends a block arbitrarily to support big directories */
241 afs_MemWritevBlk(mceP, offset, iov, nio, size)
242 register struct memCacheEntry *mceP;
251 AFS_STATCNT(afs_MemWriteBlk);
252 MObtainWriteLock(&mceP->afs_memLock,561);
253 if (size + offset > mceP->dataSize) {
254 char *oldData = mceP->data;
256 mceP->data = afs_osi_Alloc(size+offset);
258 /* may overlap, but this is OK */
260 bcopy(oldData, mceP->data, mceP->size);
262 afs_osi_Free(oldData,mceP->dataSize);
263 mceP->dataSize = size+offset;
265 if (mceP->size < offset)
266 bzero(mceP->data+mceP->size, offset-mceP->size);
267 for (bytesWritten = 0, i = 0 ; i < nio && size > 0 ; i++) {
268 bytesToWrite = (size < iov[i].iov_len) ? size : iov[i].iov_len;
270 bcopy(iov[i].iov_base, mceP->data + offset, bytesToWrite);
272 offset += bytesToWrite;
273 bytesWritten += bytesToWrite;
274 size -= bytesToWrite;
276 mceP->size = (offset < mceP->size) ? mceP->size : offset;
278 MReleaseWriteLock(&mceP->afs_memLock);
282 afs_MemWriteUIO(blkno, uioP)
286 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
289 AFS_STATCNT(afs_MemWriteUIO);
290 MObtainWriteLock(&mceP->afs_memLock,312);
291 if(uioP->uio_resid + uioP->uio_offset > mceP->dataSize) {
292 char *oldData = mceP->data;
294 mceP->data = afs_osi_Alloc(uioP->uio_resid + uioP->uio_offset);
297 bcopy(oldData, mceP->data, mceP->size);
300 afs_osi_Free(oldData,mceP->dataSize);
301 mceP->dataSize = uioP->uio_resid + uioP->uio_offset;
303 if (mceP->size < uioP->uio_offset)
304 bzero(mceP->data+mceP->size, (int)(uioP->uio_offset-mceP->size));
305 AFS_UIOMOVE(mceP->data+uioP->uio_offset, uioP->uio_resid, UIO_WRITE, uioP, code);
306 if (uioP->uio_offset > mceP->size)
307 mceP->size = uioP->uio_offset;
309 MReleaseWriteLock(&mceP->afs_memLock);
313 afs_MemCacheTruncate(mceP, size)
314 register struct memCacheEntry *mceP;
317 AFS_STATCNT(afs_MemCacheTruncate);
319 MObtainWriteLock(&mceP->afs_memLock,313);
320 /* old directory entry; g.c. */
321 if(size == 0 && mceP->dataSize > memCacheBlkSize) {
322 afs_osi_Free(mceP->data, mceP->dataSize);
323 mceP->data = afs_osi_Alloc(memCacheBlkSize);
324 mceP->dataSize = memCacheBlkSize;
327 if (size < mceP->size)
330 MReleaseWriteLock(&mceP->afs_memLock);
334 afs_MemCacheStoreProc(acall, mceP, alen, avc, shouldWake, abytesToXferP, abytesXferredP)
335 register struct memCacheEntry *mceP;
336 register struct rx_call *acall;
337 register afs_int32 alen;
340 afs_int32 *abytesToXferP;
341 afs_int32 *abytesXferredP;
345 register afs_int32 code;
348 struct iovec *tiov; /* no data copying with iovec */
349 int tnio; /* temp for iovec size */
351 AFS_STATCNT(afs_MemCacheStoreProc);
354 * In this case, alen is *always* the amount of data we'll be trying
357 *(abytesToXferP) = alen;
358 *(abytesXferredP) = 0;
359 #endif /* AFS_NOSTATS */
362 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
363 * declare them on the stack - defect 11272
365 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
367 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
371 /* do this at a higher level now -- it's a parameter */
372 /* for now, only do 'continue from close' code if file fits in one
373 chunk. Could clearly do better: if only one modified chunk
374 then can still do this. can do this on *last* modified chunk */
375 tlen = avc->m.Length-1; /* byte position of last byte we'll store */
377 if (AFS_CHUNK(tlen) != 0) *shouldWake = 0;
378 else *shouldWake = 1;
383 tlen = (alen > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : alen);
384 code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
386 osi_FreeSmallSpace(tiov);
390 code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
392 osi_FreeSmallSpace(tiov);
395 code = rx_Writev(acall, tiov, tnio, tlen);
397 (*abytesXferredP) += code;
398 #endif /* AFS_NOSTATS */
400 osi_FreeSmallSpace(tiov);
405 /* if file has been locked on server, can allow store to continue */
406 if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
407 *shouldWake = 0; /* only do this once */
411 osi_FreeSmallSpace(tiov);
415 afs_MemCacheFetchProc(acall, mceP, abase, adc, avc, abytesToXferP, abytesXferredP)
416 register struct rx_call *acall;
420 register struct memCacheEntry *mceP;
421 afs_int32 *abytesToXferP;
422 afs_int32 *abytesXferredP;
426 register afs_int32 code;
427 register int tlen, offset=0;
429 struct iovec *tiov; /* no data copying with iovec */
430 int tnio; /* temp for iovec size */
432 AFS_STATCNT(afs_MemCacheFetchProc);
434 (*abytesToXferP) = 0;
435 (*abytesXferredP) = 0;
436 #endif /* AFS_NOSTATS */
438 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
439 * declare them on the stack - defect 11272
441 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
443 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
446 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
447 if (code != sizeof(afs_int32)) {
448 code = rx_Error(acall);
449 osi_FreeSmallSpace(tiov);
450 return (code?code:-1); /* try to return code, not -1 */
452 length = ntohl(length);
454 * The fetch protocol is extended for the AFS/DFS translator
455 * to allow multiple blocks of data, each with its own length,
456 * to be returned. As long as the top bit is set, there are more
459 * We do not do this for AFS file servers because they sometimes
460 * return large negative numbers as the transfer size.
462 if (avc->states & CForeign) {
463 moredata = length & 0x80000000;
464 length &= ~0x80000000;
469 (*abytesToXferP) += length;
470 #endif /* AFS_NOSTATS */
472 tlen = (length > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : length);
473 code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
475 (*abytesXferredP) += code;
476 #endif /* AFS_NOSTATS */
478 osi_FreeSmallSpace(tiov);
482 afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
486 adc->validPos = abase;
487 if (adc->flags & DFWaiting) {
488 adc->flags &= ~DFWaiting;
489 afs_osi_Wakeup(&adc->validPos);
493 /* max of two sizes */
494 osi_FreeSmallSpace(tiov);
499 void shutdown_memcache()
503 if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
505 memCacheBlkSize = 8192;
506 for (index = 0; index < memMaxBlkNumber; index++) {
507 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
508 afs_osi_Free((memCache+index)->data, (memCache+index)->dataSize);
510 afs_osi_Free((char *)memCache, memMaxBlkNumber * sizeof(struct memCacheEntry));