xref: /freebsd/sys/geom/eli/g_eli_key_cache.c (revision 3728855a0f66545c4aa90dc0d478dc403bdfa667)
11e09ff3dSPawel Jakub Dawidek /*-
2*3728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*3728855aSPedro F. Giffuni  *
41e09ff3dSPawel Jakub Dawidek  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
51e09ff3dSPawel Jakub Dawidek  * All rights reserved.
61e09ff3dSPawel Jakub Dawidek  *
71e09ff3dSPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
81e09ff3dSPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
91e09ff3dSPawel Jakub Dawidek  * are met:
101e09ff3dSPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
111e09ff3dSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
121e09ff3dSPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
131e09ff3dSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
141e09ff3dSPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
151e09ff3dSPawel Jakub Dawidek  *
161e09ff3dSPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
171e09ff3dSPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181e09ff3dSPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191e09ff3dSPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
201e09ff3dSPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211e09ff3dSPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221e09ff3dSPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231e09ff3dSPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241e09ff3dSPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251e09ff3dSPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261e09ff3dSPawel Jakub Dawidek  * SUCH DAMAGE.
271e09ff3dSPawel Jakub Dawidek  */
281e09ff3dSPawel Jakub Dawidek 
291e09ff3dSPawel Jakub Dawidek #include <sys/cdefs.h>
301e09ff3dSPawel Jakub Dawidek __FBSDID("$FreeBSD$");
311e09ff3dSPawel Jakub Dawidek 
321e09ff3dSPawel Jakub Dawidek #include <sys/param.h>
334332fecaSAllan Jude #ifdef _KERNEL
341e09ff3dSPawel Jakub Dawidek #include <sys/kernel.h>
351e09ff3dSPawel Jakub Dawidek #include <sys/malloc.h>
361e09ff3dSPawel Jakub Dawidek #include <sys/sysctl.h>
371e09ff3dSPawel Jakub Dawidek #include <sys/systm.h>
384332fecaSAllan Jude #endif /* _KERNEL */
394332fecaSAllan Jude #include <sys/queue.h>
401e09ff3dSPawel Jakub Dawidek #include <sys/tree.h>
411e09ff3dSPawel Jakub Dawidek 
421e09ff3dSPawel Jakub Dawidek #include <geom/geom.h>
431e09ff3dSPawel Jakub Dawidek 
441e09ff3dSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
451e09ff3dSPawel Jakub Dawidek 
464332fecaSAllan Jude #ifdef _KERNEL
471e09ff3dSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
481e09ff3dSPawel Jakub Dawidek 
491e09ff3dSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom_eli);
501e09ff3dSPawel Jakub Dawidek /*
511e09ff3dSPawel Jakub Dawidek  * The default limit (8192 keys) will allow to cache all keys for 4TB
521e09ff3dSPawel Jakub Dawidek  * provider with 512 bytes sectors and will take around 1MB of memory.
531e09ff3dSPawel Jakub Dawidek  */
541e09ff3dSPawel Jakub Dawidek static u_int g_eli_key_cache_limit = 8192;
551e09ff3dSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_eli, OID_AUTO, key_cache_limit, CTLFLAG_RDTUN,
561e09ff3dSPawel Jakub Dawidek     &g_eli_key_cache_limit, 0, "Maximum number of encryption keys to cache");
571e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_hits;
581e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_hits, CTLFLAG_RW,
591e09ff3dSPawel Jakub Dawidek     &g_eli_key_cache_hits, 0, "Key cache hits");
601e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_misses;
611e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_misses, CTLFLAG_RW,
621e09ff3dSPawel Jakub Dawidek     &g_eli_key_cache_misses, 0, "Key cache misses");
631e09ff3dSPawel Jakub Dawidek 
644332fecaSAllan Jude #endif /* _KERNEL */
651e09ff3dSPawel Jakub Dawidek 
661e09ff3dSPawel Jakub Dawidek static int
671e09ff3dSPawel Jakub Dawidek g_eli_key_cmp(const struct g_eli_key *a, const struct g_eli_key *b)
681e09ff3dSPawel Jakub Dawidek {
691e09ff3dSPawel Jakub Dawidek 
701e09ff3dSPawel Jakub Dawidek 	if (a->gek_keyno > b->gek_keyno)
711e09ff3dSPawel Jakub Dawidek 		return (1);
721e09ff3dSPawel Jakub Dawidek 	else if (a->gek_keyno < b->gek_keyno)
731e09ff3dSPawel Jakub Dawidek 		return (-1);
741e09ff3dSPawel Jakub Dawidek 	return (0);
751e09ff3dSPawel Jakub Dawidek }
761e09ff3dSPawel Jakub Dawidek 
774332fecaSAllan Jude void
781e09ff3dSPawel Jakub Dawidek g_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno)
791e09ff3dSPawel Jakub Dawidek {
80457bbc4fSPawel Jakub Dawidek 	const uint8_t *ekey;
811e09ff3dSPawel Jakub Dawidek 	struct {
821e09ff3dSPawel Jakub Dawidek 		char magic[4];
831e09ff3dSPawel Jakub Dawidek 		uint8_t keyno[8];
841e09ff3dSPawel Jakub Dawidek 	} __packed hmacdata;
851e09ff3dSPawel Jakub Dawidek 
86457bbc4fSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_ENC_IVKEY) != 0)
87457bbc4fSPawel Jakub Dawidek 		ekey = sc->sc_mkey;
88457bbc4fSPawel Jakub Dawidek 	else
89457bbc4fSPawel Jakub Dawidek 		ekey = sc->sc_ekey;
90457bbc4fSPawel Jakub Dawidek 
911e09ff3dSPawel Jakub Dawidek 	bcopy("ekey", hmacdata.magic, 4);
921e09ff3dSPawel Jakub Dawidek 	le64enc(hmacdata.keyno, keyno);
93457bbc4fSPawel Jakub Dawidek 	g_eli_crypto_hmac(ekey, G_ELI_MAXKEYLEN, (uint8_t *)&hmacdata,
941e09ff3dSPawel Jakub Dawidek 	    sizeof(hmacdata), key->gek_key, 0);
951e09ff3dSPawel Jakub Dawidek 	key->gek_keyno = keyno;
961e09ff3dSPawel Jakub Dawidek 	key->gek_count = 0;
979104c920SPawel Jakub Dawidek 	key->gek_magic = G_ELI_KEY_MAGIC;
981e09ff3dSPawel Jakub Dawidek }
991e09ff3dSPawel Jakub Dawidek 
1004332fecaSAllan Jude #ifdef _KERNEL
1014332fecaSAllan Jude RB_PROTOTYPE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp);
1024332fecaSAllan Jude RB_GENERATE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp);
1034332fecaSAllan Jude 
1041e09ff3dSPawel Jakub Dawidek static struct g_eli_key *
1051e09ff3dSPawel Jakub Dawidek g_eli_key_allocate(struct g_eli_softc *sc, uint64_t keyno)
1061e09ff3dSPawel Jakub Dawidek {
1071e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key, *ekey, keysearch;
1081e09ff3dSPawel Jakub Dawidek 
1091e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1101e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
1111e09ff3dSPawel Jakub Dawidek 
1121e09ff3dSPawel Jakub Dawidek 	key = malloc(sizeof(*key), M_ELI, M_WAITOK);
1131e09ff3dSPawel Jakub Dawidek 	g_eli_key_fill(sc, key, keyno);
1141e09ff3dSPawel Jakub Dawidek 
1151e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
1161e09ff3dSPawel Jakub Dawidek 	/*
1171e09ff3dSPawel Jakub Dawidek 	 * Recheck if the key wasn't added while we weren't holding the lock.
1181e09ff3dSPawel Jakub Dawidek 	 */
1191e09ff3dSPawel Jakub Dawidek 	keysearch.gek_keyno = keyno;
1201e09ff3dSPawel Jakub Dawidek 	ekey = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
1211e09ff3dSPawel Jakub Dawidek 	if (ekey != NULL) {
12239b7ca45SAllan Jude 		explicit_bzero(key, sizeof(*key));
12376cc7f6dSMikolaj Golub 		free(key, M_ELI);
1241e09ff3dSPawel Jakub Dawidek 		key = ekey;
1251e09ff3dSPawel Jakub Dawidek 		TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
1261e09ff3dSPawel Jakub Dawidek 	} else {
1271e09ff3dSPawel Jakub Dawidek 		RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1281e09ff3dSPawel Jakub Dawidek 		sc->sc_ekeys_allocated++;
1291e09ff3dSPawel Jakub Dawidek 	}
1301e09ff3dSPawel Jakub Dawidek 	TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
1311e09ff3dSPawel Jakub Dawidek 
1321e09ff3dSPawel Jakub Dawidek 	return (key);
1331e09ff3dSPawel Jakub Dawidek }
1341e09ff3dSPawel Jakub Dawidek 
1351e09ff3dSPawel Jakub Dawidek static struct g_eli_key *
1361e09ff3dSPawel Jakub Dawidek g_eli_key_find_last(struct g_eli_softc *sc)
1371e09ff3dSPawel Jakub Dawidek {
1381e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key;
1391e09ff3dSPawel Jakub Dawidek 
1401e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1411e09ff3dSPawel Jakub Dawidek 
1421e09ff3dSPawel Jakub Dawidek 	TAILQ_FOREACH(key, &sc->sc_ekeys_queue, gek_next) {
1431e09ff3dSPawel Jakub Dawidek 		if (key->gek_count == 0)
1441e09ff3dSPawel Jakub Dawidek 			break;
1451e09ff3dSPawel Jakub Dawidek 	}
1461e09ff3dSPawel Jakub Dawidek 
1471e09ff3dSPawel Jakub Dawidek 	return (key);
1481e09ff3dSPawel Jakub Dawidek }
1491e09ff3dSPawel Jakub Dawidek 
1501e09ff3dSPawel Jakub Dawidek static void
1511e09ff3dSPawel Jakub Dawidek g_eli_key_replace(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno)
1521e09ff3dSPawel Jakub Dawidek {
1531e09ff3dSPawel Jakub Dawidek 
1541e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1559104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic."));
1561e09ff3dSPawel Jakub Dawidek 
1571e09ff3dSPawel Jakub Dawidek 	RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1581e09ff3dSPawel Jakub Dawidek 	TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
1591e09ff3dSPawel Jakub Dawidek 
1601e09ff3dSPawel Jakub Dawidek 	KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count));
1611e09ff3dSPawel Jakub Dawidek 
1621e09ff3dSPawel Jakub Dawidek 	g_eli_key_fill(sc, key, keyno);
1631e09ff3dSPawel Jakub Dawidek 
1641e09ff3dSPawel Jakub Dawidek 	RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1651e09ff3dSPawel Jakub Dawidek 	TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
1661e09ff3dSPawel Jakub Dawidek }
1671e09ff3dSPawel Jakub Dawidek 
1681e09ff3dSPawel Jakub Dawidek static void
1691e09ff3dSPawel Jakub Dawidek g_eli_key_remove(struct g_eli_softc *sc, struct g_eli_key *key)
1701e09ff3dSPawel Jakub Dawidek {
1711e09ff3dSPawel Jakub Dawidek 
1721e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1739104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic."));
1741e09ff3dSPawel Jakub Dawidek 	KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count));
1751e09ff3dSPawel Jakub Dawidek 
1761e09ff3dSPawel Jakub Dawidek 	RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1771e09ff3dSPawel Jakub Dawidek 	TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
1781e09ff3dSPawel Jakub Dawidek 	sc->sc_ekeys_allocated--;
17939b7ca45SAllan Jude 	explicit_bzero(key, sizeof(*key));
1801e09ff3dSPawel Jakub Dawidek 	free(key, M_ELI);
1811e09ff3dSPawel Jakub Dawidek }
1821e09ff3dSPawel Jakub Dawidek 
1831e09ff3dSPawel Jakub Dawidek void
1841e09ff3dSPawel Jakub Dawidek g_eli_key_init(struct g_eli_softc *sc)
1851e09ff3dSPawel Jakub Dawidek {
1861e09ff3dSPawel Jakub Dawidek 	uint8_t *mkey;
1871e09ff3dSPawel Jakub Dawidek 
1889d180439SPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
1891e09ff3dSPawel Jakub Dawidek 
1909d180439SPawel Jakub Dawidek 	mkey = sc->sc_mkey + sizeof(sc->sc_ivkey);
1911e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0)
1921e09ff3dSPawel Jakub Dawidek 		bcopy(mkey, sc->sc_ekey, G_ELI_DATAKEYLEN);
1931e09ff3dSPawel Jakub Dawidek 	else {
1941e09ff3dSPawel Jakub Dawidek 		/*
1953d47ea33SPawel Jakub Dawidek 		 * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
1961e09ff3dSPawel Jakub Dawidek 		 */
1971e09ff3dSPawel Jakub Dawidek 		g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1,
1981e09ff3dSPawel Jakub Dawidek 		    sc->sc_ekey, 0);
1991e09ff3dSPawel Jakub Dawidek 	}
2009d180439SPawel Jakub Dawidek 
2019d180439SPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
2029d180439SPawel Jakub Dawidek 		sc->sc_ekeys_total = 1;
2039d180439SPawel Jakub Dawidek 		sc->sc_ekeys_allocated = 0;
2041e09ff3dSPawel Jakub Dawidek 	} else {
2051e09ff3dSPawel Jakub Dawidek 		off_t mediasize;
2061e09ff3dSPawel Jakub Dawidek 		size_t blocksize;
2071e09ff3dSPawel Jakub Dawidek 
2081e09ff3dSPawel Jakub Dawidek 		if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
2091e09ff3dSPawel Jakub Dawidek 			struct g_provider *pp;
2101e09ff3dSPawel Jakub Dawidek 
2111e09ff3dSPawel Jakub Dawidek 			pp = LIST_FIRST(&sc->sc_geom->consumer)->provider;
2121e09ff3dSPawel Jakub Dawidek 			mediasize = pp->mediasize;
2131e09ff3dSPawel Jakub Dawidek 			blocksize = pp->sectorsize;
2141e09ff3dSPawel Jakub Dawidek 		} else {
2151e09ff3dSPawel Jakub Dawidek 			mediasize = sc->sc_mediasize;
2161e09ff3dSPawel Jakub Dawidek 			blocksize = sc->sc_sectorsize;
2171e09ff3dSPawel Jakub Dawidek 		}
2181e09ff3dSPawel Jakub Dawidek 		sc->sc_ekeys_total =
2191e09ff3dSPawel Jakub Dawidek 		    ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1;
2201e09ff3dSPawel Jakub Dawidek 		sc->sc_ekeys_allocated = 0;
2211e09ff3dSPawel Jakub Dawidek 		TAILQ_INIT(&sc->sc_ekeys_queue);
2221e09ff3dSPawel Jakub Dawidek 		RB_INIT(&sc->sc_ekeys_tree);
2235bd8adc7SPawel Jakub Dawidek 		if (sc->sc_ekeys_total <= g_eli_key_cache_limit) {
2245bd8adc7SPawel Jakub Dawidek 			uint64_t keyno;
2255bd8adc7SPawel Jakub Dawidek 
2265bd8adc7SPawel Jakub Dawidek 			for (keyno = 0; keyno < sc->sc_ekeys_total; keyno++)
2275bd8adc7SPawel Jakub Dawidek 				(void)g_eli_key_allocate(sc, keyno);
2285bd8adc7SPawel Jakub Dawidek 			KASSERT(sc->sc_ekeys_total == sc->sc_ekeys_allocated,
2295bd8adc7SPawel Jakub Dawidek 			    ("sc_ekeys_total=%ju != sc_ekeys_allocated=%ju",
2305bd8adc7SPawel Jakub Dawidek 			    (uintmax_t)sc->sc_ekeys_total,
2315bd8adc7SPawel Jakub Dawidek 			    (uintmax_t)sc->sc_ekeys_allocated));
2325bd8adc7SPawel Jakub Dawidek 		}
2331e09ff3dSPawel Jakub Dawidek 	}
2349d180439SPawel Jakub Dawidek 
2351e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
2361e09ff3dSPawel Jakub Dawidek }
2371e09ff3dSPawel Jakub Dawidek 
2381e09ff3dSPawel Jakub Dawidek void
2391e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(struct g_eli_softc *sc)
2401e09ff3dSPawel Jakub Dawidek {
2411e09ff3dSPawel Jakub Dawidek 
2421e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
2431e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
24439b7ca45SAllan Jude 		explicit_bzero(sc->sc_ekey, sizeof(sc->sc_ekey));
2451e09ff3dSPawel Jakub Dawidek 	} else {
2461e09ff3dSPawel Jakub Dawidek 		struct g_eli_key *key;
2471e09ff3dSPawel Jakub Dawidek 
2481e09ff3dSPawel Jakub Dawidek 		while ((key = TAILQ_FIRST(&sc->sc_ekeys_queue)) != NULL)
2491e09ff3dSPawel Jakub Dawidek 			g_eli_key_remove(sc, key);
2501e09ff3dSPawel Jakub Dawidek 		TAILQ_INIT(&sc->sc_ekeys_queue);
2511e09ff3dSPawel Jakub Dawidek 		RB_INIT(&sc->sc_ekeys_tree);
2521e09ff3dSPawel Jakub Dawidek 	}
2531e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
2541e09ff3dSPawel Jakub Dawidek }
2551e09ff3dSPawel Jakub Dawidek 
2561e09ff3dSPawel Jakub Dawidek /*
2571e09ff3dSPawel Jakub Dawidek  * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one
2581e09ff3dSPawel Jakub Dawidek  * key available for all the data. If the flag is not present select the key
2591e09ff3dSPawel Jakub Dawidek  * based on data offset.
2601e09ff3dSPawel Jakub Dawidek  */
2611e09ff3dSPawel Jakub Dawidek uint8_t *
2621e09ff3dSPawel Jakub Dawidek g_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize)
2631e09ff3dSPawel Jakub Dawidek {
2641e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key, keysearch;
2651e09ff3dSPawel Jakub Dawidek 	uint64_t keyno;
2661e09ff3dSPawel Jakub Dawidek 
2671e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0)
2681e09ff3dSPawel Jakub Dawidek 		return (sc->sc_ekey);
2691e09ff3dSPawel Jakub Dawidek 
2701e09ff3dSPawel Jakub Dawidek 	/* We switch key every 2^G_ELI_KEY_SHIFT blocks. */
2711e09ff3dSPawel Jakub Dawidek 	keyno = (offset >> G_ELI_KEY_SHIFT) / blocksize;
2721e09ff3dSPawel Jakub Dawidek 
2731e09ff3dSPawel Jakub Dawidek 	KASSERT(keyno < sc->sc_ekeys_total,
2741e09ff3dSPawel Jakub Dawidek 	    ("%s: keyno=%ju >= sc_ekeys_total=%ju",
2751e09ff3dSPawel Jakub Dawidek 	    __func__, (uintmax_t)keyno, (uintmax_t)sc->sc_ekeys_total));
2761e09ff3dSPawel Jakub Dawidek 
2771e09ff3dSPawel Jakub Dawidek 	keysearch.gek_keyno = keyno;
2781e09ff3dSPawel Jakub Dawidek 
2795bd8adc7SPawel Jakub Dawidek 	if (sc->sc_ekeys_total == sc->sc_ekeys_allocated) {
2805bd8adc7SPawel Jakub Dawidek 		/* We have all the keys, so avoid some overhead. */
2815bd8adc7SPawel Jakub Dawidek 		key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
2825bd8adc7SPawel Jakub Dawidek 		KASSERT(key != NULL, ("No key %ju found.", (uintmax_t)keyno));
2839104c920SPawel Jakub Dawidek 		KASSERT(key->gek_magic == G_ELI_KEY_MAGIC,
2849104c920SPawel Jakub Dawidek 		    ("Invalid key magic."));
2855bd8adc7SPawel Jakub Dawidek 		return (key->gek_key);
2865bd8adc7SPawel Jakub Dawidek 	}
2875bd8adc7SPawel Jakub Dawidek 
2881e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
2891e09ff3dSPawel Jakub Dawidek 	key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
2901e09ff3dSPawel Jakub Dawidek 	if (key != NULL) {
2911e09ff3dSPawel Jakub Dawidek 		g_eli_key_cache_hits++;
2921e09ff3dSPawel Jakub Dawidek 		TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
2931e09ff3dSPawel Jakub Dawidek 		TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
2941e09ff3dSPawel Jakub Dawidek 	} else {
2951e09ff3dSPawel Jakub Dawidek 		/*
2961e09ff3dSPawel Jakub Dawidek 		 * No key in cache, find the least recently unreferenced key
2971e09ff3dSPawel Jakub Dawidek 		 * or allocate one if we haven't reached our limit yet.
2981e09ff3dSPawel Jakub Dawidek 		 */
2991e09ff3dSPawel Jakub Dawidek 		if (sc->sc_ekeys_allocated < g_eli_key_cache_limit) {
3001e09ff3dSPawel Jakub Dawidek 			key = g_eli_key_allocate(sc, keyno);
3011e09ff3dSPawel Jakub Dawidek 		} else {
3021e09ff3dSPawel Jakub Dawidek 			g_eli_key_cache_misses++;
3031e09ff3dSPawel Jakub Dawidek 			key = g_eli_key_find_last(sc);
3041e09ff3dSPawel Jakub Dawidek 			if (key != NULL) {
3051e09ff3dSPawel Jakub Dawidek 				g_eli_key_replace(sc, key, keyno);
3061e09ff3dSPawel Jakub Dawidek 			} else {
3071e09ff3dSPawel Jakub Dawidek 				/* All keys are referenced? Allocate one. */
3081e09ff3dSPawel Jakub Dawidek 				key = g_eli_key_allocate(sc, keyno);
3091e09ff3dSPawel Jakub Dawidek 			}
3101e09ff3dSPawel Jakub Dawidek 		}
3111e09ff3dSPawel Jakub Dawidek 	}
3121e09ff3dSPawel Jakub Dawidek 	key->gek_count++;
3131e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
3141e09ff3dSPawel Jakub Dawidek 
3159104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic."));
3169104c920SPawel Jakub Dawidek 
3171e09ff3dSPawel Jakub Dawidek 	return (key->gek_key);
3181e09ff3dSPawel Jakub Dawidek }
3191e09ff3dSPawel Jakub Dawidek 
3201e09ff3dSPawel Jakub Dawidek void
3211e09ff3dSPawel Jakub Dawidek g_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey)
3221e09ff3dSPawel Jakub Dawidek {
3231e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key = (struct g_eli_key *)rawkey;
3241e09ff3dSPawel Jakub Dawidek 
3251e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0)
3261e09ff3dSPawel Jakub Dawidek 		return;
3271e09ff3dSPawel Jakub Dawidek 
3289104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic."));
3299104c920SPawel Jakub Dawidek 
3305bd8adc7SPawel Jakub Dawidek 	if (sc->sc_ekeys_total == sc->sc_ekeys_allocated)
3315bd8adc7SPawel Jakub Dawidek 		return;
3325bd8adc7SPawel Jakub Dawidek 
3331e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
3341e09ff3dSPawel Jakub Dawidek 	KASSERT(key->gek_count > 0, ("key->gek_count=%d", key->gek_count));
3351e09ff3dSPawel Jakub Dawidek 	key->gek_count--;
3361e09ff3dSPawel Jakub Dawidek 	while (sc->sc_ekeys_allocated > g_eli_key_cache_limit) {
3371e09ff3dSPawel Jakub Dawidek 		key = g_eli_key_find_last(sc);
3381e09ff3dSPawel Jakub Dawidek 		if (key == NULL)
3391e09ff3dSPawel Jakub Dawidek 			break;
3401e09ff3dSPawel Jakub Dawidek 		g_eli_key_remove(sc, key);
3411e09ff3dSPawel Jakub Dawidek 	}
3421e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
3431e09ff3dSPawel Jakub Dawidek }
3444332fecaSAllan Jude #endif /* _KERNEL */
345