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