11e09ff3dSPawel Jakub Dawidek /*-
2*4d846d26SWarner 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