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"
14 #include "afs/sysincludes.h" /* Standard vendor system headers */
15 #include "afsincludes.h" /* Afs-based standard headers */
16 #include "afs/afs_stats.h" /* statistics */
18 /* memory cache routines */
19 static struct memCacheEntry
*memCache
;
20 static int memCacheBlkSize
= 8192;
21 static int memMaxBlkNumber
= 0;
23 extern int cacheDiskType
;
26 afs_InitMemCache(int blkCount
, int blkSize
, int flags
)
30 AFS_STATCNT(afs_InitMemCache
);
32 memCacheBlkSize
= blkSize
;
34 memMaxBlkNumber
= blkCount
;
36 afs_osi_Alloc(memMaxBlkNumber
* sizeof(struct memCacheEntry
));
37 osi_Assert(memCache
!= NULL
);
39 for (index
= 0; index
< memMaxBlkNumber
; index
++) {
41 (memCache
+ index
)->size
= 0;
42 (memCache
+ index
)->dataSize
= memCacheBlkSize
;
43 LOCK_INIT(&((memCache
+ index
)->afs_memLock
), "afs_memLock");
44 blk
= afs_osi_Alloc(memCacheBlkSize
);
47 (memCache
+ index
)->data
= blk
;
48 memset((memCache
+ index
)->data
, 0, memCacheBlkSize
);
50 #if defined(AFS_HAVE_VXFS)
51 afs_InitDualFSCacheOps((struct vnode
*)0);
53 for (index
= 0; index
< blkCount
; index
++)
54 afs_InitCacheFile(NULL
, 0);
58 afs_warn("afsd: memCache allocation failure at %d KB.\n",
59 (index
* memCacheBlkSize
) / 1024);
60 while (--index
>= 0) {
61 afs_osi_Free((memCache
+ index
)->data
, memCacheBlkSize
);
62 (memCache
+ index
)->data
= NULL
;
69 afs_MemCacheClose(struct osi_file
*file
)
75 afs_MemCacheOpen(afs_dcache_id_t
*ainode
)
77 struct memCacheEntry
*mep
;
79 if (ainode
->mem
< 0 || ainode
->mem
> memMaxBlkNumber
) {
80 osi_Panic("afs_MemCacheOpen: invalid block #");
82 mep
= (memCache
+ ainode
->mem
);
83 afs_Trace3(afs_iclSetp
, CM_TRACE_MEMOPEN
, ICL_TYPE_INT32
, ainode
->mem
,
84 ICL_TYPE_POINTER
, mep
, ICL_TYPE_POINTER
, mep
? mep
->data
: 0);
89 * this routine simulates a read in the Memory Cache
92 afs_MemReadBlk(struct osi_file
*fP
, int offset
, void *dest
,
95 struct memCacheEntry
*mceP
= (struct memCacheEntry
*)fP
;
98 ObtainReadLock(&mceP
->afs_memLock
);
99 AFS_STATCNT(afs_MemReadBlk
);
101 ReleaseReadLock(&mceP
->afs_memLock
);
104 /* use min of bytes in buffer or requested size */
105 bytesRead
= (size
< mceP
->size
- offset
) ? size
: mceP
->size
- offset
;
109 memcpy(dest
, mceP
->data
+ offset
, bytesRead
);
114 ReleaseReadLock(&mceP
->afs_memLock
);
119 * this routine simulates a readv in the Memory Cache
122 afs_MemReadvBlk(struct memCacheEntry
*mceP
, int offset
,
123 struct iovec
*iov
, int nio
, int size
)
129 ObtainReadLock(&mceP
->afs_memLock
);
130 AFS_STATCNT(afs_MemReadBlk
);
132 ReleaseReadLock(&mceP
->afs_memLock
);
135 /* use min of bytes in buffer or requested size */
136 bytesRead
= (size
< mceP
->size
- offset
) ? size
: mceP
->size
- offset
;
139 for (i
= 0, size
= bytesRead
; i
< nio
&& size
> 0; i
++) {
140 bytesToRead
= (size
< iov
[i
].iov_len
) ? size
: iov
[i
].iov_len
;
142 memcpy(iov
[i
].iov_base
, mceP
->data
+ offset
, bytesToRead
);
144 offset
+= bytesToRead
;
151 ReleaseReadLock(&mceP
->afs_memLock
);
156 afs_MemReadUIO(afs_dcache_id_t
*ainode
, struct uio
*uioP
)
158 struct memCacheEntry
*mceP
=
159 (struct memCacheEntry
*)afs_MemCacheOpen(ainode
);
160 int length
= mceP
->size
- AFS_UIO_OFFSET(uioP
);
163 AFS_STATCNT(afs_MemReadUIO
);
164 ObtainReadLock(&mceP
->afs_memLock
);
165 length
= (length
< AFS_UIO_RESID(uioP
)) ? length
: AFS_UIO_RESID(uioP
);
166 AFS_UIOMOVE(mceP
->data
+ AFS_UIO_OFFSET(uioP
), length
, UIO_READ
, uioP
, code
);
167 ReleaseReadLock(&mceP
->afs_memLock
);
172 _afs_MemExtendEntry(struct memCacheEntry
*mceP
, afs_uint32 size
)
174 if (size
> mceP
->dataSize
) {
175 char *oldData
= mceP
->data
;
177 mceP
->data
= afs_osi_Alloc(size
);
178 if (mceP
->data
== NULL
) { /* no available memory */
179 mceP
->data
= oldData
; /* revert back change that was made */
180 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n", size
);
184 /* may overlap, but this is OK */
186 memcpy(mceP
->data
, oldData
, mceP
->size
);
188 afs_osi_Free(oldData
, mceP
->dataSize
);
189 mceP
->dataSize
= size
;
195 afs_MemWriteBlk(struct osi_file
*fP
, int offset
, void *src
,
198 struct memCacheEntry
*mceP
= (struct memCacheEntry
*)fP
;
203 return afs_MemWritevBlk(mceP
, offset
, &tiov
, 1, size
);
206 /*XXX: this extends a block arbitrarily to support big directories */
208 afs_MemWritevBlk(struct memCacheEntry
*mceP
, int offset
,
209 struct iovec
*iov
, int nio
, int size
)
214 AFS_STATCNT(afs_MemWriteBlk
);
215 ObtainWriteLock(&mceP
->afs_memLock
, 561);
216 bytesWritten
= _afs_MemExtendEntry(mceP
, (offset
+ size
));
217 if (bytesWritten
!= 0)
220 if (mceP
->size
< offset
)
221 memset(mceP
->data
+ mceP
->size
, 0, offset
- mceP
->size
);
222 for (bytesWritten
= 0, i
= 0; i
< nio
&& size
> 0; i
++) {
223 bytesToWrite
= (size
< iov
[i
].iov_len
) ? size
: iov
[i
].iov_len
;
224 memcpy(mceP
->data
+ offset
, iov
[i
].iov_base
, bytesToWrite
);
225 offset
+= bytesToWrite
;
226 bytesWritten
+= bytesToWrite
;
227 size
-= bytesToWrite
;
229 mceP
->size
= (offset
< mceP
->size
) ? mceP
->size
: offset
;
232 ReleaseWriteLock(&mceP
->afs_memLock
);
237 afs_MemWriteUIO(struct vcache
*avc
, afs_dcache_id_t
*ainode
, struct uio
*uioP
)
239 struct memCacheEntry
*mceP
=
240 (struct memCacheEntry
*)afs_MemCacheOpen(ainode
);
243 AFS_STATCNT(afs_MemWriteUIO
);
244 ObtainWriteLock(&mceP
->afs_memLock
, 312);
245 if (AFS_UIO_RESID(uioP
) + AFS_UIO_OFFSET(uioP
) > mceP
->dataSize
) {
246 char *oldData
= mceP
->data
;
248 mceP
->data
= afs_osi_Alloc(AFS_UIO_RESID(uioP
) + AFS_UIO_OFFSET(uioP
));
249 if (mceP
->data
== NULL
) { /* no available memory */
250 mceP
->data
= oldData
; /* revert back change that was made */
251 ReleaseWriteLock(&mceP
->afs_memLock
);
252 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%ld bytes)\n",
253 (long)(AFS_UIO_RESID(uioP
) + AFS_UIO_OFFSET(uioP
)));
258 memcpy(mceP
->data
, oldData
, mceP
->size
);
261 afs_osi_Free(oldData
, mceP
->dataSize
);
262 mceP
->dataSize
= AFS_UIO_RESID(uioP
) + AFS_UIO_OFFSET(uioP
);
264 if (mceP
->size
< AFS_UIO_OFFSET(uioP
))
265 memset(mceP
->data
+ mceP
->size
, 0,
266 (int)(AFS_UIO_OFFSET(uioP
) - mceP
->size
));
267 AFS_UIOMOVE(mceP
->data
+ AFS_UIO_OFFSET(uioP
), AFS_UIO_RESID(uioP
), UIO_WRITE
,
269 if (AFS_UIO_OFFSET(uioP
) > mceP
->size
)
270 mceP
->size
= AFS_UIO_OFFSET(uioP
);
272 ReleaseWriteLock(&mceP
->afs_memLock
);
277 afs_MemCacheTruncate(struct osi_file
*fP
, int size
)
279 struct memCacheEntry
*mceP
= (struct memCacheEntry
*)fP
;
280 AFS_STATCNT(afs_MemCacheTruncate
);
282 ObtainWriteLock(&mceP
->afs_memLock
, 313);
283 /* old directory entry; g.c. */
284 if (size
== 0 && mceP
->dataSize
> memCacheBlkSize
) {
285 char *oldData
= mceP
->data
;
286 mceP
->data
= afs_osi_Alloc(memCacheBlkSize
);
287 if (mceP
->data
== NULL
) { /* no available memory */
288 mceP
->data
= oldData
;
289 ReleaseWriteLock(&mceP
->afs_memLock
);
290 afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
293 afs_osi_Free(oldData
, mceP
->dataSize
);
294 mceP
->dataSize
= memCacheBlkSize
;
298 if (size
< mceP
->size
)
301 ReleaseWriteLock(&mceP
->afs_memLock
);
306 afs_MemExtendEntry(struct memCacheEntry
*mceP
, afs_uint32 size
)
309 ObtainWriteLock(&mceP
->afs_memLock
, 560);
310 code
= _afs_MemExtendEntry(mceP
, size
);
311 ReleaseWriteLock(&mceP
->afs_memLock
);
316 shutdown_memcache(void)
320 if (cacheDiskType
!= AFS_FCACHE_TYPE_MEM
)
322 memCacheBlkSize
= 8192;
323 for (index
= 0; index
< memMaxBlkNumber
; index
++) {
324 LOCK_INIT(&((memCache
+ index
)->afs_memLock
), "afs_memLock");
325 afs_osi_Free((memCache
+ index
)->data
, (memCache
+ index
)->dataSize
);
327 afs_osi_Free((char *)memCache
,
328 memMaxBlkNumber
* sizeof(struct memCacheEntry
));