676d523ebe011909590862bb9fde72dd7f8ca0bf
[openafs.git] / src / afs / afs_osi_alloc.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
15
16 #include "afs/sysincludes.h"    /* Standard vendor system headers */
17 #include "afsincludes.h"        /* Afs-based standard headers */
18 #include "afs/afs_stats.h"      /* afs statistics */
19
20
21
22 #ifdef AFS_AIX41_ENV
23 #include "sys/lockl.h"
24 #include "sys/sleep.h"
25 #include "sys/syspest.h"
26 #include "sys/lock_def.h"
27 /*lock_t osi_fsplock = LOCK_AVAIL;*/
28 #endif
29
30 afs_lock_t osi_fsplock;
31
32 static struct osi_packet {
33     struct osi_packet *next;
34 } *freePacketList = NULL, *freeSmallList;
35 afs_lock_t osi_flplock;
36
37 static char memZero;            /* address of 0 bytes for kmem_alloc */
38
39 struct osimem {
40     struct osimem *next;
41 };
42
43 #if !defined(AFS_NBSD_ENV)
44 void *
45 afs_osi_Alloc(size_t x)
46 {
47 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
48     struct osimem *tm = NULL;
49     int size;
50 #endif
51
52     AFS_STATCNT(osi_Alloc);
53     /* 0-length allocs may return NULL ptr from AFS_KALLOC, so we special-case
54      * things so that NULL returned iff an error occurred */
55     if (x == 0)
56         return &memZero;
57
58     AFS_STATS(afs_stats_cmperf.OutStandingAllocs++);
59     AFS_STATS(afs_stats_cmperf.OutStandingMemUsage += x);
60 #ifdef AFS_LINUX20_ENV
61     return osi_linux_alloc(x, 1);
62 #elif defined(AFS_FBSD_ENV)
63     return osi_fbsd_alloc(x, 1);
64 #else
65     size = x;
66     tm = (struct osimem *)AFS_KALLOC(size);
67 #ifdef  AFS_SUN5_ENV
68     if (!tm)
69         osi_Panic("osi_Alloc: Couldn't allocate %d bytes; out of memory!\n",
70                   size);
71 #endif
72     return (void *)tm;
73 #endif
74 }
75
76 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
77
78 void *
79 afs_osi_Alloc_NoSleep(size_t x)
80 {
81     struct osimem *tm;
82     int size;
83
84     AFS_STATCNT(osi_Alloc);
85     /* 0-length allocs may return NULL ptr from AFS_KALLOC, so we special-case
86      * things so that NULL returned iff an error occurred */
87     if (x == 0)
88         return &memZero;
89
90     size = x;
91     AFS_STATS(afs_stats_cmperf.OutStandingAllocs++);
92     AFS_STATS(afs_stats_cmperf.OutStandingMemUsage += x);
93     tm = (struct osimem *)AFS_KALLOC_NOSLEEP(size);
94     return (void *)tm;
95 }
96
97 #endif /* SUN || SGI */
98
99 void
100 afs_osi_Free(void *x, size_t asize)
101 {
102     AFS_STATCNT(osi_Free);
103     if (x == &memZero)
104         return;                 /* check for putting memZero back */
105
106     AFS_STATS(afs_stats_cmperf.OutStandingAllocs--);
107     AFS_STATS(afs_stats_cmperf.OutStandingMemUsage -= asize);
108 #if defined(AFS_LINUX20_ENV)
109     osi_linux_free(x);
110 #elif defined(AFS_FBSD_ENV)
111     osi_fbsd_free(x);
112 #elif defined(AFS_OBSD_ENV)
113     osi_obsd_Free(x, asize);
114 #else
115     AFS_KFREE((struct osimem *)x, asize);
116 #endif
117 }
118
119 void
120 afs_osi_FreeStr(char *x)
121 {
122     afs_osi_Free(x, strlen(x) + 1);
123 }
124
125 /* free space allocated by AllocLargeSpace.  Also called by mclput when freeing
126  * a packet allocated by osi_NetReceive. */
127
128 void
129 osi_FreeLargeSpace(void *adata)
130 {
131
132     AFS_ASSERT_GLOCK();
133
134     AFS_STATCNT(osi_FreeLargeSpace);
135     afs_stats_cmperf.LargeBlocksActive--;
136     ObtainWriteLock(&osi_flplock, 322);
137     ((struct osi_packet *)adata)->next = freePacketList;
138     freePacketList = adata;
139     ReleaseWriteLock(&osi_flplock);
140 }
141
142 void
143 osi_FreeSmallSpace(void *adata)
144 {
145
146     AFS_ASSERT_GLOCK();
147
148     AFS_STATCNT(osi_FreeSmallSpace);
149     afs_stats_cmperf.SmallBlocksActive--;
150     ObtainWriteLock(&osi_fsplock, 323);
151     ((struct osi_packet *)adata)->next = freeSmallList;
152     freeSmallList = adata;
153     ReleaseWriteLock(&osi_fsplock);
154 }
155
156
157 /* allocate space for sender */
158 void *
159 osi_AllocLargeSpace(size_t size)
160 {
161     struct osi_packet *tp;
162
163     AFS_ASSERT_GLOCK();
164
165     AFS_STATCNT(osi_AllocLargeSpace);
166     if (size > AFS_LRALLOCSIZ)
167         osi_Panic("osi_AllocLargeSpace: size=%d\n", (int)size);
168     afs_stats_cmperf.LargeBlocksActive++;
169     if (!freePacketList) {
170         char *p;
171
172         afs_stats_cmperf.LargeBlocksAlloced++;
173         p = (char *)afs_osi_Alloc(AFS_LRALLOCSIZ);
174 #ifdef  KERNEL_HAVE_PIN
175         /*
176          * Need to pin this memory since under heavy conditions this memory
177          * could be swapped out; the problem is that we could inside rx where
178          * interrupts are disabled and thus we would panic if we don't pin it.
179          */
180         pin(p, AFS_LRALLOCSIZ);
181 #endif
182         return p;
183     }
184     ObtainWriteLock(&osi_flplock, 324);
185     tp = freePacketList;
186     if (tp)
187         freePacketList = tp->next;
188     ReleaseWriteLock(&osi_flplock);
189     return (char *)tp;
190 }
191
192
193 /* allocate space for sender */
194 void *
195 osi_AllocSmallSpace(size_t size)
196 {
197     struct osi_packet *tp;
198
199     AFS_STATCNT(osi_AllocSmallSpace);
200     if (size > AFS_SMALLOCSIZ)
201         osi_Panic("osi_AllocSmallS: size=%d\n", (int)size);
202
203     if (!freeSmallList) {
204         afs_stats_cmperf.SmallBlocksAlloced++;
205         afs_stats_cmperf.SmallBlocksActive++;
206         tp = afs_osi_Alloc(AFS_SMALLOCSIZ);
207 #ifdef KERNEL_HAVE_PIN
208         pin((char *)tp, AFS_SMALLOCSIZ);
209 #endif
210         return (char *)tp;
211     }
212     afs_stats_cmperf.SmallBlocksActive++;
213     ObtainWriteLock(&osi_fsplock, 327);
214     tp = freeSmallList;
215     if (tp)
216         freeSmallList = tp->next;
217     ReleaseWriteLock(&osi_fsplock);
218     return (char *)tp;
219 }
220
221 #endif /* !AFS_NBSD_ENV */
222
223 void
224 shutdown_osinet(void)
225 {
226     AFS_STATCNT(shutdown_osinet);
227     if (afs_cold_shutdown) {
228         struct osi_packet *tp;
229
230         while ((tp = freePacketList)) {
231             freePacketList = tp->next;
232             afs_osi_Free(tp, AFS_LRALLOCSIZ);
233 #ifdef  KERNEL_HAVE_PIN
234             unpin(tp, AFS_LRALLOCSIZ);
235 #endif
236         }
237
238         while ((tp = freeSmallList)) {
239             freeSmallList = tp->next;
240             afs_osi_Free(tp, AFS_SMALLOCSIZ);
241 #ifdef  KERNEL_HAVE_PIN
242             unpin(tp, AFS_SMALLOCSIZ);
243 #endif
244         }
245         LOCK_INIT(&osi_fsplock, "osi_fsplock");
246         LOCK_INIT(&osi_flplock, "osi_flplock");
247     }
248     if (afs_stats_cmperf.LargeBlocksActive ||
249         afs_stats_cmperf.SmallBlocksActive)
250     {
251         afs_warn("WARNING: not all blocks freed: large %d small %d\n",
252                  afs_stats_cmperf.LargeBlocksActive,
253                  afs_stats_cmperf.SmallBlocksActive);
254     }
255 }