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