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