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