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