LINUX 5.6: define time_t and use timespec/timespec64
[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 #include "afsincludes.h"        /* Afs-based standard headers */
16 #include "afs/afs_stats.h"      /* statistics */
17
18 /* memory cache routines */
19 static struct memCacheEntry *memCache;
20 static int memCacheBlkSize = 8192;
21 static int memMaxBlkNumber = 0;
22
23 extern int cacheDiskType;
24
25 int
26 afs_InitMemCache(int blkCount, int blkSize, int flags)
27 {
28     int index;
29
30     AFS_STATCNT(afs_InitMemCache);
31     if (blkSize)
32         memCacheBlkSize = blkSize;
33
34     memMaxBlkNumber = blkCount;
35     memCache =
36         afs_osi_Alloc(memMaxBlkNumber * sizeof(struct memCacheEntry));
37     osi_Assert(memCache != NULL);
38
39     for (index = 0; index < memMaxBlkNumber; index++) {
40         char *blk;
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);
45         if (blk == NULL)
46             goto nomem;
47         (memCache + index)->data = blk;
48         memset((memCache + index)->data, 0, memCacheBlkSize);
49     }
50 #if defined(AFS_HAVE_VXFS)
51     afs_InitDualFSCacheOps((struct vnode *)0);
52 #endif
53     for (index = 0; index < blkCount; index++)
54         afs_InitCacheFile(NULL, 0);
55     return 0;
56
57   nomem:
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;
63     }
64     return ENOMEM;
65
66 }
67
68 int
69 afs_MemCacheClose(struct osi_file *file)
70 {
71     return 0;
72 }
73
74 void *
75 afs_MemCacheOpen(afs_dcache_id_t *ainode)
76 {
77     struct memCacheEntry *mep;
78
79     if (ainode->mem < 0 || ainode->mem > memMaxBlkNumber) {
80         osi_Panic("afs_MemCacheOpen: invalid block #");
81     }
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);
85     return (void *)mep;
86 }
87
88 /*
89  * this routine simulates a read in the Memory Cache
90  */
91 int
92 afs_MemReadBlk(struct osi_file *fP, int offset, void *dest,
93                int size)
94 {
95     struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
96     int bytesRead;
97
98     ObtainReadLock(&mceP->afs_memLock);
99     AFS_STATCNT(afs_MemReadBlk);
100     if (offset < 0) {
101         ReleaseReadLock(&mceP->afs_memLock);
102         return 0;
103     }
104     /* use min of bytes in buffer or requested size */
105     bytesRead = (size < mceP->size - offset) ? size : mceP->size - offset;
106
107     if (bytesRead > 0) {
108         AFS_GUNLOCK();
109         memcpy(dest, mceP->data + offset, bytesRead);
110         AFS_GLOCK();
111     } else
112         bytesRead = 0;
113
114     ReleaseReadLock(&mceP->afs_memLock);
115     return bytesRead;
116 }
117
118 /*
119  * this routine simulates a readv in the Memory Cache
120  */
121 int
122 afs_MemReadvBlk(struct memCacheEntry *mceP, int offset,
123                 struct iovec *iov, int nio, int size)
124 {
125     int i;
126     int bytesRead;
127     int bytesToRead;
128
129     ObtainReadLock(&mceP->afs_memLock);
130     AFS_STATCNT(afs_MemReadBlk);
131     if (offset < 0) {
132         ReleaseReadLock(&mceP->afs_memLock);
133         return 0;
134     }
135     /* use min of bytes in buffer or requested size */
136     bytesRead = (size < mceP->size - offset) ? size : mceP->size - offset;
137
138     if (bytesRead > 0) {
139         for (i = 0, size = bytesRead; i < nio && size > 0; i++) {
140             bytesToRead = (size < iov[i].iov_len) ? size : iov[i].iov_len;
141             AFS_GUNLOCK();
142             memcpy(iov[i].iov_base, mceP->data + offset, bytesToRead);
143             AFS_GLOCK();
144             offset += bytesToRead;
145             size -= bytesToRead;
146         }
147         bytesRead -= size;
148     } else
149         bytesRead = 0;
150
151     ReleaseReadLock(&mceP->afs_memLock);
152     return bytesRead;
153 }
154
155 int
156 afs_MemReadUIO(afs_dcache_id_t *ainode, struct uio *uioP)
157 {
158     struct memCacheEntry *mceP =
159         (struct memCacheEntry *)afs_MemCacheOpen(ainode);
160     int length = mceP->size - AFS_UIO_OFFSET(uioP);
161     afs_int32 code;
162
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);
168     return code;
169 }
170
171 static int
172 _afs_MemExtendEntry(struct memCacheEntry *mceP, afs_uint32 size)
173 {
174     if (size > mceP->dataSize) {
175         char *oldData = mceP->data;
176
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);
181             return -ENOMEM;
182         }
183
184         /* may overlap, but this is OK */
185         AFS_GUNLOCK();
186         memcpy(mceP->data, oldData, mceP->size);
187         AFS_GLOCK();
188         afs_osi_Free(oldData, mceP->dataSize);
189         mceP->dataSize = size;
190     }
191     return 0;
192 }
193
194 int
195 afs_MemWriteBlk(struct osi_file *fP, int offset, void *src,
196                 int size)
197 {
198     struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
199     struct iovec tiov;
200
201     tiov.iov_base = src;
202     tiov.iov_len = size;
203     return afs_MemWritevBlk(mceP, offset, &tiov, 1, size);
204 }
205
206 /*XXX: this extends a block arbitrarily to support big directories */
207 int
208 afs_MemWritevBlk(struct memCacheEntry *mceP, int offset,
209                  struct iovec *iov, int nio, int size)
210 {
211     int i;
212     int bytesWritten;
213     int bytesToWrite;
214     AFS_STATCNT(afs_MemWriteBlk);
215     ObtainWriteLock(&mceP->afs_memLock, 561);
216     bytesWritten = _afs_MemExtendEntry(mceP, (offset + size));
217     if (bytesWritten != 0)
218       goto out;
219     AFS_GUNLOCK();
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;
228     }
229     mceP->size = (offset < mceP->size) ? mceP->size : offset;
230     AFS_GLOCK();
231 out:
232     ReleaseWriteLock(&mceP->afs_memLock);
233     return bytesWritten;
234 }
235
236 int
237 afs_MemWriteUIO(struct vcache *avc, afs_dcache_id_t *ainode, struct uio *uioP)
238 {
239     struct memCacheEntry *mceP =
240         (struct memCacheEntry *)afs_MemCacheOpen(ainode);
241     afs_int32 code;
242
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;
247
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)));
254             return -ENOMEM;
255         }
256
257         AFS_GUNLOCK();
258         memcpy(mceP->data, oldData, mceP->size);
259         AFS_GLOCK();
260
261         afs_osi_Free(oldData, mceP->dataSize);
262         mceP->dataSize = AFS_UIO_RESID(uioP) + AFS_UIO_OFFSET(uioP);
263     }
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,
268                 uioP, code);
269     if (AFS_UIO_OFFSET(uioP) > mceP->size)
270         mceP->size = AFS_UIO_OFFSET(uioP);
271
272     ReleaseWriteLock(&mceP->afs_memLock);
273     return code;
274 }
275
276 int
277 afs_MemCacheTruncate(struct osi_file *fP, int size)
278 {
279     struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
280     AFS_STATCNT(afs_MemCacheTruncate);
281
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",
291                      memCacheBlkSize);
292         } else {
293             afs_osi_Free(oldData, mceP->dataSize);
294             mceP->dataSize = memCacheBlkSize;
295         }
296     }
297
298     if (size < mceP->size)
299         mceP->size = size;
300
301     ReleaseWriteLock(&mceP->afs_memLock);
302     return 0;
303 }
304
305 int
306 afs_MemExtendEntry(struct memCacheEntry *mceP, afs_uint32 size)
307 {
308     int code = 0;
309     ObtainWriteLock(&mceP->afs_memLock, 560);
310     code = _afs_MemExtendEntry(mceP, size);
311     ReleaseWriteLock(&mceP->afs_memLock);
312     return code;
313 }
314
315 void
316 shutdown_memcache(void)
317 {
318     int index;
319
320     if (cacheDiskType != AFS_FCACHE_TYPE_MEM)
321         return;
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);
326     }
327     afs_osi_Free((char *)memCache,
328                  memMaxBlkNumber * sizeof(struct memCacheEntry));
329     memMaxBlkNumber = 0;
330 }