1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/types.h>
26 #include <sys/sunddi.h>
27 #include <sys/kmem.h>
28 #include <sys/sysmacros.h>
29 #include <smbsrv/smb_kproto.h>
30 #include <smbsrv/alloc.h>
31
32 #define SMB_SMH_MAGIC 0x534D485F /* 'SMH_' */
33 #define SMB_SMH_VALID(_smh_) ASSERT((_smh_)->smh_magic == SMB_SMH_MAGIC)
34 #define SMB_MEM2SMH(_mem_) ((smb_mem_header_t *)(_mem_) - 1)
35
36 typedef struct smb_mem_header {
37 uint32_t smh_magic;
38 size_t smh_size;
39 smb_request_t *smh_sr;
40 list_node_t smh_lnd;
41 } smb_mem_header_t;
42
43 static void *smb_alloc(smb_request_t *, size_t, boolean_t);
44 static void smb_free(smb_request_t *, void *, boolean_t);
45 static void *smb_realloc(smb_request_t *, void *, size_t, boolean_t);
46
47 /*
48 * Allocate memory.
49 */
50 void *
smb_mem_alloc(size_t size)51 smb_mem_alloc(size_t size)
52 {
53 return (smb_alloc(NULL, size, B_FALSE));
54 }
55
56 /*
57 * Allocate memory and zero it out.
58 */
59 void *
smb_mem_zalloc(size_t size)60 smb_mem_zalloc(size_t size)
61 {
62 return (smb_alloc(NULL, size, B_TRUE));
63 }
64
65 /*
66 * Allocate or resize memory previously allocated.
67 *
68 * The address passed in MUST be considered invalid when this function returns.
69 */
70 void *
smb_mem_realloc(void * ptr,size_t size)71 smb_mem_realloc(void *ptr, size_t size)
72 {
73 return (smb_realloc(NULL, ptr, size, B_FALSE));
74 }
75
76 /*
77 * Allocate or resize memory previously allocated. If the new size is greater
78 * than the current size, the extra space is zeroed out. If the new size is less
79 * then the current size the space truncated is zeroed out.
80 *
81 * The address passed in MUST be considered invalid when this function returns.
82 */
83 void *
smb_mem_rezalloc(void * ptr,size_t size)84 smb_mem_rezalloc(void *ptr, size_t size)
85 {
86 return (smb_realloc(NULL, ptr, size, B_TRUE));
87 }
88
89 /*
90 * Free memory previously allocated with smb_malloc(), smb_zalloc(),
91 * smb_remalloc() or smb_rezalloc().
92 */
93 void
smb_mem_free(void * ptr)94 smb_mem_free(void *ptr)
95 {
96 smb_free(NULL, ptr, B_FALSE);
97 }
98
99 /*
100 * Free memory previously allocated with smb_mem_malloc(), smb_mem_zalloc(),
101 * smb_mem_remalloc() or smb_mem_rezalloc() or smb_mem_strdup(). The memory will
102 * be zeroed out before being actually freed.
103 */
104 void
smb_mem_zfree(void * ptr)105 smb_mem_zfree(void *ptr)
106 {
107 smb_free(NULL, ptr, B_TRUE);
108 }
109
110 /*
111 * Duplicate a string.
112 */
113 char *
smb_mem_strdup(const char * ptr)114 smb_mem_strdup(const char *ptr)
115 {
116 char *p;
117 size_t size;
118
119 size = strlen(ptr) + 1;
120 p = smb_alloc(NULL, size, B_FALSE);
121 bcopy(ptr, p, size);
122 return (p);
123 }
124
125 /*
126 * Initialize the list for request-specific temporary storage.
127 */
128 void
smb_srm_init(smb_request_t * sr)129 smb_srm_init(smb_request_t *sr)
130 {
131 list_create(&sr->sr_storage, sizeof (smb_mem_header_t),
132 offsetof(smb_mem_header_t, smh_lnd));
133 }
134
135 /*
136 * Free everything on the request-specific temporary storage list and destroy
137 * the list.
138 */
139 void
smb_srm_fini(smb_request_t * sr)140 smb_srm_fini(smb_request_t *sr)
141 {
142 smb_mem_header_t *smh;
143
144 while ((smh = list_head(&sr->sr_storage)) != NULL)
145 smb_free(sr, ++smh, B_FALSE);
146 list_destroy(&sr->sr_storage);
147 }
148
149 /*
150 * Allocate memory and associate it with the specified request.
151 * Memory allocated here can only be used for the duration of this request; it
152 * will be freed automatically on completion of the request.
153 */
154 void *
smb_srm_alloc(smb_request_t * sr,size_t size)155 smb_srm_alloc(smb_request_t *sr, size_t size)
156 {
157 return (smb_alloc(sr, size, B_FALSE));
158 }
159
160 /*
161 * Allocate memory, zero it out and associate it with the specified request.
162 * Memory allocated here can only be used for the duration of this request; it
163 * will be freed automatically on completion of the request.
164 */
165 void *
smb_srm_zalloc(smb_request_t * sr,size_t size)166 smb_srm_zalloc(smb_request_t *sr, size_t size)
167 {
168 return (smb_alloc(sr, size, B_TRUE));
169 }
170
171 /*
172 * Allocate or resize memory previously allocated for the specified request.
173 *
174 * The address passed in MUST be considered invalid when this function returns.
175 */
176 void *
smb_srm_realloc(smb_request_t * sr,void * p,size_t size)177 smb_srm_realloc(smb_request_t *sr, void *p, size_t size)
178 {
179 return (smb_realloc(sr, p, size, B_FALSE));
180 }
181
182 /*
183 * Allocate or resize memory previously allocated for the specified request. If
184 * the new size is greater than the current size, the extra space is zeroed out.
185 * If the new size is less then the current size the space truncated is zeroed
186 * out.
187 *
188 * The address passed in MUST be considered invalid when this function returns.
189 */
190 void *
smb_srm_rezalloc(smb_request_t * sr,void * p,size_t size)191 smb_srm_rezalloc(smb_request_t *sr, void *p, size_t size)
192 {
193 return (smb_realloc(sr, p, size, B_TRUE));
194 }
195
196 char *
smb_srm_strdup(smb_request_t * sr,const char * s)197 smb_srm_strdup(smb_request_t *sr, const char *s)
198 {
199 char *p;
200 size_t size;
201
202 size = strlen(s) + 1;
203 p = smb_srm_alloc(sr, size);
204 bcopy(s, p, size);
205 return (p);
206 }
207
208 /*
209 * Allocate memory.
210 *
211 * sr If not NULL, request the memory allocated must be associated with.
212 *
213 * size Size of the meory to allocate.
214 *
215 * zero If true the memory allocated will be zeroed out.
216 */
217 static void *
smb_alloc(smb_request_t * sr,size_t size,boolean_t zero)218 smb_alloc(smb_request_t *sr, size_t size, boolean_t zero)
219 {
220 smb_mem_header_t *smh;
221
222 if (zero) {
223 smh = kmem_zalloc(size + sizeof (smb_mem_header_t), KM_SLEEP);
224 } else {
225 smh = kmem_alloc(size + sizeof (smb_mem_header_t), KM_SLEEP);
226 smh->smh_sr = NULL;
227 bzero(&smh->smh_lnd, sizeof (smh->smh_lnd));
228 }
229 smh->smh_sr = sr;
230 smh->smh_size = size;
231 smh->smh_magic = SMB_SMH_MAGIC;
232 if (sr != NULL) {
233 SMB_REQ_VALID(sr);
234 list_insert_tail(&sr->sr_storage, smh);
235 }
236 return (++smh);
237 }
238
239 /*
240 * Free memory.
241 *
242 * sr If not NULL, request the memory to free is associated with.
243 *
244 * ptr Memory address
245 *
246 * zero If true the memory is zeroed out before being freed.
247 */
248 static void
smb_free(smb_request_t * sr,void * ptr,boolean_t zero)249 smb_free(smb_request_t *sr, void *ptr, boolean_t zero)
250 {
251 smb_mem_header_t *smh;
252
253 if (ptr != NULL) {
254 smh = SMB_MEM2SMH(ptr);
255 SMB_SMH_VALID(smh);
256 ASSERT(sr == smh->smh_sr);
257 if (sr != NULL) {
258 SMB_REQ_VALID(sr);
259 list_remove(&sr->sr_storage, smh);
260 }
261 if (zero)
262 bzero(ptr, smh->smh_size);
263
264 smh->smh_magic = 0;
265 kmem_free(smh, smh->smh_size + sizeof (smb_mem_header_t));
266 }
267 }
268
269 /*
270 * Allocate or resize memory previously allocated.
271 *
272 * sr If not NULL, request the memory is associated with.
273 *
274 * ptr Memory address
275 *
276 * size New size
277 *
278 * zero If true zero out the extra space or the truncated space.
279 */
280 static void *
smb_realloc(smb_request_t * sr,void * ptr,size_t size,boolean_t zero)281 smb_realloc(smb_request_t *sr, void *ptr, size_t size, boolean_t zero)
282 {
283 smb_mem_header_t *smh;
284 void *new_ptr;
285
286 if (ptr == NULL)
287 return (smb_alloc(sr, size, zero));
288
289 smh = SMB_MEM2SMH(ptr);
290 SMB_SMH_VALID(smh);
291 ASSERT(sr == smh->smh_sr);
292
293 if (size == 0) {
294 smb_free(sr, ptr, zero);
295 return (NULL);
296 }
297 if (smh->smh_size >= size) {
298 if ((zero) & (smh->smh_size > size))
299 bzero((caddr_t)ptr + size, smh->smh_size - size);
300 return (ptr);
301 }
302 new_ptr = smb_alloc(sr, size, B_FALSE);
303 bcopy(ptr, new_ptr, smh->smh_size);
304 if (zero)
305 bzero((caddr_t)new_ptr + smh->smh_size, size - smh->smh_size);
306
307 smb_free(sr, ptr, zero);
308 return (new_ptr);
309 }
310