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 }