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