1*1e09ff3dSPawel Jakub Dawidek /*- 2*1e09ff3dSPawel Jakub Dawidek * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 3*1e09ff3dSPawel Jakub Dawidek * All rights reserved. 4*1e09ff3dSPawel Jakub Dawidek * 5*1e09ff3dSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 6*1e09ff3dSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 7*1e09ff3dSPawel Jakub Dawidek * are met: 8*1e09ff3dSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 9*1e09ff3dSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 10*1e09ff3dSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 11*1e09ff3dSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 12*1e09ff3dSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 13*1e09ff3dSPawel Jakub Dawidek * 14*1e09ff3dSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15*1e09ff3dSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*1e09ff3dSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*1e09ff3dSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18*1e09ff3dSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*1e09ff3dSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*1e09ff3dSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*1e09ff3dSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*1e09ff3dSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*1e09ff3dSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*1e09ff3dSPawel Jakub Dawidek * SUCH DAMAGE. 25*1e09ff3dSPawel Jakub Dawidek */ 26*1e09ff3dSPawel Jakub Dawidek 27*1e09ff3dSPawel Jakub Dawidek #include <sys/cdefs.h> 28*1e09ff3dSPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 29*1e09ff3dSPawel Jakub Dawidek 30*1e09ff3dSPawel Jakub Dawidek #include <sys/param.h> 31*1e09ff3dSPawel Jakub Dawidek #include <sys/kernel.h> 32*1e09ff3dSPawel Jakub Dawidek #include <sys/malloc.h> 33*1e09ff3dSPawel Jakub Dawidek #include <sys/queue.h> 34*1e09ff3dSPawel Jakub Dawidek #include <sys/sysctl.h> 35*1e09ff3dSPawel Jakub Dawidek #include <sys/systm.h> 36*1e09ff3dSPawel Jakub Dawidek #include <sys/tree.h> 37*1e09ff3dSPawel Jakub Dawidek 38*1e09ff3dSPawel Jakub Dawidek #include <geom/geom.h> 39*1e09ff3dSPawel Jakub Dawidek 40*1e09ff3dSPawel Jakub Dawidek #include <geom/eli/g_eli.h> 41*1e09ff3dSPawel Jakub Dawidek 42*1e09ff3dSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI); 43*1e09ff3dSPawel Jakub Dawidek 44*1e09ff3dSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom_eli); 45*1e09ff3dSPawel Jakub Dawidek /* 46*1e09ff3dSPawel Jakub Dawidek * The default limit (8192 keys) will allow to cache all keys for 4TB 47*1e09ff3dSPawel Jakub Dawidek * provider with 512 bytes sectors and will take around 1MB of memory. 48*1e09ff3dSPawel Jakub Dawidek */ 49*1e09ff3dSPawel Jakub Dawidek static u_int g_eli_key_cache_limit = 8192; 50*1e09ff3dSPawel Jakub Dawidek TUNABLE_INT("kern.geom.eli.key_cache_limit", &g_eli_key_cache_limit); 51*1e09ff3dSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_eli, OID_AUTO, key_cache_limit, CTLFLAG_RDTUN, 52*1e09ff3dSPawel Jakub Dawidek &g_eli_key_cache_limit, 0, "Maximum number of encryption keys to cache"); 53*1e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_hits; 54*1e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_hits, CTLFLAG_RW, 55*1e09ff3dSPawel Jakub Dawidek &g_eli_key_cache_hits, 0, "Key cache hits"); 56*1e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_misses; 57*1e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_misses, CTLFLAG_RW, 58*1e09ff3dSPawel Jakub Dawidek &g_eli_key_cache_misses, 0, "Key cache misses"); 59*1e09ff3dSPawel Jakub Dawidek 60*1e09ff3dSPawel Jakub Dawidek struct g_eli_key { 61*1e09ff3dSPawel Jakub Dawidek /* Key value, must be first in the structure. */ 62*1e09ff3dSPawel Jakub Dawidek uint8_t gek_key[G_ELI_DATAKEYLEN]; 63*1e09ff3dSPawel Jakub Dawidek /* Key number. */ 64*1e09ff3dSPawel Jakub Dawidek uint64_t gek_keyno; 65*1e09ff3dSPawel Jakub Dawidek /* Reference counter. */ 66*1e09ff3dSPawel Jakub Dawidek int gek_count; 67*1e09ff3dSPawel Jakub Dawidek /* Keeps keys sorted by most recent use. */ 68*1e09ff3dSPawel Jakub Dawidek TAILQ_ENTRY(g_eli_key) gek_next; 69*1e09ff3dSPawel Jakub Dawidek /* Keeps keys sorted by number. */ 70*1e09ff3dSPawel Jakub Dawidek RB_ENTRY(g_eli_key) gek_link; 71*1e09ff3dSPawel Jakub Dawidek }; 72*1e09ff3dSPawel Jakub Dawidek 73*1e09ff3dSPawel Jakub Dawidek static int 74*1e09ff3dSPawel Jakub Dawidek g_eli_key_cmp(const struct g_eli_key *a, const struct g_eli_key *b) 75*1e09ff3dSPawel Jakub Dawidek { 76*1e09ff3dSPawel Jakub Dawidek 77*1e09ff3dSPawel Jakub Dawidek if (a->gek_keyno > b->gek_keyno) 78*1e09ff3dSPawel Jakub Dawidek return (1); 79*1e09ff3dSPawel Jakub Dawidek else if (a->gek_keyno < b->gek_keyno) 80*1e09ff3dSPawel Jakub Dawidek return (-1); 81*1e09ff3dSPawel Jakub Dawidek return (0); 82*1e09ff3dSPawel Jakub Dawidek } 83*1e09ff3dSPawel Jakub Dawidek 84*1e09ff3dSPawel Jakub Dawidek RB_PROTOTYPE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp); 85*1e09ff3dSPawel Jakub Dawidek RB_GENERATE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp); 86*1e09ff3dSPawel Jakub Dawidek 87*1e09ff3dSPawel Jakub Dawidek static void 88*1e09ff3dSPawel Jakub Dawidek g_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno) 89*1e09ff3dSPawel Jakub Dawidek { 90*1e09ff3dSPawel Jakub Dawidek struct { 91*1e09ff3dSPawel Jakub Dawidek char magic[4]; 92*1e09ff3dSPawel Jakub Dawidek uint8_t keyno[8]; 93*1e09ff3dSPawel Jakub Dawidek } __packed hmacdata; 94*1e09ff3dSPawel Jakub Dawidek 95*1e09ff3dSPawel Jakub Dawidek bcopy("ekey", hmacdata.magic, 4); 96*1e09ff3dSPawel Jakub Dawidek le64enc(hmacdata.keyno, keyno); 97*1e09ff3dSPawel Jakub Dawidek g_eli_crypto_hmac(sc->sc_mkey, G_ELI_MAXKEYLEN, (uint8_t *)&hmacdata, 98*1e09ff3dSPawel Jakub Dawidek sizeof(hmacdata), key->gek_key, 0); 99*1e09ff3dSPawel Jakub Dawidek key->gek_keyno = keyno; 100*1e09ff3dSPawel Jakub Dawidek key->gek_count = 0; 101*1e09ff3dSPawel Jakub Dawidek } 102*1e09ff3dSPawel Jakub Dawidek 103*1e09ff3dSPawel Jakub Dawidek static struct g_eli_key * 104*1e09ff3dSPawel Jakub Dawidek g_eli_key_allocate(struct g_eli_softc *sc, uint64_t keyno) 105*1e09ff3dSPawel Jakub Dawidek { 106*1e09ff3dSPawel Jakub Dawidek struct g_eli_key *key, *ekey, keysearch; 107*1e09ff3dSPawel Jakub Dawidek 108*1e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 109*1e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 110*1e09ff3dSPawel Jakub Dawidek 111*1e09ff3dSPawel Jakub Dawidek key = malloc(sizeof(*key), M_ELI, M_WAITOK); 112*1e09ff3dSPawel Jakub Dawidek g_eli_key_fill(sc, key, keyno); 113*1e09ff3dSPawel Jakub Dawidek 114*1e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 115*1e09ff3dSPawel Jakub Dawidek /* 116*1e09ff3dSPawel Jakub Dawidek * Recheck if the key wasn't added while we weren't holding the lock. 117*1e09ff3dSPawel Jakub Dawidek */ 118*1e09ff3dSPawel Jakub Dawidek keysearch.gek_keyno = keyno; 119*1e09ff3dSPawel Jakub Dawidek ekey = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 120*1e09ff3dSPawel Jakub Dawidek if (ekey != NULL) { 121*1e09ff3dSPawel Jakub Dawidek bzero(key, sizeof(*key)); 122*1e09ff3dSPawel Jakub Dawidek key = ekey; 123*1e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 124*1e09ff3dSPawel Jakub Dawidek } else { 125*1e09ff3dSPawel Jakub Dawidek RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key); 126*1e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated++; 127*1e09ff3dSPawel Jakub Dawidek } 128*1e09ff3dSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 129*1e09ff3dSPawel Jakub Dawidek 130*1e09ff3dSPawel Jakub Dawidek return (key); 131*1e09ff3dSPawel Jakub Dawidek } 132*1e09ff3dSPawel Jakub Dawidek 133*1e09ff3dSPawel Jakub Dawidek static struct g_eli_key * 134*1e09ff3dSPawel Jakub Dawidek g_eli_key_find_last(struct g_eli_softc *sc) 135*1e09ff3dSPawel Jakub Dawidek { 136*1e09ff3dSPawel Jakub Dawidek struct g_eli_key *key; 137*1e09ff3dSPawel Jakub Dawidek 138*1e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 139*1e09ff3dSPawel Jakub Dawidek 140*1e09ff3dSPawel Jakub Dawidek TAILQ_FOREACH(key, &sc->sc_ekeys_queue, gek_next) { 141*1e09ff3dSPawel Jakub Dawidek if (key->gek_count == 0) 142*1e09ff3dSPawel Jakub Dawidek break; 143*1e09ff3dSPawel Jakub Dawidek } 144*1e09ff3dSPawel Jakub Dawidek 145*1e09ff3dSPawel Jakub Dawidek return (key); 146*1e09ff3dSPawel Jakub Dawidek } 147*1e09ff3dSPawel Jakub Dawidek 148*1e09ff3dSPawel Jakub Dawidek static void 149*1e09ff3dSPawel Jakub Dawidek g_eli_key_replace(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno) 150*1e09ff3dSPawel Jakub Dawidek { 151*1e09ff3dSPawel Jakub Dawidek 152*1e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 153*1e09ff3dSPawel Jakub Dawidek 154*1e09ff3dSPawel Jakub Dawidek RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key); 155*1e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 156*1e09ff3dSPawel Jakub Dawidek 157*1e09ff3dSPawel Jakub Dawidek KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count)); 158*1e09ff3dSPawel Jakub Dawidek 159*1e09ff3dSPawel Jakub Dawidek g_eli_key_fill(sc, key, keyno); 160*1e09ff3dSPawel Jakub Dawidek 161*1e09ff3dSPawel Jakub Dawidek RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key); 162*1e09ff3dSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 163*1e09ff3dSPawel Jakub Dawidek } 164*1e09ff3dSPawel Jakub Dawidek 165*1e09ff3dSPawel Jakub Dawidek static void 166*1e09ff3dSPawel Jakub Dawidek g_eli_key_remove(struct g_eli_softc *sc, struct g_eli_key *key) 167*1e09ff3dSPawel Jakub Dawidek { 168*1e09ff3dSPawel Jakub Dawidek 169*1e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 170*1e09ff3dSPawel Jakub Dawidek 171*1e09ff3dSPawel Jakub Dawidek KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count)); 172*1e09ff3dSPawel Jakub Dawidek 173*1e09ff3dSPawel Jakub Dawidek RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key); 174*1e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 175*1e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated--; 176*1e09ff3dSPawel Jakub Dawidek bzero(key, sizeof(*key)); 177*1e09ff3dSPawel Jakub Dawidek free(key, M_ELI); 178*1e09ff3dSPawel Jakub Dawidek } 179*1e09ff3dSPawel Jakub Dawidek 180*1e09ff3dSPawel Jakub Dawidek void 181*1e09ff3dSPawel Jakub Dawidek g_eli_key_init(struct g_eli_softc *sc) 182*1e09ff3dSPawel Jakub Dawidek { 183*1e09ff3dSPawel Jakub Dawidek 184*1e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 185*1e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { 186*1e09ff3dSPawel Jakub Dawidek uint8_t *mkey; 187*1e09ff3dSPawel Jakub Dawidek 188*1e09ff3dSPawel Jakub Dawidek mkey = sc->sc_mkey + sizeof(sc->sc_ivkey); 189*1e09ff3dSPawel Jakub Dawidek 190*1e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_total = 1; 191*1e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated = 0; 192*1e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0) 193*1e09ff3dSPawel Jakub Dawidek bcopy(mkey, sc->sc_ekey, G_ELI_DATAKEYLEN); 194*1e09ff3dSPawel Jakub Dawidek else { 195*1e09ff3dSPawel Jakub Dawidek /* 196*1e09ff3dSPawel Jakub Dawidek * The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10) 197*1e09ff3dSPawel Jakub Dawidek */ 198*1e09ff3dSPawel Jakub Dawidek g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, 199*1e09ff3dSPawel Jakub Dawidek sc->sc_ekey, 0); 200*1e09ff3dSPawel Jakub Dawidek } 201*1e09ff3dSPawel Jakub Dawidek } else { 202*1e09ff3dSPawel Jakub Dawidek off_t mediasize; 203*1e09ff3dSPawel Jakub Dawidek size_t blocksize; 204*1e09ff3dSPawel Jakub Dawidek 205*1e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) { 206*1e09ff3dSPawel Jakub Dawidek struct g_provider *pp; 207*1e09ff3dSPawel Jakub Dawidek 208*1e09ff3dSPawel Jakub Dawidek pp = LIST_FIRST(&sc->sc_geom->consumer)->provider; 209*1e09ff3dSPawel Jakub Dawidek mediasize = pp->mediasize; 210*1e09ff3dSPawel Jakub Dawidek blocksize = pp->sectorsize; 211*1e09ff3dSPawel Jakub Dawidek } else { 212*1e09ff3dSPawel Jakub Dawidek mediasize = sc->sc_mediasize; 213*1e09ff3dSPawel Jakub Dawidek blocksize = sc->sc_sectorsize; 214*1e09ff3dSPawel Jakub Dawidek } 215*1e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_total = 216*1e09ff3dSPawel Jakub Dawidek ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1; 217*1e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated = 0; 218*1e09ff3dSPawel Jakub Dawidek TAILQ_INIT(&sc->sc_ekeys_queue); 219*1e09ff3dSPawel Jakub Dawidek RB_INIT(&sc->sc_ekeys_tree); 220*1e09ff3dSPawel Jakub Dawidek } 221*1e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 222*1e09ff3dSPawel Jakub Dawidek } 223*1e09ff3dSPawel Jakub Dawidek 224*1e09ff3dSPawel Jakub Dawidek void 225*1e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(struct g_eli_softc *sc) 226*1e09ff3dSPawel Jakub Dawidek { 227*1e09ff3dSPawel Jakub Dawidek 228*1e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 229*1e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { 230*1e09ff3dSPawel Jakub Dawidek bzero(sc->sc_ekey, sizeof(sc->sc_ekey)); 231*1e09ff3dSPawel Jakub Dawidek } else { 232*1e09ff3dSPawel Jakub Dawidek struct g_eli_key *key; 233*1e09ff3dSPawel Jakub Dawidek 234*1e09ff3dSPawel Jakub Dawidek while ((key = TAILQ_FIRST(&sc->sc_ekeys_queue)) != NULL) 235*1e09ff3dSPawel Jakub Dawidek g_eli_key_remove(sc, key); 236*1e09ff3dSPawel Jakub Dawidek TAILQ_INIT(&sc->sc_ekeys_queue); 237*1e09ff3dSPawel Jakub Dawidek RB_INIT(&sc->sc_ekeys_tree); 238*1e09ff3dSPawel Jakub Dawidek } 239*1e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 240*1e09ff3dSPawel Jakub Dawidek } 241*1e09ff3dSPawel Jakub Dawidek 242*1e09ff3dSPawel Jakub Dawidek /* 243*1e09ff3dSPawel Jakub Dawidek * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one 244*1e09ff3dSPawel Jakub Dawidek * key available for all the data. If the flag is not present select the key 245*1e09ff3dSPawel Jakub Dawidek * based on data offset. 246*1e09ff3dSPawel Jakub Dawidek */ 247*1e09ff3dSPawel Jakub Dawidek uint8_t * 248*1e09ff3dSPawel Jakub Dawidek g_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize) 249*1e09ff3dSPawel Jakub Dawidek { 250*1e09ff3dSPawel Jakub Dawidek struct g_eli_key *key, keysearch; 251*1e09ff3dSPawel Jakub Dawidek uint64_t keyno; 252*1e09ff3dSPawel Jakub Dawidek 253*1e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) 254*1e09ff3dSPawel Jakub Dawidek return (sc->sc_ekey); 255*1e09ff3dSPawel Jakub Dawidek 256*1e09ff3dSPawel Jakub Dawidek KASSERT(sc->sc_ekeys_total > 1, ("%s: sc_ekeys_total=%ju", __func__, 257*1e09ff3dSPawel Jakub Dawidek (uintmax_t)sc->sc_ekeys_total)); 258*1e09ff3dSPawel Jakub Dawidek KASSERT((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0, 259*1e09ff3dSPawel Jakub Dawidek ("%s: SINGLE_KEY flag set, but sc_ekeys_total=%ju", __func__, 260*1e09ff3dSPawel Jakub Dawidek (uintmax_t)sc->sc_ekeys_total)); 261*1e09ff3dSPawel Jakub Dawidek 262*1e09ff3dSPawel Jakub Dawidek /* We switch key every 2^G_ELI_KEY_SHIFT blocks. */ 263*1e09ff3dSPawel Jakub Dawidek keyno = (offset >> G_ELI_KEY_SHIFT) / blocksize; 264*1e09ff3dSPawel Jakub Dawidek 265*1e09ff3dSPawel Jakub Dawidek KASSERT(keyno < sc->sc_ekeys_total, 266*1e09ff3dSPawel Jakub Dawidek ("%s: keyno=%ju >= sc_ekeys_total=%ju", 267*1e09ff3dSPawel Jakub Dawidek __func__, (uintmax_t)keyno, (uintmax_t)sc->sc_ekeys_total)); 268*1e09ff3dSPawel Jakub Dawidek 269*1e09ff3dSPawel Jakub Dawidek keysearch.gek_keyno = keyno; 270*1e09ff3dSPawel Jakub Dawidek 271*1e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 272*1e09ff3dSPawel Jakub Dawidek key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 273*1e09ff3dSPawel Jakub Dawidek if (key != NULL) { 274*1e09ff3dSPawel Jakub Dawidek g_eli_key_cache_hits++; 275*1e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 276*1e09ff3dSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 277*1e09ff3dSPawel Jakub Dawidek } else { 278*1e09ff3dSPawel Jakub Dawidek /* 279*1e09ff3dSPawel Jakub Dawidek * No key in cache, find the least recently unreferenced key 280*1e09ff3dSPawel Jakub Dawidek * or allocate one if we haven't reached our limit yet. 281*1e09ff3dSPawel Jakub Dawidek */ 282*1e09ff3dSPawel Jakub Dawidek if (sc->sc_ekeys_allocated < g_eli_key_cache_limit) { 283*1e09ff3dSPawel Jakub Dawidek key = g_eli_key_allocate(sc, keyno); 284*1e09ff3dSPawel Jakub Dawidek } else { 285*1e09ff3dSPawel Jakub Dawidek g_eli_key_cache_misses++; 286*1e09ff3dSPawel Jakub Dawidek key = g_eli_key_find_last(sc); 287*1e09ff3dSPawel Jakub Dawidek if (key != NULL) { 288*1e09ff3dSPawel Jakub Dawidek g_eli_key_replace(sc, key, keyno); 289*1e09ff3dSPawel Jakub Dawidek } else { 290*1e09ff3dSPawel Jakub Dawidek /* All keys are referenced? Allocate one. */ 291*1e09ff3dSPawel Jakub Dawidek key = g_eli_key_allocate(sc, keyno); 292*1e09ff3dSPawel Jakub Dawidek } 293*1e09ff3dSPawel Jakub Dawidek } 294*1e09ff3dSPawel Jakub Dawidek } 295*1e09ff3dSPawel Jakub Dawidek key->gek_count++; 296*1e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 297*1e09ff3dSPawel Jakub Dawidek 298*1e09ff3dSPawel Jakub Dawidek return (key->gek_key); 299*1e09ff3dSPawel Jakub Dawidek } 300*1e09ff3dSPawel Jakub Dawidek 301*1e09ff3dSPawel Jakub Dawidek void 302*1e09ff3dSPawel Jakub Dawidek g_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey) 303*1e09ff3dSPawel Jakub Dawidek { 304*1e09ff3dSPawel Jakub Dawidek struct g_eli_key *key = (struct g_eli_key *)rawkey; 305*1e09ff3dSPawel Jakub Dawidek 306*1e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) 307*1e09ff3dSPawel Jakub Dawidek return; 308*1e09ff3dSPawel Jakub Dawidek 309*1e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 310*1e09ff3dSPawel Jakub Dawidek KASSERT(key->gek_count > 0, ("key->gek_count=%d", key->gek_count)); 311*1e09ff3dSPawel Jakub Dawidek key->gek_count--; 312*1e09ff3dSPawel Jakub Dawidek while (sc->sc_ekeys_allocated > g_eli_key_cache_limit) { 313*1e09ff3dSPawel Jakub Dawidek key = g_eli_key_find_last(sc); 314*1e09ff3dSPawel Jakub Dawidek if (key == NULL) 315*1e09ff3dSPawel Jakub Dawidek break; 316*1e09ff3dSPawel Jakub Dawidek g_eli_key_remove(sc, key); 317*1e09ff3dSPawel Jakub Dawidek } 318*1e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 319*1e09ff3dSPawel Jakub Dawidek } 320