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