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