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