1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License, Version 1.0 only 7 * (the "License"). You may not use this file except in compliance 8 * with the License. 9 * 10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11 * or https://opensource.org/licenses/CDDL-1.0. 12 * See the License for the specific language governing permissions 13 * and limitations under the License. 14 * 15 * When distributing Covered Code, include this CDDL HEADER in each 16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17 * If applicable, add the following below this CDDL HEADER, with the 18 * fields enclosed by brackets "[]" replaced with your own identifying 19 * information: Portions Copyright [yyyy] [name of copyright owner] 20 * 21 * CDDL HEADER END 22 */ 23 /* 24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #ifndef _LIBSPL_UMEM_H 29 #define _LIBSPL_UMEM_H 30 31 /* 32 * XXX: We should use the real portable umem library if it is detected 33 * at configure time. However, if the library is not available, we can 34 * use a trivial malloc based implementation. This obviously impacts 35 * performance, but unless you are using a full userspace build of zpool for 36 * something other than ztest, you are likely not going to notice or care. 37 * 38 * https://labs.omniti.com/trac/portableumem 39 */ 40 #include <sys/debug.h> 41 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <string.h> 45 46 #ifdef __cplusplus 47 extern "C" { 48 #endif 49 50 typedef void vmem_t; 51 52 /* 53 * Flags for umem_alloc/umem_free 54 */ 55 #define UMEM_DEFAULT 0x0000 /* normal -- may fail */ 56 #define UMEM_NOFAIL 0x0100 /* Never fails */ 57 58 /* 59 * Flags for umem_cache_create() 60 */ 61 #define UMC_NODEBUG 0x00020000 62 63 #define UMEM_CACHE_NAMELEN 31 64 65 typedef int umem_nofail_callback_t(void); 66 typedef int umem_constructor_t(void *, void *, int); 67 typedef void umem_destructor_t(void *, void *); 68 typedef void umem_reclaim_t(void *); 69 70 typedef struct umem_cache { 71 char cache_name[UMEM_CACHE_NAMELEN + 1]; 72 size_t cache_bufsize; 73 size_t cache_align; 74 umem_constructor_t *cache_constructor; 75 umem_destructor_t *cache_destructor; 76 umem_reclaim_t *cache_reclaim; 77 void *cache_private; 78 void *cache_arena; 79 int cache_cflags; 80 } umem_cache_t; 81 82 /* Prototypes for functions to provide defaults for umem envvars */ 83 const char *_umem_debug_init(void); 84 const char *_umem_options_init(void); 85 const char *_umem_logging_init(void); 86 87 __attribute__((malloc, alloc_size(1))) 88 static inline void * 89 umem_alloc(size_t size, int flags) 90 { 91 void *ptr = NULL; 92 93 do { 94 ptr = malloc(size); 95 } while (ptr == NULL && (flags & UMEM_NOFAIL)); 96 97 return (ptr); 98 } 99 100 __attribute__((malloc, alloc_size(1))) 101 static inline void * 102 umem_alloc_aligned(size_t size, size_t align, int flags) 103 { 104 void *ptr = NULL; 105 int rc = EINVAL; 106 107 do { 108 rc = posix_memalign(&ptr, align, size); 109 } while (rc == ENOMEM && (flags & UMEM_NOFAIL)); 110 111 if (rc == EINVAL) { 112 fprintf(stderr, "%s: invalid memory alignment (%zd)\n", 113 __func__, align); 114 if (flags & UMEM_NOFAIL) 115 abort(); 116 return (NULL); 117 } 118 119 return (ptr); 120 } 121 122 __attribute__((malloc, alloc_size(1))) 123 static inline void * 124 umem_zalloc(size_t size, int flags) 125 { 126 void *ptr = NULL; 127 128 ptr = umem_alloc(size, flags); 129 if (ptr) 130 memset(ptr, 0, size); 131 132 return (ptr); 133 } 134 135 static inline void 136 umem_free(const void *ptr, size_t size __maybe_unused) 137 { 138 free((void *)ptr); 139 } 140 141 /* 142 * umem_free_aligned was added for supporting portability 143 * with non-POSIX platforms that require a different free 144 * to be used with aligned allocations. 145 */ 146 static inline void 147 umem_free_aligned(void *ptr, size_t size __maybe_unused) 148 { 149 #ifndef _WIN32 150 free((void *)ptr); 151 #else 152 _aligned_free(ptr); 153 #endif 154 } 155 156 static inline void 157 umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused) 158 {} 159 160 static inline umem_cache_t * 161 umem_cache_create( 162 const char *name, size_t bufsize, size_t align, 163 umem_constructor_t *constructor, 164 umem_destructor_t *destructor, 165 umem_reclaim_t *reclaim, 166 void *priv, void *vmp, int cflags) 167 { 168 umem_cache_t *cp; 169 170 cp = (umem_cache_t *)umem_alloc(sizeof (umem_cache_t), UMEM_DEFAULT); 171 if (cp) { 172 strlcpy(cp->cache_name, name, UMEM_CACHE_NAMELEN); 173 cp->cache_bufsize = bufsize; 174 cp->cache_align = align; 175 cp->cache_constructor = constructor; 176 cp->cache_destructor = destructor; 177 cp->cache_reclaim = reclaim; 178 cp->cache_private = priv; 179 cp->cache_arena = vmp; 180 cp->cache_cflags = cflags; 181 } 182 183 return (cp); 184 } 185 186 static inline void 187 umem_cache_destroy(umem_cache_t *cp) 188 { 189 umem_free(cp, sizeof (umem_cache_t)); 190 } 191 192 __attribute__((malloc)) 193 static inline void * 194 umem_cache_alloc(umem_cache_t *cp, int flags) 195 { 196 void *ptr = NULL; 197 198 if (cp->cache_align != 0) 199 ptr = umem_alloc_aligned( 200 cp->cache_bufsize, cp->cache_align, flags); 201 else 202 ptr = umem_alloc(cp->cache_bufsize, flags); 203 204 if (ptr && cp->cache_constructor) 205 cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT); 206 207 return (ptr); 208 } 209 210 static inline void 211 umem_cache_free(umem_cache_t *cp, void *ptr) 212 { 213 if (cp->cache_destructor) 214 cp->cache_destructor(ptr, cp->cache_private); 215 216 if (cp->cache_align != 0) 217 umem_free_aligned(ptr, cp->cache_bufsize); 218 else 219 umem_free(ptr, cp->cache_bufsize); 220 } 221 222 static inline void 223 umem_cache_reap_now(umem_cache_t *cp __maybe_unused) 224 { 225 } 226 227 #ifdef __cplusplus 228 } 229 #endif 230 231 #endif 232