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 https://opensource.org/licenses/CDDL-1.0. 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 /* 23 * Copyright (c) 2003, 2010 Oracle and/or its affiliates. 24 * Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de> 25 */ 26 27 /* 28 * This file gets included by c files for implementing the full set 29 * of zfs_impl.h defines. 30 * 31 * It's ment for easier maintaining multiple implementations of 32 * algorithms. Look into blake3_impl.c, sha256_impl.c or sha512_impl.c 33 * for reference. 34 */ 35 36 #include <sys/zfs_context.h> 37 #include <sys/zio_checksum.h> 38 #include <sys/zfs_impl.h> 39 40 /* Two default implementations */ 41 #define IMPL_FASTEST (UINT32_MAX) 42 #define IMPL_CYCLE (UINT32_MAX - 1) 43 44 #define IMPL_READ(i) (*(volatile uint32_t *) &(i)) 45 46 /* Implementation that contains the fastest method */ 47 static IMPL_OPS_T generic_fastest_impl = { 48 .name = "fastest" 49 }; 50 51 /* Hold all supported implementations */ 52 static const IMPL_OPS_T *generic_supp_impls[ARRAY_SIZE(IMPL_ARRAY)]; 53 static uint32_t generic_supp_impls_cnt = 0; 54 55 /* Currently selected implementation */ 56 static uint32_t generic_impl_chosen = IMPL_FASTEST; 57 58 static struct generic_impl_selector { 59 const char *name; 60 uint32_t sel; 61 } generic_impl_selectors[] = { 62 { "cycle", IMPL_CYCLE }, 63 { "fastest", IMPL_FASTEST } 64 }; 65 66 /* check the supported implementations */ 67 static void 68 generic_impl_init(void) 69 { 70 int i, c; 71 72 /* init only once */ 73 if (likely(generic_supp_impls_cnt != 0)) 74 return; 75 76 /* Move supported implementations into generic_supp_impls */ 77 for (i = 0, c = 0; i < ARRAY_SIZE(IMPL_ARRAY); i++) { 78 const IMPL_OPS_T *impl = IMPL_ARRAY[i]; 79 80 if (impl->is_supported && impl->is_supported()) 81 generic_supp_impls[c++] = impl; 82 } 83 generic_supp_impls_cnt = c; 84 85 /* first init generic impl, may be changed via set_fastest() */ 86 memcpy(&generic_fastest_impl, generic_supp_impls[0], 87 sizeof (generic_fastest_impl)); 88 } 89 90 /* get number of supported implementations */ 91 static uint32_t 92 generic_impl_getcnt(void) 93 { 94 generic_impl_init(); 95 return (generic_supp_impls_cnt); 96 } 97 98 /* get id of selected implementation */ 99 static uint32_t 100 generic_impl_getid(void) 101 { 102 generic_impl_init(); 103 return (IMPL_READ(generic_impl_chosen)); 104 } 105 106 /* get name of selected implementation */ 107 static const char * 108 generic_impl_getname(void) 109 { 110 uint32_t impl = IMPL_READ(generic_impl_chosen); 111 112 generic_impl_init(); 113 switch (impl) { 114 case IMPL_FASTEST: 115 return ("fastest"); 116 case IMPL_CYCLE: 117 return ("cycle"); 118 default: 119 return (generic_supp_impls[impl]->name); 120 } 121 } 122 123 /* set implementation by id */ 124 static void 125 generic_impl_setid(uint32_t id) 126 { 127 generic_impl_init(); 128 switch (id) { 129 case IMPL_FASTEST: 130 atomic_swap_32(&generic_impl_chosen, IMPL_FASTEST); 131 break; 132 case IMPL_CYCLE: 133 atomic_swap_32(&generic_impl_chosen, IMPL_CYCLE); 134 break; 135 default: 136 ASSERT3U(id, <, generic_supp_impls_cnt); 137 atomic_swap_32(&generic_impl_chosen, id); 138 break; 139 } 140 } 141 142 /* set implementation by name */ 143 static int 144 generic_impl_setname(const char *val) 145 { 146 uint32_t impl = IMPL_READ(generic_impl_chosen); 147 size_t val_len; 148 int i, err = -EINVAL; 149 150 generic_impl_init(); 151 val_len = strlen(val); 152 while ((val_len > 0) && !!isspace(val[val_len-1])) /* trim '\n' */ 153 val_len--; 154 155 /* check mandatory implementations */ 156 for (i = 0; i < ARRAY_SIZE(generic_impl_selectors); i++) { 157 const char *name = generic_impl_selectors[i].name; 158 159 if (val_len == strlen(name) && 160 strncmp(val, name, val_len) == 0) { 161 impl = generic_impl_selectors[i].sel; 162 err = 0; 163 break; 164 } 165 } 166 167 /* check all supported implementations */ 168 if (err != 0) { 169 for (i = 0; i < generic_supp_impls_cnt; i++) { 170 const char *name = generic_supp_impls[i]->name; 171 172 if (val_len == strlen(name) && 173 strncmp(val, name, val_len) == 0) { 174 impl = i; 175 err = 0; 176 break; 177 } 178 } 179 } 180 181 if (err == 0) { 182 atomic_swap_32(&generic_impl_chosen, impl); 183 } 184 185 return (err); 186 } 187 188 /* setup id as fastest implementation */ 189 static void 190 generic_impl_set_fastest(uint32_t id) 191 { 192 generic_impl_init(); 193 memcpy(&generic_fastest_impl, generic_supp_impls[id], 194 sizeof (generic_fastest_impl)); 195 } 196 197 /* return impl iterating functions */ 198 const zfs_impl_t ZFS_IMPL_OPS = { 199 .name = IMPL_NAME, 200 .getcnt = generic_impl_getcnt, 201 .getid = generic_impl_getid, 202 .getname = generic_impl_getname, 203 .set_fastest = generic_impl_set_fastest, 204 .setid = generic_impl_setid, 205 .setname = generic_impl_setname 206 }; 207 208 /* get impl ops_t of selected implementation */ 209 const IMPL_OPS_T * 210 IMPL_GET_OPS(void) 211 { 212 const IMPL_OPS_T *ops = NULL; 213 uint32_t idx, impl = IMPL_READ(generic_impl_chosen); 214 static uint32_t cycle_count = 0; 215 216 generic_impl_init(); 217 switch (impl) { 218 case IMPL_FASTEST: 219 ops = &generic_fastest_impl; 220 break; 221 case IMPL_CYCLE: 222 idx = (++cycle_count) % generic_supp_impls_cnt; 223 ops = generic_supp_impls[idx]; 224 break; 225 default: 226 ASSERT3U(impl, <, generic_supp_impls_cnt); 227 ops = generic_supp_impls[impl]; 228 break; 229 } 230 231 ASSERT3P(ops, !=, NULL); 232 return (ops); 233 } 234