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