15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
22*12508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw */
245331Samw
255331Samw #include <sys/types.h>
265331Samw #include <sys/sunddi.h>
275331Samw #include <sys/kmem.h>
285331Samw #include <sys/sysmacros.h>
2910966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
305331Samw #include <smbsrv/alloc.h>
315331Samw
3211963SAfshin.Ardakani@Sun.COM #define SMB_SMH_MAGIC 0x534D485F /* 'SMH_' */
3311963SAfshin.Ardakani@Sun.COM #define SMB_SMH_VALID(_smh_) ASSERT((_smh_)->smh_magic == SMB_SMH_MAGIC)
3411963SAfshin.Ardakani@Sun.COM #define SMB_MEM2SMH(_mem_) ((smb_mem_header_t *)(_mem_) - 1)
355331Samw
3611963SAfshin.Ardakani@Sun.COM typedef struct smb_mem_header {
3711963SAfshin.Ardakani@Sun.COM uint32_t smh_magic;
3811963SAfshin.Ardakani@Sun.COM size_t smh_size;
3911963SAfshin.Ardakani@Sun.COM smb_request_t *smh_sr;
4011963SAfshin.Ardakani@Sun.COM list_node_t smh_lnd;
4111963SAfshin.Ardakani@Sun.COM } smb_mem_header_t;
4211963SAfshin.Ardakani@Sun.COM
4311963SAfshin.Ardakani@Sun.COM static void *smb_alloc(smb_request_t *, size_t, boolean_t);
4411963SAfshin.Ardakani@Sun.COM static void smb_free(smb_request_t *, void *, boolean_t);
4511963SAfshin.Ardakani@Sun.COM static void *smb_realloc(smb_request_t *, void *, size_t, boolean_t);
4611963SAfshin.Ardakani@Sun.COM
4711963SAfshin.Ardakani@Sun.COM /*
4811963SAfshin.Ardakani@Sun.COM * Allocate memory.
4911963SAfshin.Ardakani@Sun.COM */
505331Samw void *
smb_mem_alloc(size_t size)5111963SAfshin.Ardakani@Sun.COM smb_mem_alloc(size_t size)
525331Samw {
5311963SAfshin.Ardakani@Sun.COM return (smb_alloc(NULL, size, B_FALSE));
5411963SAfshin.Ardakani@Sun.COM }
555331Samw
5611963SAfshin.Ardakani@Sun.COM /*
5711963SAfshin.Ardakani@Sun.COM * Allocate memory and zero it out.
5811963SAfshin.Ardakani@Sun.COM */
5911963SAfshin.Ardakani@Sun.COM void *
smb_mem_zalloc(size_t size)6011963SAfshin.Ardakani@Sun.COM smb_mem_zalloc(size_t size)
6111963SAfshin.Ardakani@Sun.COM {
6211963SAfshin.Ardakani@Sun.COM return (smb_alloc(NULL, size, B_TRUE));
635331Samw }
645331Samw
6511963SAfshin.Ardakani@Sun.COM /*
6611963SAfshin.Ardakani@Sun.COM * Allocate or resize memory previously allocated.
6711963SAfshin.Ardakani@Sun.COM *
6811963SAfshin.Ardakani@Sun.COM * The address passed in MUST be considered invalid when this function returns.
6911963SAfshin.Ardakani@Sun.COM */
7011963SAfshin.Ardakani@Sun.COM void *
smb_mem_realloc(void * ptr,size_t size)7111963SAfshin.Ardakani@Sun.COM smb_mem_realloc(void *ptr, size_t size)
7211963SAfshin.Ardakani@Sun.COM {
7311963SAfshin.Ardakani@Sun.COM return (smb_realloc(NULL, ptr, size, B_FALSE));
7411963SAfshin.Ardakani@Sun.COM }
7511963SAfshin.Ardakani@Sun.COM
7611963SAfshin.Ardakani@Sun.COM /*
7711963SAfshin.Ardakani@Sun.COM * Allocate or resize memory previously allocated. If the new size is greater
7811963SAfshin.Ardakani@Sun.COM * than the current size, the extra space is zeroed out. If the new size is less
7911963SAfshin.Ardakani@Sun.COM * then the current size the space truncated is zeroed out.
8011963SAfshin.Ardakani@Sun.COM *
8111963SAfshin.Ardakani@Sun.COM * The address passed in MUST be considered invalid when this function returns.
8211963SAfshin.Ardakani@Sun.COM */
8311963SAfshin.Ardakani@Sun.COM void *
smb_mem_rezalloc(void * ptr,size_t size)8411963SAfshin.Ardakani@Sun.COM smb_mem_rezalloc(void *ptr, size_t size)
8511963SAfshin.Ardakani@Sun.COM {
8611963SAfshin.Ardakani@Sun.COM return (smb_realloc(NULL, ptr, size, B_TRUE));
8711963SAfshin.Ardakani@Sun.COM }
8811963SAfshin.Ardakani@Sun.COM
8911963SAfshin.Ardakani@Sun.COM /*
9011963SAfshin.Ardakani@Sun.COM * Free memory previously allocated with smb_malloc(), smb_zalloc(),
9111963SAfshin.Ardakani@Sun.COM * smb_remalloc() or smb_rezalloc().
9211963SAfshin.Ardakani@Sun.COM */
9311963SAfshin.Ardakani@Sun.COM void
smb_mem_free(void * ptr)9411963SAfshin.Ardakani@Sun.COM smb_mem_free(void *ptr)
9511963SAfshin.Ardakani@Sun.COM {
9611963SAfshin.Ardakani@Sun.COM smb_free(NULL, ptr, B_FALSE);
9711963SAfshin.Ardakani@Sun.COM }
9811963SAfshin.Ardakani@Sun.COM
9911963SAfshin.Ardakani@Sun.COM /*
10011963SAfshin.Ardakani@Sun.COM * Free memory previously allocated with smb_mem_malloc(), smb_mem_zalloc(),
10111963SAfshin.Ardakani@Sun.COM * smb_mem_remalloc() or smb_mem_rezalloc() or smb_mem_strdup(). The memory will
10211963SAfshin.Ardakani@Sun.COM * be zeroed out before being actually freed.
10311963SAfshin.Ardakani@Sun.COM */
10411963SAfshin.Ardakani@Sun.COM void
smb_mem_zfree(void * ptr)10511963SAfshin.Ardakani@Sun.COM smb_mem_zfree(void *ptr)
10611963SAfshin.Ardakani@Sun.COM {
10711963SAfshin.Ardakani@Sun.COM smb_free(NULL, ptr, B_TRUE);
10811963SAfshin.Ardakani@Sun.COM }
10911963SAfshin.Ardakani@Sun.COM
11011963SAfshin.Ardakani@Sun.COM /*
11111963SAfshin.Ardakani@Sun.COM * Duplicate a string.
11211963SAfshin.Ardakani@Sun.COM */
1135331Samw char *
smb_mem_strdup(const char * ptr)11411963SAfshin.Ardakani@Sun.COM smb_mem_strdup(const char *ptr)
1155331Samw {
11610966SJordan.Brown@Sun.COM char *p;
11710966SJordan.Brown@Sun.COM size_t size;
1185331Samw
1195331Samw size = strlen(ptr) + 1;
12011963SAfshin.Ardakani@Sun.COM p = smb_alloc(NULL, size, B_FALSE);
12111963SAfshin.Ardakani@Sun.COM bcopy(ptr, p, size);
1225331Samw return (p);
1235331Samw }
1245331Samw
12510966SJordan.Brown@Sun.COM /*
12610966SJordan.Brown@Sun.COM * Initialize the list for request-specific temporary storage.
12710966SJordan.Brown@Sun.COM */
12810966SJordan.Brown@Sun.COM void
smb_srm_init(smb_request_t * sr)12910966SJordan.Brown@Sun.COM smb_srm_init(smb_request_t *sr)
13010966SJordan.Brown@Sun.COM {
13111963SAfshin.Ardakani@Sun.COM list_create(&sr->sr_storage, sizeof (smb_mem_header_t),
13211963SAfshin.Ardakani@Sun.COM offsetof(smb_mem_header_t, smh_lnd));
13310966SJordan.Brown@Sun.COM }
13410966SJordan.Brown@Sun.COM
13510966SJordan.Brown@Sun.COM /*
13611963SAfshin.Ardakani@Sun.COM * Free everything on the request-specific temporary storage list and destroy
13711963SAfshin.Ardakani@Sun.COM * the list.
13810966SJordan.Brown@Sun.COM */
13910966SJordan.Brown@Sun.COM void
smb_srm_fini(smb_request_t * sr)14010966SJordan.Brown@Sun.COM smb_srm_fini(smb_request_t *sr)
14110966SJordan.Brown@Sun.COM {
14211963SAfshin.Ardakani@Sun.COM smb_mem_header_t *smh;
14310966SJordan.Brown@Sun.COM
14411963SAfshin.Ardakani@Sun.COM while ((smh = list_head(&sr->sr_storage)) != NULL)
14511963SAfshin.Ardakani@Sun.COM smb_free(sr, ++smh, B_FALSE);
14610966SJordan.Brown@Sun.COM list_destroy(&sr->sr_storage);
14710966SJordan.Brown@Sun.COM }
14810966SJordan.Brown@Sun.COM
14910966SJordan.Brown@Sun.COM /*
15010966SJordan.Brown@Sun.COM * Allocate memory and associate it with the specified request.
15111963SAfshin.Ardakani@Sun.COM * Memory allocated here can only be used for the duration of this request; it
15211963SAfshin.Ardakani@Sun.COM * will be freed automatically on completion of the request.
15310966SJordan.Brown@Sun.COM */
15410966SJordan.Brown@Sun.COM void *
smb_srm_alloc(smb_request_t * sr,size_t size)15510966SJordan.Brown@Sun.COM smb_srm_alloc(smb_request_t *sr, size_t size)
15610966SJordan.Brown@Sun.COM {
15711963SAfshin.Ardakani@Sun.COM return (smb_alloc(sr, size, B_FALSE));
15810966SJordan.Brown@Sun.COM }
15910966SJordan.Brown@Sun.COM
16010966SJordan.Brown@Sun.COM /*
16111963SAfshin.Ardakani@Sun.COM * Allocate memory, zero it out and associate it with the specified request.
16211963SAfshin.Ardakani@Sun.COM * Memory allocated here can only be used for the duration of this request; it
16311963SAfshin.Ardakani@Sun.COM * will be freed automatically on completion of the request.
16411963SAfshin.Ardakani@Sun.COM */
16511963SAfshin.Ardakani@Sun.COM void *
smb_srm_zalloc(smb_request_t * sr,size_t size)16611963SAfshin.Ardakani@Sun.COM smb_srm_zalloc(smb_request_t *sr, size_t size)
16711963SAfshin.Ardakani@Sun.COM {
16811963SAfshin.Ardakani@Sun.COM return (smb_alloc(sr, size, B_TRUE));
16911963SAfshin.Ardakani@Sun.COM }
17011963SAfshin.Ardakani@Sun.COM
17111963SAfshin.Ardakani@Sun.COM /*
17211963SAfshin.Ardakani@Sun.COM * Allocate or resize memory previously allocated for the specified request.
17311963SAfshin.Ardakani@Sun.COM *
17411963SAfshin.Ardakani@Sun.COM * The address passed in MUST be considered invalid when this function returns.
17510966SJordan.Brown@Sun.COM */
17610966SJordan.Brown@Sun.COM void *
smb_srm_realloc(smb_request_t * sr,void * p,size_t size)17710966SJordan.Brown@Sun.COM smb_srm_realloc(smb_request_t *sr, void *p, size_t size)
17810966SJordan.Brown@Sun.COM {
17911963SAfshin.Ardakani@Sun.COM return (smb_realloc(sr, p, size, B_FALSE));
18011963SAfshin.Ardakani@Sun.COM }
18111963SAfshin.Ardakani@Sun.COM
18211963SAfshin.Ardakani@Sun.COM /*
18311963SAfshin.Ardakani@Sun.COM * Allocate or resize memory previously allocated for the specified request. If
18411963SAfshin.Ardakani@Sun.COM * the new size is greater than the current size, the extra space is zeroed out.
18511963SAfshin.Ardakani@Sun.COM * If the new size is less then the current size the space truncated is zeroed
18611963SAfshin.Ardakani@Sun.COM * out.
18711963SAfshin.Ardakani@Sun.COM *
18811963SAfshin.Ardakani@Sun.COM * The address passed in MUST be considered invalid when this function returns.
18911963SAfshin.Ardakani@Sun.COM */
19011963SAfshin.Ardakani@Sun.COM void *
smb_srm_rezalloc(smb_request_t * sr,void * p,size_t size)19111963SAfshin.Ardakani@Sun.COM smb_srm_rezalloc(smb_request_t *sr, void *p, size_t size)
19211963SAfshin.Ardakani@Sun.COM {
19311963SAfshin.Ardakani@Sun.COM return (smb_realloc(sr, p, size, B_TRUE));
19411963SAfshin.Ardakani@Sun.COM }
19510966SJordan.Brown@Sun.COM
196*12508Samw@Sun.COM char *
smb_srm_strdup(smb_request_t * sr,const char * s)197*12508Samw@Sun.COM smb_srm_strdup(smb_request_t *sr, const char *s)
198*12508Samw@Sun.COM {
199*12508Samw@Sun.COM char *p;
200*12508Samw@Sun.COM size_t size;
201*12508Samw@Sun.COM
202*12508Samw@Sun.COM size = strlen(s) + 1;
203*12508Samw@Sun.COM p = smb_srm_alloc(sr, size);
204*12508Samw@Sun.COM bcopy(s, p, size);
205*12508Samw@Sun.COM return (p);
206*12508Samw@Sun.COM }
207*12508Samw@Sun.COM
20811963SAfshin.Ardakani@Sun.COM /*
20911963SAfshin.Ardakani@Sun.COM * Allocate memory.
21011963SAfshin.Ardakani@Sun.COM *
21111963SAfshin.Ardakani@Sun.COM * sr If not NULL, request the memory allocated must be associated with.
21211963SAfshin.Ardakani@Sun.COM *
21311963SAfshin.Ardakani@Sun.COM * size Size of the meory to allocate.
21411963SAfshin.Ardakani@Sun.COM *
21511963SAfshin.Ardakani@Sun.COM * zero If true the memory allocated will be zeroed out.
21611963SAfshin.Ardakani@Sun.COM */
21711963SAfshin.Ardakani@Sun.COM static void *
smb_alloc(smb_request_t * sr,size_t size,boolean_t zero)21811963SAfshin.Ardakani@Sun.COM smb_alloc(smb_request_t *sr, size_t size, boolean_t zero)
21911963SAfshin.Ardakani@Sun.COM {
22011963SAfshin.Ardakani@Sun.COM smb_mem_header_t *smh;
22110966SJordan.Brown@Sun.COM
22211963SAfshin.Ardakani@Sun.COM if (zero) {
22311963SAfshin.Ardakani@Sun.COM smh = kmem_zalloc(size + sizeof (smb_mem_header_t), KM_SLEEP);
22411963SAfshin.Ardakani@Sun.COM } else {
22511963SAfshin.Ardakani@Sun.COM smh = kmem_alloc(size + sizeof (smb_mem_header_t), KM_SLEEP);
22611963SAfshin.Ardakani@Sun.COM smh->smh_sr = NULL;
22711963SAfshin.Ardakani@Sun.COM bzero(&smh->smh_lnd, sizeof (smh->smh_lnd));
22811963SAfshin.Ardakani@Sun.COM }
22911963SAfshin.Ardakani@Sun.COM smh->smh_sr = sr;
23011963SAfshin.Ardakani@Sun.COM smh->smh_size = size;
23111963SAfshin.Ardakani@Sun.COM smh->smh_magic = SMB_SMH_MAGIC;
23211963SAfshin.Ardakani@Sun.COM if (sr != NULL) {
23311963SAfshin.Ardakani@Sun.COM SMB_REQ_VALID(sr);
23411963SAfshin.Ardakani@Sun.COM list_insert_tail(&sr->sr_storage, smh);
23511963SAfshin.Ardakani@Sun.COM }
23611963SAfshin.Ardakani@Sun.COM return (++smh);
23711963SAfshin.Ardakani@Sun.COM }
23810966SJordan.Brown@Sun.COM
23911963SAfshin.Ardakani@Sun.COM /*
24011963SAfshin.Ardakani@Sun.COM * Free memory.
24111963SAfshin.Ardakani@Sun.COM *
24211963SAfshin.Ardakani@Sun.COM * sr If not NULL, request the memory to free is associated with.
24311963SAfshin.Ardakani@Sun.COM *
24411963SAfshin.Ardakani@Sun.COM * ptr Memory address
24511963SAfshin.Ardakani@Sun.COM *
24611963SAfshin.Ardakani@Sun.COM * zero If true the memory is zeroed out before being freed.
24711963SAfshin.Ardakani@Sun.COM */
24811963SAfshin.Ardakani@Sun.COM static void
smb_free(smb_request_t * sr,void * ptr,boolean_t zero)24911963SAfshin.Ardakani@Sun.COM smb_free(smb_request_t *sr, void *ptr, boolean_t zero)
25011963SAfshin.Ardakani@Sun.COM {
25111963SAfshin.Ardakani@Sun.COM smb_mem_header_t *smh;
25211963SAfshin.Ardakani@Sun.COM
25311963SAfshin.Ardakani@Sun.COM if (ptr != NULL) {
25411963SAfshin.Ardakani@Sun.COM smh = SMB_MEM2SMH(ptr);
25511963SAfshin.Ardakani@Sun.COM SMB_SMH_VALID(smh);
25611963SAfshin.Ardakani@Sun.COM ASSERT(sr == smh->smh_sr);
25711963SAfshin.Ardakani@Sun.COM if (sr != NULL) {
25811963SAfshin.Ardakani@Sun.COM SMB_REQ_VALID(sr);
25911963SAfshin.Ardakani@Sun.COM list_remove(&sr->sr_storage, smh);
26011963SAfshin.Ardakani@Sun.COM }
26111963SAfshin.Ardakani@Sun.COM if (zero)
26211963SAfshin.Ardakani@Sun.COM bzero(ptr, smh->smh_size);
26311963SAfshin.Ardakani@Sun.COM
26411963SAfshin.Ardakani@Sun.COM smh->smh_magic = 0;
26511963SAfshin.Ardakani@Sun.COM kmem_free(smh, smh->smh_size + sizeof (smb_mem_header_t));
26611963SAfshin.Ardakani@Sun.COM }
26711963SAfshin.Ardakani@Sun.COM }
26810966SJordan.Brown@Sun.COM
26911963SAfshin.Ardakani@Sun.COM /*
27011963SAfshin.Ardakani@Sun.COM * Allocate or resize memory previously allocated.
27111963SAfshin.Ardakani@Sun.COM *
27211963SAfshin.Ardakani@Sun.COM * sr If not NULL, request the memory is associated with.
27311963SAfshin.Ardakani@Sun.COM *
27411963SAfshin.Ardakani@Sun.COM * ptr Memory address
27511963SAfshin.Ardakani@Sun.COM *
27611963SAfshin.Ardakani@Sun.COM * size New size
27711963SAfshin.Ardakani@Sun.COM *
27811963SAfshin.Ardakani@Sun.COM * zero If true zero out the extra space or the truncated space.
27911963SAfshin.Ardakani@Sun.COM */
28011963SAfshin.Ardakani@Sun.COM static void *
smb_realloc(smb_request_t * sr,void * ptr,size_t size,boolean_t zero)28111963SAfshin.Ardakani@Sun.COM smb_realloc(smb_request_t *sr, void *ptr, size_t size, boolean_t zero)
28211963SAfshin.Ardakani@Sun.COM {
28311963SAfshin.Ardakani@Sun.COM smb_mem_header_t *smh;
28411963SAfshin.Ardakani@Sun.COM void *new_ptr;
28511963SAfshin.Ardakani@Sun.COM
28611963SAfshin.Ardakani@Sun.COM if (ptr == NULL)
28711963SAfshin.Ardakani@Sun.COM return (smb_alloc(sr, size, zero));
28811963SAfshin.Ardakani@Sun.COM
28911963SAfshin.Ardakani@Sun.COM smh = SMB_MEM2SMH(ptr);
29011963SAfshin.Ardakani@Sun.COM SMB_SMH_VALID(smh);
29111963SAfshin.Ardakani@Sun.COM ASSERT(sr == smh->smh_sr);
29211963SAfshin.Ardakani@Sun.COM
29311963SAfshin.Ardakani@Sun.COM if (size == 0) {
29411963SAfshin.Ardakani@Sun.COM smb_free(sr, ptr, zero);
29511963SAfshin.Ardakani@Sun.COM return (NULL);
29611963SAfshin.Ardakani@Sun.COM }
29711963SAfshin.Ardakani@Sun.COM if (smh->smh_size >= size) {
29811963SAfshin.Ardakani@Sun.COM if ((zero) & (smh->smh_size > size))
29911963SAfshin.Ardakani@Sun.COM bzero((caddr_t)ptr + size, smh->smh_size - size);
30011963SAfshin.Ardakani@Sun.COM return (ptr);
30111963SAfshin.Ardakani@Sun.COM }
30211963SAfshin.Ardakani@Sun.COM new_ptr = smb_alloc(sr, size, B_FALSE);
30311963SAfshin.Ardakani@Sun.COM bcopy(ptr, new_ptr, smh->smh_size);
30411963SAfshin.Ardakani@Sun.COM if (zero)
30511963SAfshin.Ardakani@Sun.COM bzero((caddr_t)new_ptr + smh->smh_size, size - smh->smh_size);
30611963SAfshin.Ardakani@Sun.COM
30711963SAfshin.Ardakani@Sun.COM smb_free(sr, ptr, zero);
30811963SAfshin.Ardakani@Sun.COM return (new_ptr);
30910966SJordan.Brown@Sun.COM }
310