xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_alloc.c (revision 8d0c3d29bb99f6521f2dc5058a7e4debebad7899)
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 *
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 *
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 *
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 *
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
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
105 smb_mem_zfree(void *ptr)
106 {
107 	smb_free(NULL, ptr, B_TRUE);
108 }
109 
110 /*
111  * Duplicate a string.
112  */
113 char *
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
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
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 *
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 *
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 *
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 *
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 *
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 *
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
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 *
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