11e09ff3dSPawel Jakub Dawidek /*- 21e09ff3dSPawel Jakub Dawidek * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 31e09ff3dSPawel Jakub Dawidek * All rights reserved. 41e09ff3dSPawel Jakub Dawidek * 51e09ff3dSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 61e09ff3dSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 71e09ff3dSPawel Jakub Dawidek * are met: 81e09ff3dSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 91e09ff3dSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 101e09ff3dSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 111e09ff3dSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 121e09ff3dSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 131e09ff3dSPawel Jakub Dawidek * 141e09ff3dSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 151e09ff3dSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161e09ff3dSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171e09ff3dSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 181e09ff3dSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191e09ff3dSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201e09ff3dSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211e09ff3dSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221e09ff3dSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231e09ff3dSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241e09ff3dSPawel Jakub Dawidek * SUCH DAMAGE. 251e09ff3dSPawel Jakub Dawidek */ 261e09ff3dSPawel Jakub Dawidek 271e09ff3dSPawel Jakub Dawidek #include <sys/cdefs.h> 281e09ff3dSPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 291e09ff3dSPawel Jakub Dawidek 301e09ff3dSPawel Jakub Dawidek #include <sys/param.h> 311e09ff3dSPawel Jakub Dawidek #include <sys/kernel.h> 321e09ff3dSPawel Jakub Dawidek #include <sys/malloc.h> 331e09ff3dSPawel Jakub Dawidek #include <sys/queue.h> 341e09ff3dSPawel Jakub Dawidek #include <sys/sysctl.h> 351e09ff3dSPawel Jakub Dawidek #include <sys/systm.h> 361e09ff3dSPawel Jakub Dawidek #include <sys/tree.h> 371e09ff3dSPawel Jakub Dawidek 381e09ff3dSPawel Jakub Dawidek #include <geom/geom.h> 391e09ff3dSPawel Jakub Dawidek 401e09ff3dSPawel Jakub Dawidek #include <geom/eli/g_eli.h> 411e09ff3dSPawel Jakub Dawidek 421e09ff3dSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI); 431e09ff3dSPawel Jakub Dawidek 441e09ff3dSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom_eli); 451e09ff3dSPawel Jakub Dawidek /* 461e09ff3dSPawel Jakub Dawidek * The default limit (8192 keys) will allow to cache all keys for 4TB 471e09ff3dSPawel Jakub Dawidek * provider with 512 bytes sectors and will take around 1MB of memory. 481e09ff3dSPawel Jakub Dawidek */ 491e09ff3dSPawel Jakub Dawidek static u_int g_eli_key_cache_limit = 8192; 501e09ff3dSPawel Jakub Dawidek TUNABLE_INT("kern.geom.eli.key_cache_limit", &g_eli_key_cache_limit); 511e09ff3dSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_eli, OID_AUTO, key_cache_limit, CTLFLAG_RDTUN, 521e09ff3dSPawel Jakub Dawidek &g_eli_key_cache_limit, 0, "Maximum number of encryption keys to cache"); 531e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_hits; 541e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_hits, CTLFLAG_RW, 551e09ff3dSPawel Jakub Dawidek &g_eli_key_cache_hits, 0, "Key cache hits"); 561e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_misses; 571e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_misses, CTLFLAG_RW, 581e09ff3dSPawel Jakub Dawidek &g_eli_key_cache_misses, 0, "Key cache misses"); 591e09ff3dSPawel Jakub Dawidek 601e09ff3dSPawel Jakub Dawidek struct g_eli_key { 611e09ff3dSPawel Jakub Dawidek /* Key value, must be first in the structure. */ 621e09ff3dSPawel Jakub Dawidek uint8_t gek_key[G_ELI_DATAKEYLEN]; 631e09ff3dSPawel Jakub Dawidek /* Key number. */ 641e09ff3dSPawel Jakub Dawidek uint64_t gek_keyno; 651e09ff3dSPawel Jakub Dawidek /* Reference counter. */ 661e09ff3dSPawel Jakub Dawidek int gek_count; 671e09ff3dSPawel Jakub Dawidek /* Keeps keys sorted by most recent use. */ 681e09ff3dSPawel Jakub Dawidek TAILQ_ENTRY(g_eli_key) gek_next; 691e09ff3dSPawel Jakub Dawidek /* Keeps keys sorted by number. */ 701e09ff3dSPawel Jakub Dawidek RB_ENTRY(g_eli_key) gek_link; 711e09ff3dSPawel Jakub Dawidek }; 721e09ff3dSPawel Jakub Dawidek 731e09ff3dSPawel Jakub Dawidek static int 741e09ff3dSPawel Jakub Dawidek g_eli_key_cmp(const struct g_eli_key *a, const struct g_eli_key *b) 751e09ff3dSPawel Jakub Dawidek { 761e09ff3dSPawel Jakub Dawidek 771e09ff3dSPawel Jakub Dawidek if (a->gek_keyno > b->gek_keyno) 781e09ff3dSPawel Jakub Dawidek return (1); 791e09ff3dSPawel Jakub Dawidek else if (a->gek_keyno < b->gek_keyno) 801e09ff3dSPawel Jakub Dawidek return (-1); 811e09ff3dSPawel Jakub Dawidek return (0); 821e09ff3dSPawel Jakub Dawidek } 831e09ff3dSPawel Jakub Dawidek 841e09ff3dSPawel Jakub Dawidek RB_PROTOTYPE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp); 851e09ff3dSPawel Jakub Dawidek RB_GENERATE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp); 861e09ff3dSPawel Jakub Dawidek 871e09ff3dSPawel Jakub Dawidek static void 881e09ff3dSPawel Jakub Dawidek g_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno) 891e09ff3dSPawel Jakub Dawidek { 901e09ff3dSPawel Jakub Dawidek struct { 911e09ff3dSPawel Jakub Dawidek char magic[4]; 921e09ff3dSPawel Jakub Dawidek uint8_t keyno[8]; 931e09ff3dSPawel Jakub Dawidek } __packed hmacdata; 941e09ff3dSPawel Jakub Dawidek 951e09ff3dSPawel Jakub Dawidek bcopy("ekey", hmacdata.magic, 4); 961e09ff3dSPawel Jakub Dawidek le64enc(hmacdata.keyno, keyno); 971e09ff3dSPawel Jakub Dawidek g_eli_crypto_hmac(sc->sc_mkey, G_ELI_MAXKEYLEN, (uint8_t *)&hmacdata, 981e09ff3dSPawel Jakub Dawidek sizeof(hmacdata), key->gek_key, 0); 991e09ff3dSPawel Jakub Dawidek key->gek_keyno = keyno; 1001e09ff3dSPawel Jakub Dawidek key->gek_count = 0; 1011e09ff3dSPawel Jakub Dawidek } 1021e09ff3dSPawel Jakub Dawidek 1031e09ff3dSPawel Jakub Dawidek static struct g_eli_key * 1041e09ff3dSPawel Jakub Dawidek g_eli_key_allocate(struct g_eli_softc *sc, uint64_t keyno) 1051e09ff3dSPawel Jakub Dawidek { 1061e09ff3dSPawel Jakub Dawidek struct g_eli_key *key, *ekey, keysearch; 1071e09ff3dSPawel Jakub Dawidek 1081e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 1091e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 1101e09ff3dSPawel Jakub Dawidek 1111e09ff3dSPawel Jakub Dawidek key = malloc(sizeof(*key), M_ELI, M_WAITOK); 1121e09ff3dSPawel Jakub Dawidek g_eli_key_fill(sc, key, keyno); 1131e09ff3dSPawel Jakub Dawidek 1141e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 1151e09ff3dSPawel Jakub Dawidek /* 1161e09ff3dSPawel Jakub Dawidek * Recheck if the key wasn't added while we weren't holding the lock. 1171e09ff3dSPawel Jakub Dawidek */ 1181e09ff3dSPawel Jakub Dawidek keysearch.gek_keyno = keyno; 1191e09ff3dSPawel Jakub Dawidek ekey = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 1201e09ff3dSPawel Jakub Dawidek if (ekey != NULL) { 1211e09ff3dSPawel Jakub Dawidek bzero(key, sizeof(*key)); 1221e09ff3dSPawel Jakub Dawidek key = ekey; 1231e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 1241e09ff3dSPawel Jakub Dawidek } else { 1251e09ff3dSPawel Jakub Dawidek RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key); 1261e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated++; 1271e09ff3dSPawel Jakub Dawidek } 1281e09ff3dSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 1291e09ff3dSPawel Jakub Dawidek 1301e09ff3dSPawel Jakub Dawidek return (key); 1311e09ff3dSPawel Jakub Dawidek } 1321e09ff3dSPawel Jakub Dawidek 1331e09ff3dSPawel Jakub Dawidek static struct g_eli_key * 1341e09ff3dSPawel Jakub Dawidek g_eli_key_find_last(struct g_eli_softc *sc) 1351e09ff3dSPawel Jakub Dawidek { 1361e09ff3dSPawel Jakub Dawidek struct g_eli_key *key; 1371e09ff3dSPawel Jakub Dawidek 1381e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 1391e09ff3dSPawel Jakub Dawidek 1401e09ff3dSPawel Jakub Dawidek TAILQ_FOREACH(key, &sc->sc_ekeys_queue, gek_next) { 1411e09ff3dSPawel Jakub Dawidek if (key->gek_count == 0) 1421e09ff3dSPawel Jakub Dawidek break; 1431e09ff3dSPawel Jakub Dawidek } 1441e09ff3dSPawel Jakub Dawidek 1451e09ff3dSPawel Jakub Dawidek return (key); 1461e09ff3dSPawel Jakub Dawidek } 1471e09ff3dSPawel Jakub Dawidek 1481e09ff3dSPawel Jakub Dawidek static void 1491e09ff3dSPawel Jakub Dawidek g_eli_key_replace(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno) 1501e09ff3dSPawel Jakub Dawidek { 1511e09ff3dSPawel Jakub Dawidek 1521e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 1531e09ff3dSPawel Jakub Dawidek 1541e09ff3dSPawel Jakub Dawidek RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key); 1551e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 1561e09ff3dSPawel Jakub Dawidek 1571e09ff3dSPawel Jakub Dawidek KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count)); 1581e09ff3dSPawel Jakub Dawidek 1591e09ff3dSPawel Jakub Dawidek g_eli_key_fill(sc, key, keyno); 1601e09ff3dSPawel Jakub Dawidek 1611e09ff3dSPawel Jakub Dawidek RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key); 1621e09ff3dSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 1631e09ff3dSPawel Jakub Dawidek } 1641e09ff3dSPawel Jakub Dawidek 1651e09ff3dSPawel Jakub Dawidek static void 1661e09ff3dSPawel Jakub Dawidek g_eli_key_remove(struct g_eli_softc *sc, struct g_eli_key *key) 1671e09ff3dSPawel Jakub Dawidek { 1681e09ff3dSPawel Jakub Dawidek 1691e09ff3dSPawel Jakub Dawidek mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 1701e09ff3dSPawel Jakub Dawidek 1711e09ff3dSPawel Jakub Dawidek KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count)); 1721e09ff3dSPawel Jakub Dawidek 1731e09ff3dSPawel Jakub Dawidek RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key); 1741e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 1751e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated--; 1761e09ff3dSPawel Jakub Dawidek bzero(key, sizeof(*key)); 1771e09ff3dSPawel Jakub Dawidek free(key, M_ELI); 1781e09ff3dSPawel Jakub Dawidek } 1791e09ff3dSPawel Jakub Dawidek 1801e09ff3dSPawel Jakub Dawidek void 1811e09ff3dSPawel Jakub Dawidek g_eli_key_init(struct g_eli_softc *sc) 1821e09ff3dSPawel Jakub Dawidek { 1831e09ff3dSPawel Jakub Dawidek 1841e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 1851e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { 1861e09ff3dSPawel Jakub Dawidek uint8_t *mkey; 1871e09ff3dSPawel Jakub Dawidek 1881e09ff3dSPawel Jakub Dawidek mkey = sc->sc_mkey + sizeof(sc->sc_ivkey); 1891e09ff3dSPawel Jakub Dawidek 1901e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_total = 1; 1911e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated = 0; 1921e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0) 1931e09ff3dSPawel Jakub Dawidek bcopy(mkey, sc->sc_ekey, G_ELI_DATAKEYLEN); 1941e09ff3dSPawel Jakub Dawidek else { 1951e09ff3dSPawel Jakub Dawidek /* 1961e09ff3dSPawel Jakub Dawidek * The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10) 1971e09ff3dSPawel Jakub Dawidek */ 1981e09ff3dSPawel Jakub Dawidek g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, 1991e09ff3dSPawel Jakub Dawidek sc->sc_ekey, 0); 2001e09ff3dSPawel Jakub Dawidek } 2011e09ff3dSPawel Jakub Dawidek } else { 2021e09ff3dSPawel Jakub Dawidek off_t mediasize; 2031e09ff3dSPawel Jakub Dawidek size_t blocksize; 2041e09ff3dSPawel Jakub Dawidek 2051e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) { 2061e09ff3dSPawel Jakub Dawidek struct g_provider *pp; 2071e09ff3dSPawel Jakub Dawidek 2081e09ff3dSPawel Jakub Dawidek pp = LIST_FIRST(&sc->sc_geom->consumer)->provider; 2091e09ff3dSPawel Jakub Dawidek mediasize = pp->mediasize; 2101e09ff3dSPawel Jakub Dawidek blocksize = pp->sectorsize; 2111e09ff3dSPawel Jakub Dawidek } else { 2121e09ff3dSPawel Jakub Dawidek mediasize = sc->sc_mediasize; 2131e09ff3dSPawel Jakub Dawidek blocksize = sc->sc_sectorsize; 2141e09ff3dSPawel Jakub Dawidek } 2151e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_total = 2161e09ff3dSPawel Jakub Dawidek ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1; 2171e09ff3dSPawel Jakub Dawidek sc->sc_ekeys_allocated = 0; 2181e09ff3dSPawel Jakub Dawidek TAILQ_INIT(&sc->sc_ekeys_queue); 2191e09ff3dSPawel Jakub Dawidek RB_INIT(&sc->sc_ekeys_tree); 2201e09ff3dSPawel Jakub Dawidek } 2211e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 2221e09ff3dSPawel Jakub Dawidek } 2231e09ff3dSPawel Jakub Dawidek 2241e09ff3dSPawel Jakub Dawidek void 2251e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(struct g_eli_softc *sc) 2261e09ff3dSPawel Jakub Dawidek { 2271e09ff3dSPawel Jakub Dawidek 2281e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 2291e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { 2301e09ff3dSPawel Jakub Dawidek bzero(sc->sc_ekey, sizeof(sc->sc_ekey)); 2311e09ff3dSPawel Jakub Dawidek } else { 2321e09ff3dSPawel Jakub Dawidek struct g_eli_key *key; 2331e09ff3dSPawel Jakub Dawidek 2341e09ff3dSPawel Jakub Dawidek while ((key = TAILQ_FIRST(&sc->sc_ekeys_queue)) != NULL) 2351e09ff3dSPawel Jakub Dawidek g_eli_key_remove(sc, key); 2361e09ff3dSPawel Jakub Dawidek TAILQ_INIT(&sc->sc_ekeys_queue); 2371e09ff3dSPawel Jakub Dawidek RB_INIT(&sc->sc_ekeys_tree); 2381e09ff3dSPawel Jakub Dawidek } 2391e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 2401e09ff3dSPawel Jakub Dawidek } 2411e09ff3dSPawel Jakub Dawidek 2421e09ff3dSPawel Jakub Dawidek /* 2431e09ff3dSPawel Jakub Dawidek * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one 2441e09ff3dSPawel Jakub Dawidek * key available for all the data. If the flag is not present select the key 2451e09ff3dSPawel Jakub Dawidek * based on data offset. 2461e09ff3dSPawel Jakub Dawidek */ 2471e09ff3dSPawel Jakub Dawidek uint8_t * 2481e09ff3dSPawel Jakub Dawidek g_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize) 2491e09ff3dSPawel Jakub Dawidek { 2501e09ff3dSPawel Jakub Dawidek struct g_eli_key *key, keysearch; 2511e09ff3dSPawel Jakub Dawidek uint64_t keyno; 2521e09ff3dSPawel Jakub Dawidek 2531e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) 2541e09ff3dSPawel Jakub Dawidek return (sc->sc_ekey); 2551e09ff3dSPawel Jakub Dawidek 2561e09ff3dSPawel Jakub Dawidek KASSERT(sc->sc_ekeys_total > 1, ("%s: sc_ekeys_total=%ju", __func__, 2571e09ff3dSPawel Jakub Dawidek (uintmax_t)sc->sc_ekeys_total)); 2581e09ff3dSPawel Jakub Dawidek KASSERT((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0, 2591e09ff3dSPawel Jakub Dawidek ("%s: SINGLE_KEY flag set, but sc_ekeys_total=%ju", __func__, 2601e09ff3dSPawel Jakub Dawidek (uintmax_t)sc->sc_ekeys_total)); 2611e09ff3dSPawel Jakub Dawidek 2621e09ff3dSPawel Jakub Dawidek /* We switch key every 2^G_ELI_KEY_SHIFT blocks. */ 2631e09ff3dSPawel Jakub Dawidek keyno = (offset >> G_ELI_KEY_SHIFT) / blocksize; 2641e09ff3dSPawel Jakub Dawidek 2651e09ff3dSPawel Jakub Dawidek KASSERT(keyno < sc->sc_ekeys_total, 2661e09ff3dSPawel Jakub Dawidek ("%s: keyno=%ju >= sc_ekeys_total=%ju", 2671e09ff3dSPawel Jakub Dawidek __func__, (uintmax_t)keyno, (uintmax_t)sc->sc_ekeys_total)); 2681e09ff3dSPawel Jakub Dawidek 2691e09ff3dSPawel Jakub Dawidek keysearch.gek_keyno = keyno; 2701e09ff3dSPawel Jakub Dawidek 2711e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 2721e09ff3dSPawel Jakub Dawidek key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 2731e09ff3dSPawel Jakub Dawidek if (key != NULL) { 2741e09ff3dSPawel Jakub Dawidek g_eli_key_cache_hits++; 2751e09ff3dSPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 2761e09ff3dSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 2771e09ff3dSPawel Jakub Dawidek } else { 2781e09ff3dSPawel Jakub Dawidek /* 2791e09ff3dSPawel Jakub Dawidek * No key in cache, find the least recently unreferenced key 2801e09ff3dSPawel Jakub Dawidek * or allocate one if we haven't reached our limit yet. 2811e09ff3dSPawel Jakub Dawidek */ 2821e09ff3dSPawel Jakub Dawidek if (sc->sc_ekeys_allocated < g_eli_key_cache_limit) { 2831e09ff3dSPawel Jakub Dawidek key = g_eli_key_allocate(sc, keyno); 2841e09ff3dSPawel Jakub Dawidek } else { 2851e09ff3dSPawel Jakub Dawidek g_eli_key_cache_misses++; 2861e09ff3dSPawel Jakub Dawidek key = g_eli_key_find_last(sc); 2871e09ff3dSPawel Jakub Dawidek if (key != NULL) { 2881e09ff3dSPawel Jakub Dawidek g_eli_key_replace(sc, key, keyno); 2891e09ff3dSPawel Jakub Dawidek } else { 2901e09ff3dSPawel Jakub Dawidek /* All keys are referenced? Allocate one. */ 2911e09ff3dSPawel Jakub Dawidek key = g_eli_key_allocate(sc, keyno); 2921e09ff3dSPawel Jakub Dawidek } 2931e09ff3dSPawel Jakub Dawidek } 2941e09ff3dSPawel Jakub Dawidek } 2951e09ff3dSPawel Jakub Dawidek key->gek_count++; 2961e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 2971e09ff3dSPawel Jakub Dawidek 2981e09ff3dSPawel Jakub Dawidek return (key->gek_key); 2991e09ff3dSPawel Jakub Dawidek } 3001e09ff3dSPawel Jakub Dawidek 3011e09ff3dSPawel Jakub Dawidek void 3021e09ff3dSPawel Jakub Dawidek g_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey) 3031e09ff3dSPawel Jakub Dawidek { 3041e09ff3dSPawel Jakub Dawidek struct g_eli_key *key = (struct g_eli_key *)rawkey; 3051e09ff3dSPawel Jakub Dawidek 3061e09ff3dSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) 3071e09ff3dSPawel Jakub Dawidek return; 3081e09ff3dSPawel Jakub Dawidek 3091e09ff3dSPawel Jakub Dawidek mtx_lock(&sc->sc_ekeys_lock); 3101e09ff3dSPawel Jakub Dawidek KASSERT(key->gek_count > 0, ("key->gek_count=%d", key->gek_count)); 3111e09ff3dSPawel Jakub Dawidek key->gek_count--; 3121e09ff3dSPawel Jakub Dawidek while (sc->sc_ekeys_allocated > g_eli_key_cache_limit) { 3131e09ff3dSPawel Jakub Dawidek key = g_eli_key_find_last(sc); 3141e09ff3dSPawel Jakub Dawidek if (key == NULL) 3151e09ff3dSPawel Jakub Dawidek break; 3161e09ff3dSPawel Jakub Dawidek g_eli_key_remove(sc, key); 3171e09ff3dSPawel Jakub Dawidek } 3181e09ff3dSPawel Jakub Dawidek mtx_unlock(&sc->sc_ekeys_lock); 3191e09ff3dSPawel Jakub Dawidek } 320