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 "../afs/param.h" /* Should be always first */
11 #include "../afs/sysincludes.h" /* Standard vendor system headers */
12 #ifndef AFS_LINUX22_ENV
13 #include "../rpc/types.h"
21 #endif /* AFS_ALPHA_ENV */
22 #include "../afs/afsincludes.h" /* Afs-based standard headers */
23 #include "../afs/afs_stats.h" /* statistics */
25 /* memory cache routines */
27 struct memCacheEntry {
28 int size; /* # of valid bytes in this entry */
29 int dataSize; /* size of allocated data area */
30 afs_lock_t afs_memLock;
31 char *data; /* bytes */
34 static struct memCacheEntry *memCache;
35 static int memCacheBlkSize = 8192;
36 static int memMaxBlkNumber = 0;
37 static int memAllocMaySleep = 0;
39 extern int cacheDiskType;
41 afs_InitMemCache(size, blkSize, flags)
48 AFS_STATCNT(afs_InitMemCache);
50 memCacheBlkSize = blkSize;
52 memMaxBlkNumber = size / memCacheBlkSize;
53 memCache = (struct memCacheEntry *)
54 afs_osi_Alloc(memMaxBlkNumber * sizeof(struct memCacheEntry));
55 if (flags & AFSCALL_INIT_MEMCACHE_SLEEP) {
59 for(index = 0; index < memMaxBlkNumber; index++) {
61 (memCache+index)->size = 0;
62 (memCache+index)->dataSize = memCacheBlkSize;
63 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
64 if (memAllocMaySleep) {
65 blk = afs_osi_Alloc(memCacheBlkSize);
67 blk = afs_osi_Alloc_NoSleep(memCacheBlkSize);
71 (memCache+index)->data = blk;
72 bzero((memCache+index)->data, memCacheBlkSize);
74 #if defined(AFS_SGI62_ENV) || defined(AFS_HAVE_VXFS)
75 afs_InitDualFSCacheOps((struct vnode*)0);
81 printf("afsd: memCache allocation failure at %d KB.\n",
82 (index * memCacheBlkSize) / 1024);
84 afs_osi_Free((memCache+index)->data, memCacheBlkSize);
85 (memCache+index)->data = NULL;
91 afs_MemCacheClose(file)
97 void *afs_MemCacheOpen(ino_t blkno)
99 struct memCacheEntry *mep;
101 if (blkno < 0 || blkno > memMaxBlkNumber) {
102 osi_Panic("afs_MemCacheOpen: invalid block #");
104 mep = (memCache + blkno);
109 * this routine simulates a read in the Memory Cache
111 afs_MemReadBlk(mceP, offset, dest, size)
113 register struct memCacheEntry *mceP;
119 MObtainReadLock(&mceP->afs_memLock);
120 AFS_STATCNT(afs_MemReadBlk);
122 MReleaseReadLock(&mceP->afs_memLock);
125 /* use min of bytes in buffer or requested size */
126 bytesRead = (size < mceP->size - offset) ? size :
131 bcopy(mceP->data + offset, dest, bytesRead);
137 MReleaseReadLock(&mceP->afs_memLock);
142 * this routine simulates a readv in the Memory Cache
144 afs_MemReadvBlk(mceP, offset, iov, nio, size)
146 register struct memCacheEntry *mceP;
155 MObtainReadLock(&mceP->afs_memLock);
156 AFS_STATCNT(afs_MemReadBlk);
158 MReleaseReadLock(&mceP->afs_memLock);
161 /* use min of bytes in buffer or requested size */
162 bytesRead = (size < mceP->size - offset) ? size :
166 for (i = 0 , size = bytesRead ; i < nio && size > 0 ; i++) {
167 bytesToRead = (size < iov[i].iov_len) ? size : iov[i].iov_len;
169 bcopy(mceP->data + offset, iov[i].iov_base, bytesToRead);
171 offset += bytesToRead;
178 MReleaseReadLock(&mceP->afs_memLock);
182 afs_MemReadUIO(blkno, uioP)
186 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
187 int length = mceP->size - uioP->uio_offset;
190 AFS_STATCNT(afs_MemReadUIO);
191 MObtainReadLock(&mceP->afs_memLock);
192 length = (length < uioP->uio_resid) ? length : uioP->uio_resid;
193 AFS_UIOMOVE(mceP->data + uioP->uio_offset, length, UIO_READ, uioP, code);
194 MReleaseReadLock(&mceP->afs_memLock);
198 /*XXX: this extends a block arbitrarily to support big directories */
199 afs_MemWriteBlk(mceP, offset, src, size)
200 register struct memCacheEntry *mceP;
205 AFS_STATCNT(afs_MemWriteBlk);
206 MObtainWriteLock(&mceP->afs_memLock,560);
207 if (size + offset > mceP->dataSize) {
208 char *oldData = mceP->data;
210 if (memAllocMaySleep) {
211 mceP->data = afs_osi_Alloc(size+offset);
213 mceP->data = afs_osi_Alloc_NoSleep(size+offset);
215 if ( mceP->data == NULL ) /* no available memory */
217 mceP->data = oldData; /* revert back change that was made */
218 MReleaseWriteLock(&mceP->afs_memLock);
219 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
224 /* may overlap, but this is OK */
226 bcopy(oldData, mceP->data, mceP->size);
228 afs_osi_Free(oldData,mceP->dataSize);
229 mceP->dataSize = size+offset;
232 if (mceP->size < offset)
233 bzero(mceP->data+mceP->size, offset-mceP->size);
234 bcopy(src, mceP->data + offset, size);
236 mceP->size = (size+offset < mceP->size) ? mceP->size :
239 MReleaseWriteLock(&mceP->afs_memLock);
243 /*XXX: this extends a block arbitrarily to support big directories */
244 afs_MemWritevBlk(mceP, offset, iov, nio, size)
245 register struct memCacheEntry *mceP;
254 AFS_STATCNT(afs_MemWriteBlk);
255 MObtainWriteLock(&mceP->afs_memLock,561);
256 if (size + offset > mceP->dataSize) {
257 char *oldData = mceP->data;
259 mceP->data = afs_osi_Alloc(size+offset);
261 /* may overlap, but this is OK */
263 bcopy(oldData, mceP->data, mceP->size);
265 afs_osi_Free(oldData,mceP->dataSize);
266 mceP->dataSize = size+offset;
268 if (mceP->size < offset)
269 bzero(mceP->data+mceP->size, offset-mceP->size);
270 for (bytesWritten = 0, i = 0 ; i < nio && size > 0 ; i++) {
271 bytesToWrite = (size < iov[i].iov_len) ? size : iov[i].iov_len;
273 bcopy(iov[i].iov_base, mceP->data + offset, bytesToWrite);
275 offset += bytesToWrite;
276 bytesWritten += bytesToWrite;
277 size -= bytesToWrite;
279 mceP->size = (offset < mceP->size) ? mceP->size : offset;
281 MReleaseWriteLock(&mceP->afs_memLock);
285 afs_MemWriteUIO(blkno, uioP)
289 register struct memCacheEntry *mceP = (struct memCacheEntry *)afs_MemCacheOpen(blkno);
292 AFS_STATCNT(afs_MemWriteUIO);
293 MObtainWriteLock(&mceP->afs_memLock,312);
294 if(uioP->uio_resid + uioP->uio_offset > mceP->dataSize) {
295 char *oldData = mceP->data;
297 mceP->data = afs_osi_Alloc(uioP->uio_resid + uioP->uio_offset);
300 bcopy(oldData, mceP->data, mceP->size);
303 afs_osi_Free(oldData,mceP->dataSize);
304 mceP->dataSize = uioP->uio_resid + uioP->uio_offset;
306 if (mceP->size < uioP->uio_offset)
307 bzero(mceP->data+mceP->size, (int)(uioP->uio_offset-mceP->size));
308 AFS_UIOMOVE(mceP->data+uioP->uio_offset, uioP->uio_resid, UIO_WRITE, uioP, code);
309 if (uioP->uio_offset > mceP->size)
310 mceP->size = uioP->uio_offset;
312 MReleaseWriteLock(&mceP->afs_memLock);
316 afs_MemCacheTruncate(mceP, size)
317 register struct memCacheEntry *mceP;
320 AFS_STATCNT(afs_MemCacheTruncate);
322 MObtainWriteLock(&mceP->afs_memLock,313);
323 /* old directory entry; g.c. */
324 if(size == 0 && mceP->dataSize > memCacheBlkSize) {
325 afs_osi_Free(mceP->data, mceP->dataSize);
326 mceP->data = afs_osi_Alloc(memCacheBlkSize);
327 mceP->dataSize = memCacheBlkSize;
330 if (size < mceP->size)
333 MReleaseWriteLock(&mceP->afs_memLock);
337 afs_MemCacheStoreProc(acall, mceP, alen, avc, shouldWake, abytesToXferP, abytesXferredP)
338 register struct memCacheEntry *mceP;
339 register struct rx_call *acall;
340 register afs_int32 alen;
343 afs_int32 *abytesToXferP;
344 afs_int32 *abytesXferredP;
348 register afs_int32 code;
351 struct iovec *tiov; /* no data copying with iovec */
352 int tnio; /* temp for iovec size */
354 AFS_STATCNT(afs_MemCacheStoreProc);
357 * In this case, alen is *always* the amount of data we'll be trying
360 *(abytesToXferP) = alen;
361 *(abytesXferredP) = 0;
362 #endif /* AFS_NOSTATS */
365 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
366 * declare them on the stack - defect 11272
368 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
370 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
374 /* do this at a higher level now -- it's a parameter */
375 /* for now, only do 'continue from close' code if file fits in one
376 chunk. Could clearly do better: if only one modified chunk
377 then can still do this. can do this on *last* modified chunk */
378 tlen = avc->m.Length-1; /* byte position of last byte we'll store */
380 if (AFS_CHUNK(tlen) != 0) *shouldWake = 0;
381 else *shouldWake = 1;
386 tlen = (alen > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : alen);
387 code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
389 osi_FreeSmallSpace(tiov);
393 code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
395 osi_FreeSmallSpace(tiov);
398 code = rx_Writev(acall, tiov, tnio, tlen);
400 (*abytesXferredP) += code;
401 #endif /* AFS_NOSTATS */
403 osi_FreeSmallSpace(tiov);
408 /* if file has been locked on server, can allow store to continue */
409 if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
410 *shouldWake = 0; /* only do this once */
414 osi_FreeSmallSpace(tiov);
418 afs_MemCacheFetchProc(acall, mceP, abase, adc, avc, abytesToXferP, abytesXferredP)
419 register struct rx_call *acall;
423 register struct memCacheEntry *mceP;
424 afs_int32 *abytesToXferP;
425 afs_int32 *abytesXferredP;
429 register afs_int32 code;
430 register int tlen, offset=0;
432 struct iovec *tiov; /* no data copying with iovec */
433 int tnio; /* temp for iovec size */
435 AFS_STATCNT(afs_MemCacheFetchProc);
437 (*abytesToXferP) = 0;
438 (*abytesXferredP) = 0;
439 #endif /* AFS_NOSTATS */
441 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
442 * declare them on the stack - defect 11272
444 tiov = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec)*RX_MAXIOVECS);
446 osi_Panic("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
449 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
450 if (code != sizeof(afs_int32)) {
451 code = rx_Error(acall);
452 osi_FreeSmallSpace(tiov);
453 return (code?code:-1); /* try to return code, not -1 */
455 length = ntohl(length);
457 * The fetch protocol is extended for the AFS/DFS translator
458 * to allow multiple blocks of data, each with its own length,
459 * to be returned. As long as the top bit is set, there are more
462 * We do not do this for AFS file servers because they sometimes
463 * return large negative numbers as the transfer size.
465 if (avc->states & CForeign) {
466 moredata = length & 0x80000000;
467 length &= ~0x80000000;
472 (*abytesToXferP) += length;
473 #endif /* AFS_NOSTATS */
475 tlen = (length > AFS_LRALLOCSIZ? AFS_LRALLOCSIZ : length);
476 code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
478 (*abytesXferredP) += code;
479 #endif /* AFS_NOSTATS */
481 osi_FreeSmallSpace(tiov);
485 afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
489 adc->validPos = abase;
490 if (adc->flags & DFWaiting) {
491 adc->flags &= ~DFWaiting;
492 afs_osi_Wakeup(&adc->validPos);
496 /* max of two sizes */
497 osi_FreeSmallSpace(tiov);
502 void shutdown_memcache()
506 if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
508 memCacheBlkSize = 8192;
509 for (index = 0; index < memMaxBlkNumber; index++) {
510 LOCK_INIT(&((memCache+index)->afs_memLock), "afs_memLock");
511 afs_osi_Free((memCache+index)->data, (memCache+index)->dataSize);
513 afs_osi_Free((char *)memCache, memMaxBlkNumber * sizeof(struct memCacheEntry));