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