65fc2bdd897cdec83f0feab51dcb9628393f1d1d
[openafs.git] / src / afs / afs_memcache.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h"    /* Standard vendor system headers */
15 #ifndef AFS_LINUX22_ENV
16 #include "rpc/types.h"
17 #endif
18 #include "afsincludes.h"        /* Afs-based standard headers */
19 #include "afs/afs_stats.h"      /* statistics */
20
21 /* memory cache routines */
22 static struct memCacheEntry *memCache;
23 static int memCacheBlkSize = 8192;
24 static int memMaxBlkNumber = 0;
25
26 extern int cacheDiskType;
27
28 int
29 afs_InitMemCache(int blkCount, int blkSize, int flags)
30 {
31     int index;
32
33     AFS_STATCNT(afs_InitMemCache);
34     if (blkSize)
35         memCacheBlkSize = blkSize;
36
37     memMaxBlkNumber = blkCount;
38     memCache = (struct memCacheEntry *)
39         afs_osi_Alloc(memMaxBlkNumber * sizeof(struct memCacheEntry));
40
41     for (index = 0; index < memMaxBlkNumber; index++) {
42         char *blk;
43         (memCache + index)->size = 0;
44         (memCache + index)->dataSize = memCacheBlkSize;
45         LOCK_INIT(&((memCache + index)->afs_memLock), "afs_memLock");
46         blk = afs_osi_Alloc(memCacheBlkSize);
47         if (blk == NULL)
48             goto nomem;
49         (memCache + index)->data = blk;
50         memset((memCache + index)->data, 0, memCacheBlkSize);
51     }
52 #if defined(AFS_SGI62_ENV) || defined(AFS_HAVE_VXFS)
53     afs_InitDualFSCacheOps((struct vnode *)0);
54 #endif
55
56     return 0;
57
58   nomem:
59     printf("afsd:  memCache allocation failure at %d KB.\n",
60            (index * memCacheBlkSize) / 1024);
61     while (--index >= 0) {
62         afs_osi_Free((memCache + index)->data, memCacheBlkSize);
63         (memCache + index)->data = NULL;
64     }
65     return ENOMEM;
66
67 }
68
69 int
70 afs_MemCacheClose(struct osi_file *file)
71 {
72     return 0;
73 }
74
75 void *
76 afs_MemCacheOpen(afs_dcache_id_t *ainode)
77 {
78     struct memCacheEntry *mep;
79
80     if (ainode->mem < 0 || ainode->mem > memMaxBlkNumber) {
81         osi_Panic("afs_MemCacheOpen: invalid block #");
82     }
83     mep = (memCache + ainode->mem);
84     afs_Trace3(afs_iclSetp, CM_TRACE_MEMOPEN, ICL_TYPE_INT32, ainode->mem,
85                ICL_TYPE_POINTER, mep, ICL_TYPE_POINTER, mep ? mep->data : 0);
86     return (void *)mep;
87 }
88
89 /*
90  * this routine simulates a read in the Memory Cache 
91  */
92 int
93 afs_MemReadBlk(register struct osi_file *fP, int offset, void *dest,
94                int size)
95 {
96     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
97     int bytesRead;
98
99     ObtainReadLock(&mceP->afs_memLock);
100     AFS_STATCNT(afs_MemReadBlk);
101     if (offset < 0) {
102         ReleaseReadLock(&mceP->afs_memLock);
103         return 0;
104     }
105     /* use min of bytes in buffer or requested size */
106     bytesRead = (size < mceP->size - offset) ? size : mceP->size - offset;
107
108     if (bytesRead > 0) {
109         AFS_GUNLOCK();
110         memcpy(dest, mceP->data + offset, bytesRead);
111         AFS_GLOCK();
112     } else
113         bytesRead = 0;
114
115     ReleaseReadLock(&mceP->afs_memLock);
116     return bytesRead;
117 }
118
119 /*
120  * this routine simulates a readv in the Memory Cache 
121  */
122 int
123 afs_MemReadvBlk(register struct memCacheEntry *mceP, int offset,
124                 struct iovec *iov, int nio, int size)
125 {
126     int i;
127     int bytesRead;
128     int bytesToRead;
129
130     ObtainReadLock(&mceP->afs_memLock);
131     AFS_STATCNT(afs_MemReadBlk);
132     if (offset < 0) {
133         ReleaseReadLock(&mceP->afs_memLock);
134         return 0;
135     }
136     /* use min of bytes in buffer or requested size */
137     bytesRead = (size < mceP->size - offset) ? size : mceP->size - offset;
138
139     if (bytesRead > 0) {
140         for (i = 0, size = bytesRead; i < nio && size > 0; i++) {
141             bytesToRead = (size < iov[i].iov_len) ? size : iov[i].iov_len;
142             AFS_GUNLOCK();
143             memcpy(iov[i].iov_base, mceP->data + offset, bytesToRead);
144             AFS_GLOCK();
145             offset += bytesToRead;
146             size -= bytesToRead;
147         }
148         bytesRead -= size;
149     } else
150         bytesRead = 0;
151
152     ReleaseReadLock(&mceP->afs_memLock);
153     return bytesRead;
154 }
155
156 int
157 afs_MemReadUIO(afs_dcache_id_t *ainode, struct uio *uioP)
158 {
159     register struct memCacheEntry *mceP =
160         (struct memCacheEntry *)afs_MemCacheOpen(ainode);
161     int length = mceP->size - AFS_UIO_OFFSET(uioP);
162     afs_int32 code;
163
164     AFS_STATCNT(afs_MemReadUIO);
165     ObtainReadLock(&mceP->afs_memLock);
166     length = (length < AFS_UIO_RESID(uioP)) ? length : AFS_UIO_RESID(uioP);
167     AFS_UIOMOVE(mceP->data + AFS_UIO_OFFSET(uioP), length, UIO_READ, uioP, code);
168     ReleaseReadLock(&mceP->afs_memLock);
169     return code;
170 }
171
172 /*XXX: this extends a block arbitrarily to support big directories */
173 int
174 afs_MemWriteBlk(register struct osi_file *fP, int offset, void *src,
175                 int size)
176 {
177     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
178     AFS_STATCNT(afs_MemWriteBlk);
179     ObtainWriteLock(&mceP->afs_memLock, 560);
180     if (size + offset > mceP->dataSize) {
181         char *oldData = mceP->data;
182
183         mceP->data = afs_osi_Alloc(size + offset);
184         if (mceP->data == NULL) {       /* no available memory */
185             mceP->data = oldData;       /* revert back change that was made */
186             ReleaseWriteLock(&mceP->afs_memLock);
187             afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
188                      size + offset);
189             return -ENOMEM;
190         }
191
192         /* may overlap, but this is OK */
193         AFS_GUNLOCK();
194         memcpy(mceP->data, oldData, mceP->size);
195         AFS_GLOCK();
196         afs_osi_Free(oldData, mceP->dataSize);
197         mceP->dataSize = size + offset;
198     }
199     AFS_GUNLOCK();
200     if (mceP->size < offset)
201         memset(mceP->data + mceP->size, 0, offset - mceP->size);
202     memcpy(mceP->data + offset, src, size);
203     AFS_GLOCK();
204     mceP->size = (size + offset < mceP->size) ? mceP->size : size + offset;
205
206     ReleaseWriteLock(&mceP->afs_memLock);
207     return size;
208 }
209
210 /*XXX: this extends a block arbitrarily to support big directories */
211 int
212 afs_MemWritevBlk(register struct memCacheEntry *mceP, int offset,
213                  struct iovec *iov, int nio, int size)
214 {
215     int i;
216     int bytesWritten;
217     int bytesToWrite;
218     AFS_STATCNT(afs_MemWriteBlk);
219     ObtainWriteLock(&mceP->afs_memLock, 561);
220     if (offset + size > mceP->dataSize) {
221         char *oldData = mceP->data;
222
223         mceP->data = afs_osi_Alloc(size + offset);
224         if (mceP->data == NULL) {       /* no available memory */
225             mceP->data = oldData;       /* revert back change that was made */
226             ReleaseWriteLock(&mceP->afs_memLock);
227             afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
228                      size + offset);
229             return -ENOMEM;
230         }
231
232         /* may overlap, but this is OK */
233         AFS_GUNLOCK();
234         memcpy(mceP->data, oldData, mceP->size);
235         AFS_GLOCK();
236         afs_osi_Free(oldData, mceP->dataSize);
237         mceP->dataSize = size + offset;
238     }
239     AFS_GUNLOCK();
240     if (mceP->size < offset)
241         memset(mceP->data + mceP->size, 0, offset - mceP->size);
242     for (bytesWritten = 0, i = 0; i < nio && size > 0; i++) {
243         bytesToWrite = (size < iov[i].iov_len) ? size : iov[i].iov_len;
244         memcpy(mceP->data + offset, iov[i].iov_base, bytesToWrite);
245         offset += bytesToWrite;
246         bytesWritten += bytesToWrite;
247         size -= bytesToWrite;
248     }
249     mceP->size = (offset < mceP->size) ? mceP->size : offset;
250     AFS_GLOCK();
251
252     ReleaseWriteLock(&mceP->afs_memLock);
253     return bytesWritten;
254 }
255
256 int
257 afs_MemWriteUIO(afs_dcache_id_t *ainode, struct uio *uioP)
258 {
259     register struct memCacheEntry *mceP =
260         (struct memCacheEntry *)afs_MemCacheOpen(ainode);
261     afs_int32 code;
262
263     AFS_STATCNT(afs_MemWriteUIO);
264     ObtainWriteLock(&mceP->afs_memLock, 312);
265     if (AFS_UIO_RESID(uioP) + AFS_UIO_OFFSET(uioP) > mceP->dataSize) {
266         char *oldData = mceP->data;
267
268         mceP->data = afs_osi_Alloc(AFS_UIO_RESID(uioP) + AFS_UIO_OFFSET(uioP));
269         if (mceP->data == NULL) {       /* no available memory */
270             mceP->data = oldData;       /* revert back change that was made */
271             ReleaseWriteLock(&mceP->afs_memLock);
272             afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
273                      AFS_UIO_RESID(uioP) + AFS_UIO_OFFSET(uioP));
274             return -ENOMEM;
275         }
276
277         AFS_GUNLOCK();
278         memcpy(mceP->data, oldData, mceP->size);
279         AFS_GLOCK();
280
281         afs_osi_Free(oldData, mceP->dataSize);
282         mceP->dataSize = AFS_UIO_RESID(uioP) + AFS_UIO_OFFSET(uioP);
283     }
284     if (mceP->size < AFS_UIO_OFFSET(uioP))
285         memset(mceP->data + mceP->size, 0,
286                (int)(AFS_UIO_OFFSET(uioP) - mceP->size));
287     AFS_UIOMOVE(mceP->data + AFS_UIO_OFFSET(uioP), AFS_UIO_RESID(uioP), UIO_WRITE,
288                 uioP, code);
289     if (AFS_UIO_OFFSET(uioP) > mceP->size)
290         mceP->size = AFS_UIO_OFFSET(uioP);
291
292     ReleaseWriteLock(&mceP->afs_memLock);
293     return code;
294 }
295
296 int
297 afs_MemCacheTruncate(register struct osi_file *fP, int size)
298 {
299     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
300     AFS_STATCNT(afs_MemCacheTruncate);
301
302     ObtainWriteLock(&mceP->afs_memLock, 313);
303     /* old directory entry; g.c. */
304     if (size == 0 && mceP->dataSize > memCacheBlkSize) {
305         char *oldData = mceP->data;
306         mceP->data = afs_osi_Alloc(memCacheBlkSize);
307         if (mceP->data == NULL) {       /* no available memory */
308             mceP->data = oldData;
309             ReleaseWriteLock(&mceP->afs_memLock);
310             afs_warn("afs: afs_MemWriteBlk mem alloc failure (%d bytes)\n",
311                      memCacheBlkSize);
312         } else {
313             afs_osi_Free(oldData, mceP->dataSize);
314             mceP->dataSize = memCacheBlkSize;
315         }
316     }
317
318     if (size < mceP->size)
319         mceP->size = size;
320
321     ReleaseWriteLock(&mceP->afs_memLock);
322     return 0;
323 }
324
325
326 void
327 shutdown_memcache(void)
328 {
329     register int index;
330
331     if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
332         return;
333     memCacheBlkSize = 8192;
334     for (index = 0; index < memMaxBlkNumber; index++) {
335         LOCK_INIT(&((memCache + index)->afs_memLock), "afs_memLock");
336         afs_osi_Free((memCache + index)->data, (memCache + index)->dataSize);
337     }
338     afs_osi_Free((char *)memCache,
339                  memMaxBlkNumber * sizeof(struct memCacheEntry));
340     memMaxBlkNumber = 0;
341 }