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 #include <errno.h> 46 47 #ifdef __cplusplus 48 extern "C" { 49 #endif 50 51 typedef void vmem_t; 52 53 /* 54 * Flags for umem_alloc/umem_free 55 */ 56 #define UMEM_DEFAULT 0x0000 /* normal -- may fail */ 57 #define UMEM_NOFAIL 0x0100 /* Never fails */ 58 59 /* 60 * Flags for umem_cache_create() 61 */ 62 #define UMC_NODEBUG 0x00020000 63 64 #define UMEM_CACHE_NAMELEN 31 65 66 typedef int umem_nofail_callback_t(void); 67 typedef int umem_constructor_t(void *, void *, int); 68 typedef void umem_destructor_t(void *, void *); 69 typedef void umem_reclaim_t(void *); 70 71 typedef struct umem_cache { 72 char cache_name[UMEM_CACHE_NAMELEN + 1]; 73 size_t cache_bufsize; 74 size_t cache_align; 75 umem_constructor_t *cache_constructor; 76 umem_destructor_t *cache_destructor; 77 umem_reclaim_t *cache_reclaim; 78 void *cache_private; 79 void *cache_arena; 80 int cache_cflags; 81 } umem_cache_t; 82 83 /* Prototypes for functions to provide defaults for umem envvars */ 84 const char *_umem_debug_init(void); 85 const char *_umem_options_init(void); 86 const char *_umem_logging_init(void); 87 88 __attribute__((malloc, alloc_size(1))) 89 static inline void * 90 umem_alloc(size_t size, int flags) 91 { 92 void *ptr = NULL; 93 94 do { 95 ptr = malloc(size); 96 } while (ptr == NULL && (flags & UMEM_NOFAIL)); 97 98 return (ptr); 99 } 100 101 __attribute__((malloc, alloc_size(1))) 102 static inline void * 103 umem_alloc_aligned(size_t size, size_t align, int flags) 104 { 105 void *ptr = NULL; 106 int rc; 107 108 do { 109 rc = posix_memalign(&ptr, align, size); 110 } while (rc == ENOMEM && (flags & UMEM_NOFAIL)); 111 112 if (rc == EINVAL) { 113 fprintf(stderr, "%s: invalid memory alignment (%zd)\n", 114 __func__, align); 115 if (flags & UMEM_NOFAIL) 116 abort(); 117 return (NULL); 118 } 119 120 return (ptr); 121 } 122 123 __attribute__((malloc, alloc_size(1))) 124 static inline void * 125 umem_zalloc(size_t size, int flags) 126 { 127 void *ptr = NULL; 128 129 ptr = umem_alloc(size, flags); 130 if (ptr) 131 memset(ptr, 0, size); 132 133 return (ptr); 134 } 135 136 static inline void 137 umem_free(const void *ptr, size_t size __maybe_unused) 138 { 139 free((void *)ptr); 140 } 141 142 /* 143 * umem_free_aligned was added for supporting portability 144 * with non-POSIX platforms that require a different free 145 * to be used with aligned allocations. 146 */ 147 static inline void 148 umem_free_aligned(void *ptr, size_t size __maybe_unused) 149 { 150 #ifndef _WIN32 151 free((void *)ptr); 152 #else 153 _aligned_free(ptr); 154 #endif 155 } 156 157 static inline void 158 umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused) 159 {} 160 161 static inline umem_cache_t * 162 umem_cache_create( 163 const char *name, size_t bufsize, size_t align, 164 umem_constructor_t *constructor, 165 umem_destructor_t *destructor, 166 umem_reclaim_t *reclaim, 167 void *priv, void *vmp, int cflags) 168 { 169 umem_cache_t *cp; 170 171 cp = (umem_cache_t *)umem_alloc(sizeof (umem_cache_t), UMEM_DEFAULT); 172 if (cp) { 173 strlcpy(cp->cache_name, name, UMEM_CACHE_NAMELEN); 174 cp->cache_bufsize = bufsize; 175 cp->cache_align = align; 176 cp->cache_constructor = constructor; 177 cp->cache_destructor = destructor; 178 cp->cache_reclaim = reclaim; 179 cp->cache_private = priv; 180 cp->cache_arena = vmp; 181 cp->cache_cflags = cflags; 182 } 183 184 return (cp); 185 } 186 187 static inline void 188 umem_cache_destroy(umem_cache_t *cp) 189 { 190 umem_free(cp, sizeof (umem_cache_t)); 191 } 192 193 __attribute__((malloc)) 194 static inline void * 195 umem_cache_alloc(umem_cache_t *cp, int flags) 196 { 197 void *ptr = NULL; 198 199 if (cp->cache_align != 0) 200 ptr = umem_alloc_aligned( 201 cp->cache_bufsize, cp->cache_align, flags); 202 else 203 ptr = umem_alloc(cp->cache_bufsize, flags); 204 205 if (ptr && cp->cache_constructor) 206 cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT); 207 208 return (ptr); 209 } 210 211 static inline void 212 umem_cache_free(umem_cache_t *cp, void *ptr) 213 { 214 if (cp->cache_destructor) 215 cp->cache_destructor(ptr, cp->cache_private); 216 217 if (cp->cache_align != 0) 218 umem_free_aligned(ptr, cp->cache_bufsize); 219 else 220 umem_free(ptr, cp->cache_bufsize); 221 } 222 223 static inline void 224 umem_cache_reap_now(umem_cache_t *cp __maybe_unused) 225 { 226 } 227 228 #ifdef __cplusplus 229 } 230 #endif 231 232 #endif 233