xref: /freebsd/sys/geom/eli/g_eli_key_cache.c (revision fdafd315)
11e09ff3dSPawel Jakub Dawidek /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni  *
42f07cdf8SPawel Jakub Dawidek  * Copyright (c) 2011-2019 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/param.h>
304332fecaSAllan Jude #ifdef _KERNEL
311e09ff3dSPawel Jakub Dawidek #include <sys/kernel.h>
321e09ff3dSPawel Jakub Dawidek #include <sys/malloc.h>
331e09ff3dSPawel Jakub Dawidek #include <sys/sysctl.h>
341e09ff3dSPawel Jakub Dawidek #include <sys/systm.h>
354332fecaSAllan Jude #endif /* _KERNEL */
364332fecaSAllan Jude #include <sys/queue.h>
371e09ff3dSPawel Jakub Dawidek #include <sys/tree.h>
381e09ff3dSPawel Jakub Dawidek 
391e09ff3dSPawel Jakub Dawidek #include <geom/geom.h>
401e09ff3dSPawel Jakub Dawidek 
411e09ff3dSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
421e09ff3dSPawel Jakub Dawidek 
434332fecaSAllan Jude #ifdef _KERNEL
441e09ff3dSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
451e09ff3dSPawel Jakub Dawidek 
461e09ff3dSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom_eli);
471e09ff3dSPawel Jakub Dawidek /*
481e09ff3dSPawel Jakub Dawidek  * The default limit (8192 keys) will allow to cache all keys for 4TB
491e09ff3dSPawel Jakub Dawidek  * provider with 512 bytes sectors and will take around 1MB of memory.
501e09ff3dSPawel Jakub Dawidek  */
511e09ff3dSPawel Jakub Dawidek static u_int g_eli_key_cache_limit = 8192;
521e09ff3dSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_eli, OID_AUTO, key_cache_limit, CTLFLAG_RDTUN,
531e09ff3dSPawel Jakub Dawidek     &g_eli_key_cache_limit, 0, "Maximum number of encryption keys to cache");
541e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_hits;
551e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_hits, CTLFLAG_RW,
561e09ff3dSPawel Jakub Dawidek     &g_eli_key_cache_hits, 0, "Key cache hits");
571e09ff3dSPawel Jakub Dawidek static uint64_t g_eli_key_cache_misses;
581e09ff3dSPawel Jakub Dawidek SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_misses, CTLFLAG_RW,
591e09ff3dSPawel Jakub Dawidek     &g_eli_key_cache_misses, 0, "Key cache misses");
601e09ff3dSPawel Jakub Dawidek 
611e09ff3dSPawel Jakub Dawidek static int
g_eli_key_cmp(const struct g_eli_key * a,const struct g_eli_key * b)621e09ff3dSPawel Jakub Dawidek g_eli_key_cmp(const struct g_eli_key *a, const struct g_eli_key *b)
631e09ff3dSPawel Jakub Dawidek {
641e09ff3dSPawel Jakub Dawidek 
651e09ff3dSPawel Jakub Dawidek 	if (a->gek_keyno > b->gek_keyno)
661e09ff3dSPawel Jakub Dawidek 		return (1);
671e09ff3dSPawel Jakub Dawidek 	else if (a->gek_keyno < b->gek_keyno)
681e09ff3dSPawel Jakub Dawidek 		return (-1);
691e09ff3dSPawel Jakub Dawidek 	return (0);
701e09ff3dSPawel Jakub Dawidek }
714bae19e9SWarner Losh #endif /* _KERNEL */
721e09ff3dSPawel Jakub Dawidek 
734332fecaSAllan Jude void
g_eli_key_fill(struct g_eli_softc * sc,struct g_eli_key * key,uint64_t keyno)741e09ff3dSPawel Jakub Dawidek g_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno)
751e09ff3dSPawel Jakub Dawidek {
76457bbc4fSPawel Jakub Dawidek 	const uint8_t *ekey;
771e09ff3dSPawel Jakub Dawidek 	struct {
781e09ff3dSPawel Jakub Dawidek 		char magic[4];
791e09ff3dSPawel Jakub Dawidek 		uint8_t keyno[8];
801e09ff3dSPawel Jakub Dawidek 	} __packed hmacdata;
811e09ff3dSPawel Jakub Dawidek 
82457bbc4fSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_ENC_IVKEY) != 0)
83457bbc4fSPawel Jakub Dawidek 		ekey = sc->sc_mkey;
84457bbc4fSPawel Jakub Dawidek 	else
85457bbc4fSPawel Jakub Dawidek 		ekey = sc->sc_ekey;
86457bbc4fSPawel Jakub Dawidek 
871e09ff3dSPawel Jakub Dawidek 	bcopy("ekey", hmacdata.magic, 4);
881e09ff3dSPawel Jakub Dawidek 	le64enc(hmacdata.keyno, keyno);
89457bbc4fSPawel Jakub Dawidek 	g_eli_crypto_hmac(ekey, G_ELI_MAXKEYLEN, (uint8_t *)&hmacdata,
901e09ff3dSPawel Jakub Dawidek 	    sizeof(hmacdata), key->gek_key, 0);
911e09ff3dSPawel Jakub Dawidek 	key->gek_keyno = keyno;
921e09ff3dSPawel Jakub Dawidek 	key->gek_count = 0;
939104c920SPawel Jakub Dawidek 	key->gek_magic = G_ELI_KEY_MAGIC;
941e09ff3dSPawel Jakub Dawidek }
951e09ff3dSPawel Jakub Dawidek 
964332fecaSAllan Jude #ifdef _KERNEL
974332fecaSAllan Jude RB_PROTOTYPE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp);
984332fecaSAllan Jude RB_GENERATE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp);
994332fecaSAllan Jude 
1001e09ff3dSPawel Jakub Dawidek static struct g_eli_key *
g_eli_key_allocate(struct g_eli_softc * sc,uint64_t keyno)1011e09ff3dSPawel Jakub Dawidek g_eli_key_allocate(struct g_eli_softc *sc, uint64_t keyno)
1021e09ff3dSPawel Jakub Dawidek {
1031e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key, *ekey, keysearch;
1041e09ff3dSPawel Jakub Dawidek 
1051e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1061e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
1071e09ff3dSPawel Jakub Dawidek 
1081e09ff3dSPawel Jakub Dawidek 	key = malloc(sizeof(*key), M_ELI, M_WAITOK);
1091e09ff3dSPawel Jakub Dawidek 	g_eli_key_fill(sc, key, keyno);
1101e09ff3dSPawel Jakub Dawidek 
1111e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
1121e09ff3dSPawel Jakub Dawidek 	/*
1131e09ff3dSPawel Jakub Dawidek 	 * Recheck if the key wasn't added while we weren't holding the lock.
1141e09ff3dSPawel Jakub Dawidek 	 */
1151e09ff3dSPawel Jakub Dawidek 	keysearch.gek_keyno = keyno;
1161e09ff3dSPawel Jakub Dawidek 	ekey = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
1171e09ff3dSPawel Jakub Dawidek 	if (ekey != NULL) {
1184a711b8dSJohn Baldwin 		zfree(key, M_ELI);
1191e09ff3dSPawel Jakub Dawidek 		key = ekey;
1201e09ff3dSPawel Jakub Dawidek 		TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
1211e09ff3dSPawel Jakub Dawidek 	} else {
1221e09ff3dSPawel Jakub Dawidek 		RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1231e09ff3dSPawel Jakub Dawidek 		sc->sc_ekeys_allocated++;
1241e09ff3dSPawel Jakub Dawidek 	}
1251e09ff3dSPawel Jakub Dawidek 	TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
1261e09ff3dSPawel Jakub Dawidek 
1271e09ff3dSPawel Jakub Dawidek 	return (key);
1281e09ff3dSPawel Jakub Dawidek }
1291e09ff3dSPawel Jakub Dawidek 
1301e09ff3dSPawel Jakub Dawidek static struct g_eli_key *
g_eli_key_find_last(struct g_eli_softc * sc)1311e09ff3dSPawel Jakub Dawidek g_eli_key_find_last(struct g_eli_softc *sc)
1321e09ff3dSPawel Jakub Dawidek {
1331e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key;
1341e09ff3dSPawel Jakub Dawidek 
1351e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1361e09ff3dSPawel Jakub Dawidek 
1371e09ff3dSPawel Jakub Dawidek 	TAILQ_FOREACH(key, &sc->sc_ekeys_queue, gek_next) {
1381e09ff3dSPawel Jakub Dawidek 		if (key->gek_count == 0)
1391e09ff3dSPawel Jakub Dawidek 			break;
1401e09ff3dSPawel Jakub Dawidek 	}
1411e09ff3dSPawel Jakub Dawidek 
1421e09ff3dSPawel Jakub Dawidek 	return (key);
1431e09ff3dSPawel Jakub Dawidek }
1441e09ff3dSPawel Jakub Dawidek 
1451e09ff3dSPawel Jakub Dawidek static void
g_eli_key_replace(struct g_eli_softc * sc,struct g_eli_key * key,uint64_t keyno)1461e09ff3dSPawel Jakub Dawidek g_eli_key_replace(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno)
1471e09ff3dSPawel Jakub Dawidek {
1481e09ff3dSPawel Jakub Dawidek 
1491e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1509104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic."));
1511e09ff3dSPawel Jakub Dawidek 
1521e09ff3dSPawel Jakub Dawidek 	RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1531e09ff3dSPawel Jakub Dawidek 	TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
1541e09ff3dSPawel Jakub Dawidek 
1551e09ff3dSPawel Jakub Dawidek 	KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count));
1561e09ff3dSPawel Jakub Dawidek 
1571e09ff3dSPawel Jakub Dawidek 	g_eli_key_fill(sc, key, keyno);
1581e09ff3dSPawel Jakub Dawidek 
1591e09ff3dSPawel Jakub Dawidek 	RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1601e09ff3dSPawel Jakub Dawidek 	TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
1611e09ff3dSPawel Jakub Dawidek }
1621e09ff3dSPawel Jakub Dawidek 
1631e09ff3dSPawel Jakub Dawidek static void
g_eli_key_remove(struct g_eli_softc * sc,struct g_eli_key * key)1641e09ff3dSPawel Jakub Dawidek g_eli_key_remove(struct g_eli_softc *sc, struct g_eli_key *key)
1651e09ff3dSPawel Jakub Dawidek {
1661e09ff3dSPawel Jakub Dawidek 
1671e09ff3dSPawel Jakub Dawidek 	mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
1689104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic."));
1691e09ff3dSPawel Jakub Dawidek 	KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count));
1701e09ff3dSPawel Jakub Dawidek 
1711e09ff3dSPawel Jakub Dawidek 	RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key);
1721e09ff3dSPawel Jakub Dawidek 	TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
1731e09ff3dSPawel Jakub Dawidek 	sc->sc_ekeys_allocated--;
1744a711b8dSJohn Baldwin 	zfree(key, M_ELI);
1751e09ff3dSPawel Jakub Dawidek }
1761e09ff3dSPawel Jakub Dawidek 
1771e09ff3dSPawel Jakub Dawidek void
g_eli_key_init(struct g_eli_softc * sc)1781e09ff3dSPawel Jakub Dawidek g_eli_key_init(struct g_eli_softc *sc)
1791e09ff3dSPawel Jakub Dawidek {
1801e09ff3dSPawel Jakub Dawidek 	uint8_t *mkey;
1811e09ff3dSPawel Jakub Dawidek 
1829d180439SPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
1831e09ff3dSPawel Jakub Dawidek 
1849d180439SPawel Jakub Dawidek 	mkey = sc->sc_mkey + sizeof(sc->sc_ivkey);
1851e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0)
1861e09ff3dSPawel Jakub Dawidek 		bcopy(mkey, sc->sc_ekey, G_ELI_DATAKEYLEN);
1871e09ff3dSPawel Jakub Dawidek 	else {
1881e09ff3dSPawel Jakub Dawidek 		/*
1893d47ea33SPawel Jakub Dawidek 		 * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
1901e09ff3dSPawel Jakub Dawidek 		 */
1911e09ff3dSPawel Jakub Dawidek 		g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1,
1921e09ff3dSPawel Jakub Dawidek 		    sc->sc_ekey, 0);
1931e09ff3dSPawel Jakub Dawidek 	}
1949d180439SPawel Jakub Dawidek 
1959d180439SPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
1969d180439SPawel Jakub Dawidek 		sc->sc_ekeys_total = 1;
1979d180439SPawel Jakub Dawidek 		sc->sc_ekeys_allocated = 0;
1981e09ff3dSPawel Jakub Dawidek 	} else {
1991e09ff3dSPawel Jakub Dawidek 		off_t mediasize;
2001e09ff3dSPawel Jakub Dawidek 		size_t blocksize;
2011e09ff3dSPawel Jakub Dawidek 
2021e09ff3dSPawel Jakub Dawidek 		if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
2031e09ff3dSPawel Jakub Dawidek 			struct g_provider *pp;
2041e09ff3dSPawel Jakub Dawidek 
2051e09ff3dSPawel Jakub Dawidek 			pp = LIST_FIRST(&sc->sc_geom->consumer)->provider;
2061e09ff3dSPawel Jakub Dawidek 			mediasize = pp->mediasize;
2071e09ff3dSPawel Jakub Dawidek 			blocksize = pp->sectorsize;
2081e09ff3dSPawel Jakub Dawidek 		} else {
2091e09ff3dSPawel Jakub Dawidek 			mediasize = sc->sc_mediasize;
2101e09ff3dSPawel Jakub Dawidek 			blocksize = sc->sc_sectorsize;
2111e09ff3dSPawel Jakub Dawidek 		}
2121e09ff3dSPawel Jakub Dawidek 		sc->sc_ekeys_total =
2131e09ff3dSPawel Jakub Dawidek 		    ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1;
2141e09ff3dSPawel Jakub Dawidek 		sc->sc_ekeys_allocated = 0;
2151e09ff3dSPawel Jakub Dawidek 		TAILQ_INIT(&sc->sc_ekeys_queue);
2161e09ff3dSPawel Jakub Dawidek 		RB_INIT(&sc->sc_ekeys_tree);
2175bd8adc7SPawel Jakub Dawidek 		if (sc->sc_ekeys_total <= g_eli_key_cache_limit) {
2185bd8adc7SPawel Jakub Dawidek 			uint64_t keyno;
2195bd8adc7SPawel Jakub Dawidek 
2205bd8adc7SPawel Jakub Dawidek 			for (keyno = 0; keyno < sc->sc_ekeys_total; keyno++)
2215bd8adc7SPawel Jakub Dawidek 				(void)g_eli_key_allocate(sc, keyno);
2225bd8adc7SPawel Jakub Dawidek 			KASSERT(sc->sc_ekeys_total == sc->sc_ekeys_allocated,
2235bd8adc7SPawel Jakub Dawidek 			    ("sc_ekeys_total=%ju != sc_ekeys_allocated=%ju",
2245bd8adc7SPawel Jakub Dawidek 			    (uintmax_t)sc->sc_ekeys_total,
2255bd8adc7SPawel Jakub Dawidek 			    (uintmax_t)sc->sc_ekeys_allocated));
2265bd8adc7SPawel Jakub Dawidek 		}
2271e09ff3dSPawel Jakub Dawidek 	}
2289d180439SPawel Jakub Dawidek 
2291e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
2301e09ff3dSPawel Jakub Dawidek }
2311e09ff3dSPawel Jakub Dawidek 
2321e09ff3dSPawel Jakub Dawidek void
g_eli_key_destroy(struct g_eli_softc * sc)2331e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(struct g_eli_softc *sc)
2341e09ff3dSPawel Jakub Dawidek {
2351e09ff3dSPawel Jakub Dawidek 
2361e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
2371e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
23839b7ca45SAllan Jude 		explicit_bzero(sc->sc_ekey, sizeof(sc->sc_ekey));
2391e09ff3dSPawel Jakub Dawidek 	} else {
2401e09ff3dSPawel Jakub Dawidek 		struct g_eli_key *key;
2411e09ff3dSPawel Jakub Dawidek 
2421e09ff3dSPawel Jakub Dawidek 		while ((key = TAILQ_FIRST(&sc->sc_ekeys_queue)) != NULL)
2431e09ff3dSPawel Jakub Dawidek 			g_eli_key_remove(sc, key);
2441e09ff3dSPawel Jakub Dawidek 		TAILQ_INIT(&sc->sc_ekeys_queue);
2451e09ff3dSPawel Jakub Dawidek 		RB_INIT(&sc->sc_ekeys_tree);
2461e09ff3dSPawel Jakub Dawidek 	}
2471e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
2481e09ff3dSPawel Jakub Dawidek }
2491e09ff3dSPawel Jakub Dawidek 
2502f07cdf8SPawel Jakub Dawidek void
g_eli_key_resize(struct g_eli_softc * sc)2512f07cdf8SPawel Jakub Dawidek g_eli_key_resize(struct g_eli_softc *sc)
2522f07cdf8SPawel Jakub Dawidek {
2532f07cdf8SPawel Jakub Dawidek 	uint64_t new_ekeys_total;
2542f07cdf8SPawel Jakub Dawidek 	off_t mediasize;
2552f07cdf8SPawel Jakub Dawidek 	size_t blocksize;
2562f07cdf8SPawel Jakub Dawidek 
2572f07cdf8SPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
2582f07cdf8SPawel Jakub Dawidek 		return;
2592f07cdf8SPawel Jakub Dawidek 	}
2602f07cdf8SPawel Jakub Dawidek 
2612f07cdf8SPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
2622f07cdf8SPawel Jakub Dawidek 
2632f07cdf8SPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
2642f07cdf8SPawel Jakub Dawidek 		struct g_provider *pp;
2652f07cdf8SPawel Jakub Dawidek 
2662f07cdf8SPawel Jakub Dawidek 		pp = LIST_FIRST(&sc->sc_geom->consumer)->provider;
2672f07cdf8SPawel Jakub Dawidek 		mediasize = pp->mediasize;
2682f07cdf8SPawel Jakub Dawidek 		blocksize = pp->sectorsize;
2692f07cdf8SPawel Jakub Dawidek 	} else {
2702f07cdf8SPawel Jakub Dawidek 		mediasize = sc->sc_mediasize;
2712f07cdf8SPawel Jakub Dawidek 		blocksize = sc->sc_sectorsize;
2722f07cdf8SPawel Jakub Dawidek 	}
2732f07cdf8SPawel Jakub Dawidek 	new_ekeys_total = ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1;
2742f07cdf8SPawel Jakub Dawidek 	/* We only allow to grow. */
2752f07cdf8SPawel Jakub Dawidek 	KASSERT(new_ekeys_total >= sc->sc_ekeys_total,
2762f07cdf8SPawel Jakub Dawidek 	    ("new_ekeys_total=%ju < sc_ekeys_total=%ju",
2772f07cdf8SPawel Jakub Dawidek 	    (uintmax_t)new_ekeys_total, (uintmax_t)sc->sc_ekeys_total));
2782f07cdf8SPawel Jakub Dawidek 	if (new_ekeys_total <= g_eli_key_cache_limit) {
2792f07cdf8SPawel Jakub Dawidek 		uint64_t keyno;
2802f07cdf8SPawel Jakub Dawidek 
2812f07cdf8SPawel Jakub Dawidek 		for (keyno = sc->sc_ekeys_total; keyno < new_ekeys_total;
2822f07cdf8SPawel Jakub Dawidek 		    keyno++) {
2832f07cdf8SPawel Jakub Dawidek 			(void)g_eli_key_allocate(sc, keyno);
2842f07cdf8SPawel Jakub Dawidek 		}
2852f07cdf8SPawel Jakub Dawidek 		KASSERT(new_ekeys_total == sc->sc_ekeys_allocated,
2862f07cdf8SPawel Jakub Dawidek 		    ("new_ekeys_total=%ju != sc_ekeys_allocated=%ju",
2872f07cdf8SPawel Jakub Dawidek 		    (uintmax_t)new_ekeys_total,
2882f07cdf8SPawel Jakub Dawidek 		    (uintmax_t)sc->sc_ekeys_allocated));
2892f07cdf8SPawel Jakub Dawidek 	}
2902f07cdf8SPawel Jakub Dawidek 
2912f07cdf8SPawel Jakub Dawidek 	sc->sc_ekeys_total = new_ekeys_total;
2922f07cdf8SPawel Jakub Dawidek 
2932f07cdf8SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
2942f07cdf8SPawel Jakub Dawidek }
2952f07cdf8SPawel Jakub Dawidek 
2961e09ff3dSPawel Jakub Dawidek /*
2971e09ff3dSPawel Jakub Dawidek  * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one
2981e09ff3dSPawel Jakub Dawidek  * key available for all the data. If the flag is not present select the key
2991e09ff3dSPawel Jakub Dawidek  * based on data offset.
3001e09ff3dSPawel Jakub Dawidek  */
3011e09ff3dSPawel Jakub Dawidek uint8_t *
g_eli_key_hold(struct g_eli_softc * sc,off_t offset,size_t blocksize)3021e09ff3dSPawel Jakub Dawidek g_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize)
3031e09ff3dSPawel Jakub Dawidek {
3041e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key, keysearch;
3051e09ff3dSPawel Jakub Dawidek 	uint64_t keyno;
3061e09ff3dSPawel Jakub Dawidek 
3071e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0)
3081e09ff3dSPawel Jakub Dawidek 		return (sc->sc_ekey);
3091e09ff3dSPawel Jakub Dawidek 
3101e09ff3dSPawel Jakub Dawidek 	/* We switch key every 2^G_ELI_KEY_SHIFT blocks. */
3111e09ff3dSPawel Jakub Dawidek 	keyno = (offset >> G_ELI_KEY_SHIFT) / blocksize;
3121e09ff3dSPawel Jakub Dawidek 
3131e09ff3dSPawel Jakub Dawidek 	KASSERT(keyno < sc->sc_ekeys_total,
3141e09ff3dSPawel Jakub Dawidek 	    ("%s: keyno=%ju >= sc_ekeys_total=%ju",
3151e09ff3dSPawel Jakub Dawidek 	    __func__, (uintmax_t)keyno, (uintmax_t)sc->sc_ekeys_total));
3161e09ff3dSPawel Jakub Dawidek 
3171e09ff3dSPawel Jakub Dawidek 	keysearch.gek_keyno = keyno;
3181e09ff3dSPawel Jakub Dawidek 
3195bd8adc7SPawel Jakub Dawidek 	if (sc->sc_ekeys_total == sc->sc_ekeys_allocated) {
3205bd8adc7SPawel Jakub Dawidek 		/* We have all the keys, so avoid some overhead. */
3215bd8adc7SPawel Jakub Dawidek 		key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
3225bd8adc7SPawel Jakub Dawidek 		KASSERT(key != NULL, ("No key %ju found.", (uintmax_t)keyno));
3239104c920SPawel Jakub Dawidek 		KASSERT(key->gek_magic == G_ELI_KEY_MAGIC,
3249104c920SPawel Jakub Dawidek 		    ("Invalid key magic."));
3255bd8adc7SPawel Jakub Dawidek 		return (key->gek_key);
3265bd8adc7SPawel Jakub Dawidek 	}
3275bd8adc7SPawel Jakub Dawidek 
3281e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
3291e09ff3dSPawel Jakub Dawidek 	key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
3301e09ff3dSPawel Jakub Dawidek 	if (key != NULL) {
3311e09ff3dSPawel Jakub Dawidek 		g_eli_key_cache_hits++;
3321e09ff3dSPawel Jakub Dawidek 		TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
3331e09ff3dSPawel Jakub Dawidek 		TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
3341e09ff3dSPawel Jakub Dawidek 	} else {
3351e09ff3dSPawel Jakub Dawidek 		/*
3361e09ff3dSPawel Jakub Dawidek 		 * No key in cache, find the least recently unreferenced key
3371e09ff3dSPawel Jakub Dawidek 		 * or allocate one if we haven't reached our limit yet.
3381e09ff3dSPawel Jakub Dawidek 		 */
3391e09ff3dSPawel Jakub Dawidek 		if (sc->sc_ekeys_allocated < g_eli_key_cache_limit) {
3401e09ff3dSPawel Jakub Dawidek 			key = g_eli_key_allocate(sc, keyno);
3411e09ff3dSPawel Jakub Dawidek 		} else {
3421e09ff3dSPawel Jakub Dawidek 			g_eli_key_cache_misses++;
3431e09ff3dSPawel Jakub Dawidek 			key = g_eli_key_find_last(sc);
3441e09ff3dSPawel Jakub Dawidek 			if (key != NULL) {
3451e09ff3dSPawel Jakub Dawidek 				g_eli_key_replace(sc, key, keyno);
3461e09ff3dSPawel Jakub Dawidek 			} else {
3471e09ff3dSPawel Jakub Dawidek 				/* All keys are referenced? Allocate one. */
3481e09ff3dSPawel Jakub Dawidek 				key = g_eli_key_allocate(sc, keyno);
3491e09ff3dSPawel Jakub Dawidek 			}
3501e09ff3dSPawel Jakub Dawidek 		}
3511e09ff3dSPawel Jakub Dawidek 	}
3521e09ff3dSPawel Jakub Dawidek 	key->gek_count++;
3531e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
3541e09ff3dSPawel Jakub Dawidek 
3559104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic."));
3569104c920SPawel Jakub Dawidek 
3571e09ff3dSPawel Jakub Dawidek 	return (key->gek_key);
3581e09ff3dSPawel Jakub Dawidek }
3591e09ff3dSPawel Jakub Dawidek 
3601e09ff3dSPawel Jakub Dawidek void
g_eli_key_drop(struct g_eli_softc * sc,uint8_t * rawkey)3611e09ff3dSPawel Jakub Dawidek g_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey)
3621e09ff3dSPawel Jakub Dawidek {
3631e09ff3dSPawel Jakub Dawidek 	struct g_eli_key *key = (struct g_eli_key *)rawkey;
3641e09ff3dSPawel Jakub Dawidek 
3651e09ff3dSPawel Jakub Dawidek 	if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0)
3661e09ff3dSPawel Jakub Dawidek 		return;
3671e09ff3dSPawel Jakub Dawidek 
3689104c920SPawel Jakub Dawidek 	KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic."));
3699104c920SPawel Jakub Dawidek 
3705bd8adc7SPawel Jakub Dawidek 	if (sc->sc_ekeys_total == sc->sc_ekeys_allocated)
3715bd8adc7SPawel Jakub Dawidek 		return;
3725bd8adc7SPawel Jakub Dawidek 
3731e09ff3dSPawel Jakub Dawidek 	mtx_lock(&sc->sc_ekeys_lock);
3741e09ff3dSPawel Jakub Dawidek 	KASSERT(key->gek_count > 0, ("key->gek_count=%d", key->gek_count));
3751e09ff3dSPawel Jakub Dawidek 	key->gek_count--;
3761e09ff3dSPawel Jakub Dawidek 	while (sc->sc_ekeys_allocated > g_eli_key_cache_limit) {
3771e09ff3dSPawel Jakub Dawidek 		key = g_eli_key_find_last(sc);
3781e09ff3dSPawel Jakub Dawidek 		if (key == NULL)
3791e09ff3dSPawel Jakub Dawidek 			break;
3801e09ff3dSPawel Jakub Dawidek 		g_eli_key_remove(sc, key);
3811e09ff3dSPawel Jakub Dawidek 	}
3821e09ff3dSPawel Jakub Dawidek 	mtx_unlock(&sc->sc_ekeys_lock);
3831e09ff3dSPawel Jakub Dawidek }
3844332fecaSAllan Jude #endif /* _KERNEL */
385