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