1c58794deSPawel Jakub Dawidek /*- 23728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 33728855aSPedro F. Giffuni * 4*2f07cdf8SPawel Jakub Dawidek * Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel@dawidek.net> 5c58794deSPawel Jakub Dawidek * All rights reserved. 6c58794deSPawel Jakub Dawidek * 7c58794deSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 8c58794deSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 9c58794deSPawel Jakub Dawidek * are met: 10c58794deSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 11c58794deSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 12c58794deSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 13c58794deSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 14c58794deSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 15c58794deSPawel Jakub Dawidek * 16c58794deSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17c58794deSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18c58794deSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19c58794deSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20c58794deSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21c58794deSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22c58794deSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23c58794deSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24c58794deSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25c58794deSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26c58794deSPawel Jakub Dawidek * SUCH DAMAGE. 27c58794deSPawel Jakub Dawidek */ 28c58794deSPawel Jakub Dawidek 29c58794deSPawel Jakub Dawidek #include <sys/cdefs.h> 30c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 31c58794deSPawel Jakub Dawidek 32c58794deSPawel Jakub Dawidek #include <sys/param.h> 33c58794deSPawel Jakub Dawidek #include <sys/systm.h> 34f6ce353eSAndriy Gapon #include <sys/cons.h> 35c58794deSPawel Jakub Dawidek #include <sys/kernel.h> 369af2131bSPawel Jakub Dawidek #include <sys/linker.h> 37c58794deSPawel Jakub Dawidek #include <sys/module.h> 38c58794deSPawel Jakub Dawidek #include <sys/lock.h> 39c58794deSPawel Jakub Dawidek #include <sys/mutex.h> 40c58794deSPawel Jakub Dawidek #include <sys/bio.h> 415d807a0eSAndrey V. Elsukov #include <sys/sbuf.h> 42c58794deSPawel Jakub Dawidek #include <sys/sysctl.h> 43c58794deSPawel Jakub Dawidek #include <sys/malloc.h> 44c5d387d0SPawel Jakub Dawidek #include <sys/eventhandler.h> 45c58794deSPawel Jakub Dawidek #include <sys/kthread.h> 46c58794deSPawel Jakub Dawidek #include <sys/proc.h> 47c58794deSPawel Jakub Dawidek #include <sys/sched.h> 48dd549194SPawel Jakub Dawidek #include <sys/smp.h> 49c58794deSPawel Jakub Dawidek #include <sys/uio.h> 50a80f82a4SPawel Jakub Dawidek #include <sys/vnode.h> 51c58794deSPawel Jakub Dawidek 52c58794deSPawel Jakub Dawidek #include <vm/uma.h> 53c58794deSPawel Jakub Dawidek 54c58794deSPawel Jakub Dawidek #include <geom/geom.h> 55c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h> 56c58794deSPawel Jakub Dawidek #include <geom/eli/pkcs5v2.h> 57c58794deSPawel Jakub Dawidek 58ec5c0e5bSAllan Jude #include <crypto/intake.h> 59ec5c0e5bSAllan Jude 60cb08c2ccSAlexander Leidinger FEATURE(geom_eli, "GEOM crypto module"); 61c58794deSPawel Jakub Dawidek 62c58794deSPawel Jakub Dawidek MALLOC_DEFINE(M_ELI, "eli data", "GEOM_ELI Data"); 63c58794deSPawel Jakub Dawidek 64c58794deSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom); 65c58794deSPawel Jakub Dawidek SYSCTL_NODE(_kern_geom, OID_AUTO, eli, CTLFLAG_RW, 0, "GEOM_ELI stuff"); 66a1f4a8c4SPawel Jakub Dawidek static int g_eli_version = G_ELI_VERSION; 67a1f4a8c4SPawel Jakub Dawidek SYSCTL_INT(_kern_geom_eli, OID_AUTO, version, CTLFLAG_RD, &g_eli_version, 0, 68a1f4a8c4SPawel Jakub Dawidek "GELI version"); 69f95168e0SPawel Jakub Dawidek int g_eli_debug = 0; 70af3b2549SHans Petter Selasky SYSCTL_INT(_kern_geom_eli, OID_AUTO, debug, CTLFLAG_RWTUN, &g_eli_debug, 0, 71c58794deSPawel Jakub Dawidek "Debug level"); 72c58794deSPawel Jakub Dawidek static u_int g_eli_tries = 3; 73af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_geom_eli, OID_AUTO, tries, CTLFLAG_RWTUN, &g_eli_tries, 0, 7498645006SChristian Brueffer "Number of tries for entering the passphrase"); 75eb4c31fdSEd Schouten static u_int g_eli_visible_passphrase = GETS_NOECHO; 76af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_geom_eli, OID_AUTO, visible_passphrase, CTLFLAG_RWTUN, 77c58794deSPawel Jakub Dawidek &g_eli_visible_passphrase, 0, 78eb4c31fdSEd Schouten "Visibility of passphrase prompt (0 = invisible, 1 = visible, 2 = asterisk)"); 79b35bfe7eSPawel Jakub Dawidek u_int g_eli_overwrites = G_ELI_OVERWRITES; 80af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_geom_eli, OID_AUTO, overwrites, CTLFLAG_RWTUN, &g_eli_overwrites, 8198645006SChristian Brueffer 0, "Number of times on-disk keys should be overwritten when destroying them"); 82dd549194SPawel Jakub Dawidek static u_int g_eli_threads = 0; 83af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_geom_eli, OID_AUTO, threads, CTLFLAG_RWTUN, &g_eli_threads, 0, 84c58794deSPawel Jakub Dawidek "Number of threads doing crypto work"); 85eaa3b919SPawel Jakub Dawidek u_int g_eli_batch = 0; 86af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_geom_eli, OID_AUTO, batch, CTLFLAG_RWTUN, &g_eli_batch, 0, 87eaa3b919SPawel Jakub Dawidek "Use crypto operations batching"); 88c58794deSPawel Jakub Dawidek 89835c4dd4SColin Percival /* 90835c4dd4SColin Percival * Passphrase cached during boot, in order to be more user-friendly if 91835c4dd4SColin Percival * there are multiple providers using the same passphrase. 92835c4dd4SColin Percival */ 93835c4dd4SColin Percival static char cached_passphrase[256]; 94835c4dd4SColin Percival static u_int g_eli_boot_passcache = 1; 95835c4dd4SColin Percival TUNABLE_INT("kern.geom.eli.boot_passcache", &g_eli_boot_passcache); 96835c4dd4SColin Percival SYSCTL_UINT(_kern_geom_eli, OID_AUTO, boot_passcache, CTLFLAG_RD, 97835c4dd4SColin Percival &g_eli_boot_passcache, 0, 98835c4dd4SColin Percival "Passphrases are cached during boot process for possible reuse"); 99835c4dd4SColin Percival static void 10066427784SColin Percival fetch_loader_passphrase(void * dummy) 10166427784SColin Percival { 10266427784SColin Percival char * env_passphrase; 10366427784SColin Percival 10466427784SColin Percival KASSERT(dynamic_kenv, ("need dynamic kenv")); 10566427784SColin Percival 10666427784SColin Percival if ((env_passphrase = kern_getenv("kern.geom.eli.passphrase")) != NULL) { 10766427784SColin Percival /* Extract passphrase from the environment. */ 10866427784SColin Percival strlcpy(cached_passphrase, env_passphrase, 10966427784SColin Percival sizeof(cached_passphrase)); 11066427784SColin Percival freeenv(env_passphrase); 11166427784SColin Percival 11266427784SColin Percival /* Wipe the passphrase from the environment. */ 11366427784SColin Percival kern_unsetenv("kern.geom.eli.passphrase"); 11466427784SColin Percival } 11566427784SColin Percival } 11666427784SColin Percival SYSINIT(geli_fetch_loader_passphrase, SI_SUB_KMEM + 1, SI_ORDER_ANY, 11766427784SColin Percival fetch_loader_passphrase, NULL); 118ec5c0e5bSAllan Jude 11966427784SColin Percival static void 120ec5c0e5bSAllan Jude zero_boot_passcache(void) 121835c4dd4SColin Percival { 122835c4dd4SColin Percival 123ec5c0e5bSAllan Jude explicit_bzero(cached_passphrase, sizeof(cached_passphrase)); 124835c4dd4SColin Percival } 125ec5c0e5bSAllan Jude 126ec5c0e5bSAllan Jude static void 127ec5c0e5bSAllan Jude zero_geli_intake_keys(void) 128ec5c0e5bSAllan Jude { 129ec5c0e5bSAllan Jude struct keybuf *keybuf; 130ec5c0e5bSAllan Jude int i; 131ec5c0e5bSAllan Jude 132ec5c0e5bSAllan Jude if ((keybuf = get_keybuf()) != NULL) { 133ec5c0e5bSAllan Jude /* Scan the key buffer, clear all GELI keys. */ 134ec5c0e5bSAllan Jude for (i = 0; i < keybuf->kb_nents; i++) { 135ec5c0e5bSAllan Jude if (keybuf->kb_ents[i].ke_type == KEYBUF_TYPE_GELI) { 136ec5c0e5bSAllan Jude explicit_bzero(keybuf->kb_ents[i].ke_data, 137ec5c0e5bSAllan Jude sizeof(keybuf->kb_ents[i].ke_data)); 138ec5c0e5bSAllan Jude keybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE; 139ec5c0e5bSAllan Jude } 140ec5c0e5bSAllan Jude } 141ec5c0e5bSAllan Jude } 142ec5c0e5bSAllan Jude } 143ec5c0e5bSAllan Jude 144ec5c0e5bSAllan Jude static void 145ec5c0e5bSAllan Jude zero_intake_passcache(void *dummy) 146ec5c0e5bSAllan Jude { 147ec5c0e5bSAllan Jude zero_boot_passcache(); 148ec5c0e5bSAllan Jude zero_geli_intake_keys(); 149ec5c0e5bSAllan Jude } 150ec5c0e5bSAllan Jude EVENTHANDLER_DEFINE(mountroot, zero_intake_passcache, NULL, 0); 151835c4dd4SColin Percival 152c5d387d0SPawel Jakub Dawidek static eventhandler_tag g_eli_pre_sync = NULL; 153c5d387d0SPawel Jakub Dawidek 154*2f07cdf8SPawel Jakub Dawidek static int g_eli_read_metadata_offset(struct g_class *mp, struct g_provider *pp, 155*2f07cdf8SPawel Jakub Dawidek off_t offset, struct g_eli_metadata *md); 156*2f07cdf8SPawel Jakub Dawidek 157c58794deSPawel Jakub Dawidek static int g_eli_destroy_geom(struct gctl_req *req, struct g_class *mp, 158c58794deSPawel Jakub Dawidek struct g_geom *gp); 159c5d387d0SPawel Jakub Dawidek static void g_eli_init(struct g_class *mp); 160c5d387d0SPawel Jakub Dawidek static void g_eli_fini(struct g_class *mp); 161c58794deSPawel Jakub Dawidek 162c58794deSPawel Jakub Dawidek static g_taste_t g_eli_taste; 163c58794deSPawel Jakub Dawidek static g_dumpconf_t g_eli_dumpconf; 164c58794deSPawel Jakub Dawidek 165c58794deSPawel Jakub Dawidek struct g_class g_eli_class = { 166c58794deSPawel Jakub Dawidek .name = G_ELI_CLASS_NAME, 167c58794deSPawel Jakub Dawidek .version = G_VERSION, 168c58794deSPawel Jakub Dawidek .ctlreq = g_eli_config, 169c58794deSPawel Jakub Dawidek .taste = g_eli_taste, 170c5d387d0SPawel Jakub Dawidek .destroy_geom = g_eli_destroy_geom, 171c5d387d0SPawel Jakub Dawidek .init = g_eli_init, 172c5d387d0SPawel Jakub Dawidek .fini = g_eli_fini 173c58794deSPawel Jakub Dawidek }; 174c58794deSPawel Jakub Dawidek 175c58794deSPawel Jakub Dawidek 176c58794deSPawel Jakub Dawidek /* 177c58794deSPawel Jakub Dawidek * Code paths: 178c58794deSPawel Jakub Dawidek * BIO_READ: 1795ad4a7c7SPawel Jakub Dawidek * g_eli_start -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver 180c58794deSPawel Jakub Dawidek * BIO_WRITE: 181c58794deSPawel Jakub Dawidek * g_eli_start -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver 182c58794deSPawel Jakub Dawidek */ 183c58794deSPawel Jakub Dawidek 184c58794deSPawel Jakub Dawidek 185c58794deSPawel Jakub Dawidek /* 186c58794deSPawel Jakub Dawidek * EAGAIN from crypto(9) means, that we were probably balanced to another crypto 187c58794deSPawel Jakub Dawidek * accelerator or something like this. 188c58794deSPawel Jakub Dawidek * The function updates the SID and rerun the operation. 189c58794deSPawel Jakub Dawidek */ 190eaa3b919SPawel Jakub Dawidek int 191c58794deSPawel Jakub Dawidek g_eli_crypto_rerun(struct cryptop *crp) 192c58794deSPawel Jakub Dawidek { 193c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 194c58794deSPawel Jakub Dawidek struct g_eli_worker *wr; 195c58794deSPawel Jakub Dawidek struct bio *bp; 196c58794deSPawel Jakub Dawidek int error; 197c58794deSPawel Jakub Dawidek 198c58794deSPawel Jakub Dawidek bp = (struct bio *)crp->crp_opaque; 199c58794deSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 200c58794deSPawel Jakub Dawidek LIST_FOREACH(wr, &sc->sc_workers, w_next) { 201c58794deSPawel Jakub Dawidek if (wr->w_number == bp->bio_pflags) 202c58794deSPawel Jakub Dawidek break; 203c58794deSPawel Jakub Dawidek } 204c58794deSPawel Jakub Dawidek KASSERT(wr != NULL, ("Invalid worker (%u).", bp->bio_pflags)); 2051b0909d5SConrad Meyer G_ELI_DEBUG(1, "Rerunning crypto %s request (sid: %p -> %p).", 2061b0909d5SConrad Meyer bp->bio_cmd == BIO_READ ? "READ" : "WRITE", wr->w_sid, 2071b0909d5SConrad Meyer crp->crp_session); 2081b0909d5SConrad Meyer wr->w_sid = crp->crp_session; 209c58794deSPawel Jakub Dawidek crp->crp_etype = 0; 210c58794deSPawel Jakub Dawidek error = crypto_dispatch(crp); 211c58794deSPawel Jakub Dawidek if (error == 0) 212c58794deSPawel Jakub Dawidek return (0); 213c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "%s: crypto_dispatch() returned %d.", __func__, error); 214c58794deSPawel Jakub Dawidek crp->crp_etype = error; 215c58794deSPawel Jakub Dawidek return (error); 216c58794deSPawel Jakub Dawidek } 217c58794deSPawel Jakub Dawidek 2180bab7fa8SAlan Somers static void 2190bab7fa8SAlan Somers g_eli_getattr_done(struct bio *bp) 2200bab7fa8SAlan Somers { 2210bab7fa8SAlan Somers if (bp->bio_error == 0 && 2220bab7fa8SAlan Somers !strcmp(bp->bio_attribute, "GEOM::physpath")) { 2230bab7fa8SAlan Somers strlcat(bp->bio_data, "/eli", bp->bio_length); 2240bab7fa8SAlan Somers } 2250bab7fa8SAlan Somers g_std_done(bp); 2260bab7fa8SAlan Somers } 2270bab7fa8SAlan Somers 228c58794deSPawel Jakub Dawidek /* 229c58794deSPawel Jakub Dawidek * The function is called afer reading encrypted data from the provider. 230bb30fea6SPawel Jakub Dawidek * 2315ad4a7c7SPawel Jakub Dawidek * g_eli_start -> g_eli_crypto_read -> g_io_request -> G_ELI_READ_DONE -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver 232c58794deSPawel Jakub Dawidek */ 233eaa3b919SPawel Jakub Dawidek void 234c58794deSPawel Jakub Dawidek g_eli_read_done(struct bio *bp) 235c58794deSPawel Jakub Dawidek { 236c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 237c58794deSPawel Jakub Dawidek struct bio *pbp; 238c58794deSPawel Jakub Dawidek 239c58794deSPawel Jakub Dawidek G_ELI_LOGREQ(2, bp, "Request done."); 240c58794deSPawel Jakub Dawidek pbp = bp->bio_parent; 2412dc7e36bSSteven Hartland if (pbp->bio_error == 0 && bp->bio_error != 0) 242c58794deSPawel Jakub Dawidek pbp->bio_error = bp->bio_error; 24390574b0aSMikolaj Golub g_destroy_bio(bp); 244eaa3b919SPawel Jakub Dawidek /* 245eaa3b919SPawel Jakub Dawidek * Do we have all sectors already? 246eaa3b919SPawel Jakub Dawidek */ 247eaa3b919SPawel Jakub Dawidek pbp->bio_inbed++; 248eaa3b919SPawel Jakub Dawidek if (pbp->bio_inbed < pbp->bio_children) 249eaa3b919SPawel Jakub Dawidek return; 2505ad4a7c7SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 251c58794deSPawel Jakub Dawidek if (pbp->bio_error != 0) { 2522dc7e36bSSteven Hartland G_ELI_LOGREQ(0, pbp, "%s() failed (error=%d)", __func__, 2532dc7e36bSSteven Hartland pbp->bio_error); 254c58794deSPawel Jakub Dawidek pbp->bio_completed = 0; 255eaa3b919SPawel Jakub Dawidek if (pbp->bio_driver2 != NULL) { 256eaa3b919SPawel Jakub Dawidek free(pbp->bio_driver2, M_ELI); 257eaa3b919SPawel Jakub Dawidek pbp->bio_driver2 = NULL; 258eaa3b919SPawel Jakub Dawidek } 259c58794deSPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 26078f79a9aSMariusz Zaborski if (sc != NULL) 2615ad4a7c7SPawel Jakub Dawidek atomic_subtract_int(&sc->sc_inflight, 1); 262c58794deSPawel Jakub Dawidek return; 263c58794deSPawel Jakub Dawidek } 264c58794deSPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 265c58794deSPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, pbp); 266c58794deSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 267c58794deSPawel Jakub Dawidek wakeup(sc); 268c58794deSPawel Jakub Dawidek } 269c58794deSPawel Jakub Dawidek 270c58794deSPawel Jakub Dawidek /* 271c58794deSPawel Jakub Dawidek * The function is called after we encrypt and write data. 272bb30fea6SPawel Jakub Dawidek * 273bb30fea6SPawel Jakub Dawidek * g_eli_start -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> G_ELI_WRITE_DONE -> g_io_deliver 274c58794deSPawel Jakub Dawidek */ 275eaa3b919SPawel Jakub Dawidek void 276c58794deSPawel Jakub Dawidek g_eli_write_done(struct bio *bp) 277c58794deSPawel Jakub Dawidek { 2785ad4a7c7SPawel Jakub Dawidek struct g_eli_softc *sc; 279c58794deSPawel Jakub Dawidek struct bio *pbp; 280c58794deSPawel Jakub Dawidek 281c58794deSPawel Jakub Dawidek G_ELI_LOGREQ(2, bp, "Request done."); 282c58794deSPawel Jakub Dawidek pbp = bp->bio_parent; 2832dc7e36bSSteven Hartland if (pbp->bio_error == 0 && bp->bio_error != 0) 284c58794deSPawel Jakub Dawidek pbp->bio_error = bp->bio_error; 28590574b0aSMikolaj Golub g_destroy_bio(bp); 286eaa3b919SPawel Jakub Dawidek /* 287eaa3b919SPawel Jakub Dawidek * Do we have all sectors already? 288eaa3b919SPawel Jakub Dawidek */ 289eaa3b919SPawel Jakub Dawidek pbp->bio_inbed++; 290eaa3b919SPawel Jakub Dawidek if (pbp->bio_inbed < pbp->bio_children) 291eaa3b919SPawel Jakub Dawidek return; 292c58794deSPawel Jakub Dawidek free(pbp->bio_driver2, M_ELI); 293c58794deSPawel Jakub Dawidek pbp->bio_driver2 = NULL; 294eaa3b919SPawel Jakub Dawidek if (pbp->bio_error != 0) { 2952dc7e36bSSteven Hartland G_ELI_LOGREQ(0, pbp, "%s() failed (error=%d)", __func__, 296c58794deSPawel Jakub Dawidek pbp->bio_error); 297c58794deSPawel Jakub Dawidek pbp->bio_completed = 0; 2982dc7e36bSSteven Hartland } else 2992dc7e36bSSteven Hartland pbp->bio_completed = pbp->bio_length; 3002dc7e36bSSteven Hartland 301c58794deSPawel Jakub Dawidek /* 302c58794deSPawel Jakub Dawidek * Write is finished, send it up. 303c58794deSPawel Jakub Dawidek */ 3045ad4a7c7SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 305c58794deSPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 30678f79a9aSMariusz Zaborski if (sc != NULL) 3075ad4a7c7SPawel Jakub Dawidek atomic_subtract_int(&sc->sc_inflight, 1); 308c58794deSPawel Jakub Dawidek } 309c58794deSPawel Jakub Dawidek 310c58794deSPawel Jakub Dawidek /* 311c58794deSPawel Jakub Dawidek * This function should never be called, but GEOM made as it set ->orphan() 312c58794deSPawel Jakub Dawidek * method for every geom. 313c58794deSPawel Jakub Dawidek */ 314c58794deSPawel Jakub Dawidek static void 315c58794deSPawel Jakub Dawidek g_eli_orphan_spoil_assert(struct g_consumer *cp) 316c58794deSPawel Jakub Dawidek { 317c58794deSPawel Jakub Dawidek 318c58794deSPawel Jakub Dawidek panic("Function %s() called for %s.", __func__, cp->geom->name); 319c58794deSPawel Jakub Dawidek } 320c58794deSPawel Jakub Dawidek 321c58794deSPawel Jakub Dawidek static void 322c58794deSPawel Jakub Dawidek g_eli_orphan(struct g_consumer *cp) 323c58794deSPawel Jakub Dawidek { 324c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 325c58794deSPawel Jakub Dawidek 326c58794deSPawel Jakub Dawidek g_topology_assert(); 327c58794deSPawel Jakub Dawidek sc = cp->geom->softc; 328c58794deSPawel Jakub Dawidek if (sc == NULL) 329c58794deSPawel Jakub Dawidek return; 3305ad4a7c7SPawel Jakub Dawidek g_eli_destroy(sc, TRUE); 331c58794deSPawel Jakub Dawidek } 332c58794deSPawel Jakub Dawidek 333*2f07cdf8SPawel Jakub Dawidek static void 334*2f07cdf8SPawel Jakub Dawidek g_eli_resize(struct g_consumer *cp) 335*2f07cdf8SPawel Jakub Dawidek { 336*2f07cdf8SPawel Jakub Dawidek struct g_eli_softc *sc; 337*2f07cdf8SPawel Jakub Dawidek struct g_provider *epp, *pp; 338*2f07cdf8SPawel Jakub Dawidek off_t oldsize; 339*2f07cdf8SPawel Jakub Dawidek 340*2f07cdf8SPawel Jakub Dawidek g_topology_assert(); 341*2f07cdf8SPawel Jakub Dawidek sc = cp->geom->softc; 342*2f07cdf8SPawel Jakub Dawidek if (sc == NULL) 343*2f07cdf8SPawel Jakub Dawidek return; 344*2f07cdf8SPawel Jakub Dawidek 345*2f07cdf8SPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_AUTORESIZE) == 0) { 346*2f07cdf8SPawel Jakub Dawidek G_ELI_DEBUG(0, "Autoresize is turned off, old size: %jd.", 347*2f07cdf8SPawel Jakub Dawidek (intmax_t)sc->sc_provsize); 348*2f07cdf8SPawel Jakub Dawidek return; 349*2f07cdf8SPawel Jakub Dawidek } 350*2f07cdf8SPawel Jakub Dawidek 351*2f07cdf8SPawel Jakub Dawidek pp = cp->provider; 352*2f07cdf8SPawel Jakub Dawidek 353*2f07cdf8SPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_ONETIME) == 0) { 354*2f07cdf8SPawel Jakub Dawidek struct g_eli_metadata md; 355*2f07cdf8SPawel Jakub Dawidek u_char *sector; 356*2f07cdf8SPawel Jakub Dawidek int error; 357*2f07cdf8SPawel Jakub Dawidek 358*2f07cdf8SPawel Jakub Dawidek sector = NULL; 359*2f07cdf8SPawel Jakub Dawidek 360*2f07cdf8SPawel Jakub Dawidek error = g_eli_read_metadata_offset(cp->geom->class, pp, 361*2f07cdf8SPawel Jakub Dawidek sc->sc_provsize - pp->sectorsize, &md); 362*2f07cdf8SPawel Jakub Dawidek if (error != 0) { 363*2f07cdf8SPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot read metadata from %s (error=%d).", 364*2f07cdf8SPawel Jakub Dawidek pp->name, error); 365*2f07cdf8SPawel Jakub Dawidek goto iofail; 366*2f07cdf8SPawel Jakub Dawidek } 367*2f07cdf8SPawel Jakub Dawidek 368*2f07cdf8SPawel Jakub Dawidek md.md_provsize = pp->mediasize; 369*2f07cdf8SPawel Jakub Dawidek 370*2f07cdf8SPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 371*2f07cdf8SPawel Jakub Dawidek eli_metadata_encode(&md, sector); 372*2f07cdf8SPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 373*2f07cdf8SPawel Jakub Dawidek pp->sectorsize); 374*2f07cdf8SPawel Jakub Dawidek if (error != 0) { 375*2f07cdf8SPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot store metadata on %s (error=%d).", 376*2f07cdf8SPawel Jakub Dawidek pp->name, error); 377*2f07cdf8SPawel Jakub Dawidek goto iofail; 378*2f07cdf8SPawel Jakub Dawidek } 379*2f07cdf8SPawel Jakub Dawidek explicit_bzero(sector, pp->sectorsize); 380*2f07cdf8SPawel Jakub Dawidek error = g_write_data(cp, sc->sc_provsize - pp->sectorsize, 381*2f07cdf8SPawel Jakub Dawidek sector, pp->sectorsize); 382*2f07cdf8SPawel Jakub Dawidek if (error != 0) { 383*2f07cdf8SPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot clear old metadata from %s (error=%d).", 384*2f07cdf8SPawel Jakub Dawidek pp->name, error); 385*2f07cdf8SPawel Jakub Dawidek goto iofail; 386*2f07cdf8SPawel Jakub Dawidek } 387*2f07cdf8SPawel Jakub Dawidek iofail: 388*2f07cdf8SPawel Jakub Dawidek explicit_bzero(&md, sizeof(md)); 389*2f07cdf8SPawel Jakub Dawidek if (sector != NULL) { 390*2f07cdf8SPawel Jakub Dawidek explicit_bzero(sector, pp->sectorsize); 391*2f07cdf8SPawel Jakub Dawidek free(sector, M_ELI); 392*2f07cdf8SPawel Jakub Dawidek } 393*2f07cdf8SPawel Jakub Dawidek } 394*2f07cdf8SPawel Jakub Dawidek 395*2f07cdf8SPawel Jakub Dawidek oldsize = sc->sc_mediasize; 396*2f07cdf8SPawel Jakub Dawidek sc->sc_mediasize = eli_mediasize(sc, pp->mediasize, pp->sectorsize); 397*2f07cdf8SPawel Jakub Dawidek g_eli_key_resize(sc); 398*2f07cdf8SPawel Jakub Dawidek sc->sc_provsize = pp->mediasize; 399*2f07cdf8SPawel Jakub Dawidek 400*2f07cdf8SPawel Jakub Dawidek epp = LIST_FIRST(&sc->sc_geom->provider); 401*2f07cdf8SPawel Jakub Dawidek g_resize_provider(epp, sc->sc_mediasize); 402*2f07cdf8SPawel Jakub Dawidek G_ELI_DEBUG(0, "Device %s size changed from %jd to %jd.", epp->name, 403*2f07cdf8SPawel Jakub Dawidek (intmax_t)oldsize, (intmax_t)sc->sc_mediasize); 404*2f07cdf8SPawel Jakub Dawidek } 405*2f07cdf8SPawel Jakub Dawidek 406bb30fea6SPawel Jakub Dawidek /* 407056638c4SPawel Jakub Dawidek * BIO_READ: 4085ad4a7c7SPawel Jakub Dawidek * G_ELI_START -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver 409056638c4SPawel Jakub Dawidek * BIO_WRITE: 410056638c4SPawel Jakub Dawidek * G_ELI_START -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver 411bb30fea6SPawel Jakub Dawidek */ 412c58794deSPawel Jakub Dawidek static void 413c58794deSPawel Jakub Dawidek g_eli_start(struct bio *bp) 414c58794deSPawel Jakub Dawidek { 415c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 416d3a1be90SPawel Jakub Dawidek struct g_consumer *cp; 417c58794deSPawel Jakub Dawidek struct bio *cbp; 418c58794deSPawel Jakub Dawidek 419c58794deSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 420c58794deSPawel Jakub Dawidek KASSERT(sc != NULL, 421c58794deSPawel Jakub Dawidek ("Provider's error should be set (error=%d)(device=%s).", 422c58794deSPawel Jakub Dawidek bp->bio_to->error, bp->bio_to->name)); 423c58794deSPawel Jakub Dawidek G_ELI_LOGREQ(2, bp, "Request received."); 424c58794deSPawel Jakub Dawidek 425c58794deSPawel Jakub Dawidek switch (bp->bio_cmd) { 426c58794deSPawel Jakub Dawidek case BIO_READ: 427c58794deSPawel Jakub Dawidek case BIO_WRITE: 428d3a1be90SPawel Jakub Dawidek case BIO_GETATTR: 42942461fbaSPawel Jakub Dawidek case BIO_FLUSH: 4309a6844d5SKenneth D. Merry case BIO_ZONE: 431c58794deSPawel Jakub Dawidek break; 432c58794deSPawel Jakub Dawidek case BIO_DELETE: 433c58794deSPawel Jakub Dawidek /* 43446e34470SPawel Jakub Dawidek * If the user hasn't set the NODELETE flag, we just pass 43546e34470SPawel Jakub Dawidek * it down the stack and let the layers beneath us do (or 43646e34470SPawel Jakub Dawidek * not) whatever they do with it. If they have, we 43746e34470SPawel Jakub Dawidek * reject it. A possible extension would be an 43846e34470SPawel Jakub Dawidek * additional flag to take it as a hint to shred the data 43946e34470SPawel Jakub Dawidek * with [multiple?] overwrites. 440c58794deSPawel Jakub Dawidek */ 44146e34470SPawel Jakub Dawidek if (!(sc->sc_flags & G_ELI_FLAG_NODELETE)) 44246e34470SPawel Jakub Dawidek break; 443c58794deSPawel Jakub Dawidek default: 444c58794deSPawel Jakub Dawidek g_io_deliver(bp, EOPNOTSUPP); 445c58794deSPawel Jakub Dawidek return; 446c58794deSPawel Jakub Dawidek } 447c58794deSPawel Jakub Dawidek cbp = g_clone_bio(bp); 448c58794deSPawel Jakub Dawidek if (cbp == NULL) { 449c58794deSPawel Jakub Dawidek g_io_deliver(bp, ENOMEM); 450c58794deSPawel Jakub Dawidek return; 451c58794deSPawel Jakub Dawidek } 4525ad4a7c7SPawel Jakub Dawidek bp->bio_driver1 = cbp; 4535ad4a7c7SPawel Jakub Dawidek bp->bio_pflags = G_ELI_NEW_BIO; 454d3a1be90SPawel Jakub Dawidek switch (bp->bio_cmd) { 455d3a1be90SPawel Jakub Dawidek case BIO_READ: 456eaa3b919SPawel Jakub Dawidek if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) { 4575ad4a7c7SPawel Jakub Dawidek g_eli_crypto_read(sc, bp, 0); 458d3a1be90SPawel Jakub Dawidek break; 459eaa3b919SPawel Jakub Dawidek } 460eaa3b919SPawel Jakub Dawidek /* FALLTHROUGH */ 461d3a1be90SPawel Jakub Dawidek case BIO_WRITE: 462c58794deSPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 463c58794deSPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, bp); 464c58794deSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 465c58794deSPawel Jakub Dawidek wakeup(sc); 466d3a1be90SPawel Jakub Dawidek break; 467d3a1be90SPawel Jakub Dawidek case BIO_GETATTR: 46842461fbaSPawel Jakub Dawidek case BIO_FLUSH: 46946e34470SPawel Jakub Dawidek case BIO_DELETE: 4709a6844d5SKenneth D. Merry case BIO_ZONE: 4710bab7fa8SAlan Somers if (bp->bio_cmd == BIO_GETATTR) 4720bab7fa8SAlan Somers cbp->bio_done = g_eli_getattr_done; 4730bab7fa8SAlan Somers else 474d3a1be90SPawel Jakub Dawidek cbp->bio_done = g_std_done; 475d3a1be90SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 476d3a1be90SPawel Jakub Dawidek cbp->bio_to = cp->provider; 477cd0d707eSPawel Jakub Dawidek G_ELI_LOGREQ(2, cbp, "Sending request."); 478d3a1be90SPawel Jakub Dawidek g_io_request(cbp, cp); 479d3a1be90SPawel Jakub Dawidek break; 480c58794deSPawel Jakub Dawidek } 481c58794deSPawel Jakub Dawidek } 482c58794deSPawel Jakub Dawidek 4833ac01bc2SPawel Jakub Dawidek static int 4843ac01bc2SPawel Jakub Dawidek g_eli_newsession(struct g_eli_worker *wr) 4853ac01bc2SPawel Jakub Dawidek { 4863ac01bc2SPawel Jakub Dawidek struct g_eli_softc *sc; 4873ac01bc2SPawel Jakub Dawidek struct cryptoini crie, cria; 4883ac01bc2SPawel Jakub Dawidek int error; 4893ac01bc2SPawel Jakub Dawidek 4903ac01bc2SPawel Jakub Dawidek sc = wr->w_softc; 4913ac01bc2SPawel Jakub Dawidek 4923ac01bc2SPawel Jakub Dawidek bzero(&crie, sizeof(crie)); 4933ac01bc2SPawel Jakub Dawidek crie.cri_alg = sc->sc_ealgo; 4943ac01bc2SPawel Jakub Dawidek crie.cri_klen = sc->sc_ekeylen; 4953ac01bc2SPawel Jakub Dawidek if (sc->sc_ealgo == CRYPTO_AES_XTS) 4963ac01bc2SPawel Jakub Dawidek crie.cri_klen <<= 1; 497ad0a5236SPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_FIRST_KEY) != 0) { 498ad0a5236SPawel Jakub Dawidek crie.cri_key = g_eli_key_hold(sc, 0, 499ad0a5236SPawel Jakub Dawidek LIST_FIRST(&sc->sc_geom->consumer)->provider->sectorsize); 500ad0a5236SPawel Jakub Dawidek } else { 5011e09ff3dSPawel Jakub Dawidek crie.cri_key = sc->sc_ekey; 502ad0a5236SPawel Jakub Dawidek } 5033ac01bc2SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_AUTH) { 5043ac01bc2SPawel Jakub Dawidek bzero(&cria, sizeof(cria)); 5053ac01bc2SPawel Jakub Dawidek cria.cri_alg = sc->sc_aalgo; 5063ac01bc2SPawel Jakub Dawidek cria.cri_klen = sc->sc_akeylen; 5073ac01bc2SPawel Jakub Dawidek cria.cri_key = sc->sc_akey; 5083ac01bc2SPawel Jakub Dawidek crie.cri_next = &cria; 5093ac01bc2SPawel Jakub Dawidek } 5103ac01bc2SPawel Jakub Dawidek 5113ac01bc2SPawel Jakub Dawidek switch (sc->sc_crypto) { 5123ac01bc2SPawel Jakub Dawidek case G_ELI_CRYPTO_SW: 5133ac01bc2SPawel Jakub Dawidek error = crypto_newsession(&wr->w_sid, &crie, 5143ac01bc2SPawel Jakub Dawidek CRYPTOCAP_F_SOFTWARE); 5153ac01bc2SPawel Jakub Dawidek break; 5163ac01bc2SPawel Jakub Dawidek case G_ELI_CRYPTO_HW: 5173ac01bc2SPawel Jakub Dawidek error = crypto_newsession(&wr->w_sid, &crie, 5183ac01bc2SPawel Jakub Dawidek CRYPTOCAP_F_HARDWARE); 5193ac01bc2SPawel Jakub Dawidek break; 5203ac01bc2SPawel Jakub Dawidek case G_ELI_CRYPTO_UNKNOWN: 5213ac01bc2SPawel Jakub Dawidek error = crypto_newsession(&wr->w_sid, &crie, 5223ac01bc2SPawel Jakub Dawidek CRYPTOCAP_F_HARDWARE); 5233ac01bc2SPawel Jakub Dawidek if (error == 0) { 5243ac01bc2SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 5253ac01bc2SPawel Jakub Dawidek if (sc->sc_crypto == G_ELI_CRYPTO_UNKNOWN) 5263ac01bc2SPawel Jakub Dawidek sc->sc_crypto = G_ELI_CRYPTO_HW; 5273ac01bc2SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 5283ac01bc2SPawel Jakub Dawidek } else { 5293ac01bc2SPawel Jakub Dawidek error = crypto_newsession(&wr->w_sid, &crie, 5303ac01bc2SPawel Jakub Dawidek CRYPTOCAP_F_SOFTWARE); 5313ac01bc2SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 5323ac01bc2SPawel Jakub Dawidek if (sc->sc_crypto == G_ELI_CRYPTO_UNKNOWN) 5333ac01bc2SPawel Jakub Dawidek sc->sc_crypto = G_ELI_CRYPTO_SW; 5343ac01bc2SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 5353ac01bc2SPawel Jakub Dawidek } 5363ac01bc2SPawel Jakub Dawidek break; 5373ac01bc2SPawel Jakub Dawidek default: 5383ac01bc2SPawel Jakub Dawidek panic("%s: invalid condition", __func__); 5393ac01bc2SPawel Jakub Dawidek } 5403ac01bc2SPawel Jakub Dawidek 541ad0a5236SPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_FIRST_KEY) != 0) 542ad0a5236SPawel Jakub Dawidek g_eli_key_drop(sc, crie.cri_key); 543ad0a5236SPawel Jakub Dawidek 5443ac01bc2SPawel Jakub Dawidek return (error); 5453ac01bc2SPawel Jakub Dawidek } 5463ac01bc2SPawel Jakub Dawidek 5473ac01bc2SPawel Jakub Dawidek static void 5483ac01bc2SPawel Jakub Dawidek g_eli_freesession(struct g_eli_worker *wr) 5493ac01bc2SPawel Jakub Dawidek { 5503ac01bc2SPawel Jakub Dawidek 5513ac01bc2SPawel Jakub Dawidek crypto_freesession(wr->w_sid); 5523ac01bc2SPawel Jakub Dawidek } 5533ac01bc2SPawel Jakub Dawidek 5545ad4a7c7SPawel Jakub Dawidek static void 5555ad4a7c7SPawel Jakub Dawidek g_eli_cancel(struct g_eli_softc *sc) 5565ad4a7c7SPawel Jakub Dawidek { 5575ad4a7c7SPawel Jakub Dawidek struct bio *bp; 5585ad4a7c7SPawel Jakub Dawidek 5595ad4a7c7SPawel Jakub Dawidek mtx_assert(&sc->sc_queue_mtx, MA_OWNED); 5605ad4a7c7SPawel Jakub Dawidek 5615ad4a7c7SPawel Jakub Dawidek while ((bp = bioq_takefirst(&sc->sc_queue)) != NULL) { 5625ad4a7c7SPawel Jakub Dawidek KASSERT(bp->bio_pflags == G_ELI_NEW_BIO, 5635ad4a7c7SPawel Jakub Dawidek ("Not new bio when canceling (bp=%p).", bp)); 5645ad4a7c7SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 5655ad4a7c7SPawel Jakub Dawidek } 5665ad4a7c7SPawel Jakub Dawidek } 5675ad4a7c7SPawel Jakub Dawidek 5685ad4a7c7SPawel Jakub Dawidek static struct bio * 5695ad4a7c7SPawel Jakub Dawidek g_eli_takefirst(struct g_eli_softc *sc) 5705ad4a7c7SPawel Jakub Dawidek { 5715ad4a7c7SPawel Jakub Dawidek struct bio *bp; 5725ad4a7c7SPawel Jakub Dawidek 5735ad4a7c7SPawel Jakub Dawidek mtx_assert(&sc->sc_queue_mtx, MA_OWNED); 5745ad4a7c7SPawel Jakub Dawidek 5755ad4a7c7SPawel Jakub Dawidek if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND)) 5765ad4a7c7SPawel Jakub Dawidek return (bioq_takefirst(&sc->sc_queue)); 5775ad4a7c7SPawel Jakub Dawidek /* 5785ad4a7c7SPawel Jakub Dawidek * Device suspended, so we skip new I/O requests. 5795ad4a7c7SPawel Jakub Dawidek */ 5805ad4a7c7SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_queue.queue, bio_queue) { 5815ad4a7c7SPawel Jakub Dawidek if (bp->bio_pflags != G_ELI_NEW_BIO) 5825ad4a7c7SPawel Jakub Dawidek break; 5835ad4a7c7SPawel Jakub Dawidek } 5845ad4a7c7SPawel Jakub Dawidek if (bp != NULL) 5855ad4a7c7SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 5865ad4a7c7SPawel Jakub Dawidek return (bp); 5875ad4a7c7SPawel Jakub Dawidek } 5885ad4a7c7SPawel Jakub Dawidek 589c58794deSPawel Jakub Dawidek /* 590c58794deSPawel Jakub Dawidek * This is the main function for kernel worker thread when we don't have 591c58794deSPawel Jakub Dawidek * hardware acceleration and we have to do cryptography in software. 592c58794deSPawel Jakub Dawidek * Dedicated thread is needed, so we don't slow down g_up/g_down GEOM 593c58794deSPawel Jakub Dawidek * threads with crypto work. 594c58794deSPawel Jakub Dawidek */ 595c58794deSPawel Jakub Dawidek static void 596c58794deSPawel Jakub Dawidek g_eli_worker(void *arg) 597c58794deSPawel Jakub Dawidek { 598c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 599c58794deSPawel Jakub Dawidek struct g_eli_worker *wr; 600c58794deSPawel Jakub Dawidek struct bio *bp; 6013ac01bc2SPawel Jakub Dawidek int error; 602c58794deSPawel Jakub Dawidek 603c58794deSPawel Jakub Dawidek wr = arg; 604c58794deSPawel Jakub Dawidek sc = wr->w_softc; 605fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP 606fdce57a0SJohn Baldwin MPASS(!sc->sc_cpubind || smp_started); 607fdce57a0SJohn Baldwin #elif defined(SMP) 608a1ea1a22SPawel Jakub Dawidek /* Before sched_bind() to a CPU, wait for all CPUs to go on-line. */ 6090c879bd9SPawel Jakub Dawidek if (sc->sc_cpubind) { 610a1ea1a22SPawel Jakub Dawidek while (!smp_started) 611a1ea1a22SPawel Jakub Dawidek tsleep(wr, 0, "geli:smp", hz / 4); 612a1ea1a22SPawel Jakub Dawidek } 613a1ea1a22SPawel Jakub Dawidek #endif 614982d11f8SJeff Roberson thread_lock(curthread); 61531c4cef7SPawel Jakub Dawidek sched_prio(curthread, PUSER); 6160c879bd9SPawel Jakub Dawidek if (sc->sc_cpubind) 6170c879bd9SPawel Jakub Dawidek sched_bind(curthread, wr->w_number % mp_ncpus); 618982d11f8SJeff Roberson thread_unlock(curthread); 619c58794deSPawel Jakub Dawidek 620c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Thread %s started.", curthread->td_proc->p_comm); 621c58794deSPawel Jakub Dawidek 622c58794deSPawel Jakub Dawidek for (;;) { 623c58794deSPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 6245ad4a7c7SPawel Jakub Dawidek again: 6255ad4a7c7SPawel Jakub Dawidek bp = g_eli_takefirst(sc); 626c58794deSPawel Jakub Dawidek if (bp == NULL) { 627eaa3b919SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_DESTROY) { 6285ad4a7c7SPawel Jakub Dawidek g_eli_cancel(sc); 629c58794deSPawel Jakub Dawidek LIST_REMOVE(wr, w_next); 6303ac01bc2SPawel Jakub Dawidek g_eli_freesession(wr); 631c58794deSPawel Jakub Dawidek free(wr, M_ELI); 632c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Thread %s exiting.", 633c58794deSPawel Jakub Dawidek curthread->td_proc->p_comm); 634c58794deSPawel Jakub Dawidek wakeup(&sc->sc_workers); 635c58794deSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 6363745c395SJulian Elischer kproc_exit(0); 637c58794deSPawel Jakub Dawidek } 6385ad4a7c7SPawel Jakub Dawidek while (sc->sc_flags & G_ELI_FLAG_SUSPEND) { 6395ad4a7c7SPawel Jakub Dawidek if (sc->sc_inflight > 0) { 640038c55adSPawel Jakub Dawidek G_ELI_DEBUG(0, "inflight=%d", 641038c55adSPawel Jakub Dawidek sc->sc_inflight); 6425ad4a7c7SPawel Jakub Dawidek /* 6435ad4a7c7SPawel Jakub Dawidek * We still have inflight BIOs, so 6445ad4a7c7SPawel Jakub Dawidek * sleep and retry. 6455ad4a7c7SPawel Jakub Dawidek */ 6465ad4a7c7SPawel Jakub Dawidek msleep(sc, &sc->sc_queue_mtx, PRIBIO, 6475ad4a7c7SPawel Jakub Dawidek "geli:inf", hz / 5); 6485ad4a7c7SPawel Jakub Dawidek goto again; 6495ad4a7c7SPawel Jakub Dawidek } 6505ad4a7c7SPawel Jakub Dawidek /* 6515ad4a7c7SPawel Jakub Dawidek * Suspend requested, mark the worker as 6525ad4a7c7SPawel Jakub Dawidek * suspended and go to sleep. 6535ad4a7c7SPawel Jakub Dawidek */ 6543ac01bc2SPawel Jakub Dawidek if (wr->w_active) { 6553ac01bc2SPawel Jakub Dawidek g_eli_freesession(wr); 6563ac01bc2SPawel Jakub Dawidek wr->w_active = FALSE; 6573ac01bc2SPawel Jakub Dawidek } 6585ad4a7c7SPawel Jakub Dawidek wakeup(&sc->sc_workers); 6595ad4a7c7SPawel Jakub Dawidek msleep(sc, &sc->sc_queue_mtx, PRIBIO, 6605ad4a7c7SPawel Jakub Dawidek "geli:suspend", 0); 6613ac01bc2SPawel Jakub Dawidek if (!wr->w_active && 6623ac01bc2SPawel Jakub Dawidek !(sc->sc_flags & G_ELI_FLAG_SUSPEND)) { 6633ac01bc2SPawel Jakub Dawidek error = g_eli_newsession(wr); 6643ac01bc2SPawel Jakub Dawidek KASSERT(error == 0, 6653ac01bc2SPawel Jakub Dawidek ("g_eli_newsession() failed on resume (error=%d)", 6663ac01bc2SPawel Jakub Dawidek error)); 6673ac01bc2SPawel Jakub Dawidek wr->w_active = TRUE; 6683ac01bc2SPawel Jakub Dawidek } 6695ad4a7c7SPawel Jakub Dawidek goto again; 6705ad4a7c7SPawel Jakub Dawidek } 67131c4cef7SPawel Jakub Dawidek msleep(sc, &sc->sc_queue_mtx, PDROP, "geli:w", 0); 672c58794deSPawel Jakub Dawidek continue; 673c58794deSPawel Jakub Dawidek } 6745ad4a7c7SPawel Jakub Dawidek if (bp->bio_pflags == G_ELI_NEW_BIO) 6755ad4a7c7SPawel Jakub Dawidek atomic_add_int(&sc->sc_inflight, 1); 676c58794deSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 6775ad4a7c7SPawel Jakub Dawidek if (bp->bio_pflags == G_ELI_NEW_BIO) { 6785ad4a7c7SPawel Jakub Dawidek bp->bio_pflags = 0; 6795ad4a7c7SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_AUTH) { 6805ad4a7c7SPawel Jakub Dawidek if (bp->bio_cmd == BIO_READ) 681eaa3b919SPawel Jakub Dawidek g_eli_auth_read(sc, bp); 6825ad4a7c7SPawel Jakub Dawidek else 6835ad4a7c7SPawel Jakub Dawidek g_eli_auth_run(wr, bp); 6845ad4a7c7SPawel Jakub Dawidek } else { 6855ad4a7c7SPawel Jakub Dawidek if (bp->bio_cmd == BIO_READ) 6865ad4a7c7SPawel Jakub Dawidek g_eli_crypto_read(sc, bp, 1); 6875ad4a7c7SPawel Jakub Dawidek else 6885ad4a7c7SPawel Jakub Dawidek g_eli_crypto_run(wr, bp); 6895ad4a7c7SPawel Jakub Dawidek } 6905ad4a7c7SPawel Jakub Dawidek } else { 6915ad4a7c7SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_AUTH) 692eaa3b919SPawel Jakub Dawidek g_eli_auth_run(wr, bp); 693eaa3b919SPawel Jakub Dawidek else 694dddd1d53SPawel Jakub Dawidek g_eli_crypto_run(wr, bp); 695c58794deSPawel Jakub Dawidek } 696c58794deSPawel Jakub Dawidek } 6975ad4a7c7SPawel Jakub Dawidek } 698c58794deSPawel Jakub Dawidek 699*2f07cdf8SPawel Jakub Dawidek static int 700*2f07cdf8SPawel Jakub Dawidek g_eli_read_metadata_offset(struct g_class *mp, struct g_provider *pp, 701*2f07cdf8SPawel Jakub Dawidek off_t offset, struct g_eli_metadata *md) 702c58794deSPawel Jakub Dawidek { 703c58794deSPawel Jakub Dawidek struct g_geom *gp; 704c58794deSPawel Jakub Dawidek struct g_consumer *cp; 705c58794deSPawel Jakub Dawidek u_char *buf = NULL; 706c58794deSPawel Jakub Dawidek int error; 707c58794deSPawel Jakub Dawidek 708c58794deSPawel Jakub Dawidek g_topology_assert(); 709c58794deSPawel Jakub Dawidek 710c58794deSPawel Jakub Dawidek gp = g_new_geomf(mp, "eli:taste"); 711c58794deSPawel Jakub Dawidek gp->start = g_eli_start; 712c58794deSPawel Jakub Dawidek gp->access = g_std_access; 713c58794deSPawel Jakub Dawidek /* 714c58794deSPawel Jakub Dawidek * g_eli_read_metadata() is always called from the event thread. 715c58794deSPawel Jakub Dawidek * Our geom is created and destroyed in the same event, so there 716c58794deSPawel Jakub Dawidek * could be no orphan nor spoil event in the meantime. 717c58794deSPawel Jakub Dawidek */ 718c58794deSPawel Jakub Dawidek gp->orphan = g_eli_orphan_spoil_assert; 719c58794deSPawel Jakub Dawidek gp->spoiled = g_eli_orphan_spoil_assert; 720c58794deSPawel Jakub Dawidek cp = g_new_consumer(gp); 721c58794deSPawel Jakub Dawidek error = g_attach(cp, pp); 722c58794deSPawel Jakub Dawidek if (error != 0) 723c58794deSPawel Jakub Dawidek goto end; 724c58794deSPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 725c58794deSPawel Jakub Dawidek if (error != 0) 726c58794deSPawel Jakub Dawidek goto end; 727c58794deSPawel Jakub Dawidek g_topology_unlock(); 728*2f07cdf8SPawel Jakub Dawidek buf = g_read_data(cp, offset, pp->sectorsize, &error); 729c58794deSPawel Jakub Dawidek g_topology_lock(); 7308a4a44b5SMaxim Sobolev if (buf == NULL) 731c58794deSPawel Jakub Dawidek goto end; 732fefb6a14SPawel Jakub Dawidek error = eli_metadata_decode(buf, md); 733fefb6a14SPawel Jakub Dawidek if (error != 0) 734fefb6a14SPawel Jakub Dawidek goto end; 735fefb6a14SPawel Jakub Dawidek /* Metadata was read and decoded successfully. */ 736c58794deSPawel Jakub Dawidek end: 737c58794deSPawel Jakub Dawidek if (buf != NULL) 738c58794deSPawel Jakub Dawidek g_free(buf); 739c58794deSPawel Jakub Dawidek if (cp->provider != NULL) { 740c58794deSPawel Jakub Dawidek if (cp->acr == 1) 741c58794deSPawel Jakub Dawidek g_access(cp, -1, 0, 0); 742c58794deSPawel Jakub Dawidek g_detach(cp); 743c58794deSPawel Jakub Dawidek } 744c58794deSPawel Jakub Dawidek g_destroy_consumer(cp); 745c58794deSPawel Jakub Dawidek g_destroy_geom(gp); 746c58794deSPawel Jakub Dawidek return (error); 747c58794deSPawel Jakub Dawidek } 748c58794deSPawel Jakub Dawidek 749*2f07cdf8SPawel Jakub Dawidek int 750*2f07cdf8SPawel Jakub Dawidek g_eli_read_metadata(struct g_class *mp, struct g_provider *pp, 751*2f07cdf8SPawel Jakub Dawidek struct g_eli_metadata *md) 752*2f07cdf8SPawel Jakub Dawidek { 753*2f07cdf8SPawel Jakub Dawidek 754*2f07cdf8SPawel Jakub Dawidek return (g_eli_read_metadata_offset(mp, pp, 755*2f07cdf8SPawel Jakub Dawidek pp->mediasize - pp->sectorsize, md)); 756*2f07cdf8SPawel Jakub Dawidek } 757*2f07cdf8SPawel Jakub Dawidek 758c58794deSPawel Jakub Dawidek /* 759c58794deSPawel Jakub Dawidek * The function is called when we had last close on provider and user requested 760c58794deSPawel Jakub Dawidek * to close it when this situation occur. 761c58794deSPawel Jakub Dawidek */ 762c58794deSPawel Jakub Dawidek static void 76319351a14SAlexander Motin g_eli_last_close(void *arg, int flags __unused) 764c58794deSPawel Jakub Dawidek { 765c58794deSPawel Jakub Dawidek struct g_geom *gp; 76619351a14SAlexander Motin char gpname[64]; 767c58794deSPawel Jakub Dawidek int error; 768c58794deSPawel Jakub Dawidek 769c58794deSPawel Jakub Dawidek g_topology_assert(); 77019351a14SAlexander Motin gp = arg; 77119351a14SAlexander Motin strlcpy(gpname, gp->name, sizeof(gpname)); 77219351a14SAlexander Motin error = g_eli_destroy(gp->softc, TRUE); 773c58794deSPawel Jakub Dawidek KASSERT(error == 0, ("Cannot detach %s on last close (error=%d).", 77419351a14SAlexander Motin gpname, error)); 77519351a14SAlexander Motin G_ELI_DEBUG(0, "Detached %s on last close.", gpname); 776c58794deSPawel Jakub Dawidek } 777c58794deSPawel Jakub Dawidek 778c58794deSPawel Jakub Dawidek int 779c58794deSPawel Jakub Dawidek g_eli_access(struct g_provider *pp, int dr, int dw, int de) 780c58794deSPawel Jakub Dawidek { 781c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 782c58794deSPawel Jakub Dawidek struct g_geom *gp; 783c58794deSPawel Jakub Dawidek 784c58794deSPawel Jakub Dawidek gp = pp->geom; 785c58794deSPawel Jakub Dawidek sc = gp->softc; 786c58794deSPawel Jakub Dawidek 787c58794deSPawel Jakub Dawidek if (dw > 0) { 78885059016SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_RO) { 78985059016SPawel Jakub Dawidek /* Deny write attempts. */ 79085059016SPawel Jakub Dawidek return (EROFS); 79185059016SPawel Jakub Dawidek } 792c58794deSPawel Jakub Dawidek /* Someone is opening us for write, we need to remember that. */ 793c58794deSPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_WOPEN; 794c58794deSPawel Jakub Dawidek return (0); 795c58794deSPawel Jakub Dawidek } 796c58794deSPawel Jakub Dawidek /* Is this the last close? */ 797c58794deSPawel Jakub Dawidek if (pp->acr + dr > 0 || pp->acw + dw > 0 || pp->ace + de > 0) 798c58794deSPawel Jakub Dawidek return (0); 799c58794deSPawel Jakub Dawidek 800c58794deSPawel Jakub Dawidek /* 801c58794deSPawel Jakub Dawidek * Automatically detach on last close if requested. 802c58794deSPawel Jakub Dawidek */ 803c58794deSPawel Jakub Dawidek if ((sc->sc_flags & G_ELI_FLAG_RW_DETACH) || 804c58794deSPawel Jakub Dawidek (sc->sc_flags & G_ELI_FLAG_WOPEN)) { 80519351a14SAlexander Motin g_post_event(g_eli_last_close, gp, M_WAITOK, NULL); 806c58794deSPawel Jakub Dawidek } 807c58794deSPawel Jakub Dawidek return (0); 808c58794deSPawel Jakub Dawidek } 809c58794deSPawel Jakub Dawidek 810eba8f137SPawel Jakub Dawidek static int 811eba8f137SPawel Jakub Dawidek g_eli_cpu_is_disabled(int cpu) 812eba8f137SPawel Jakub Dawidek { 813eba8f137SPawel Jakub Dawidek #ifdef SMP 81471a19bdcSAttilio Rao return (CPU_ISSET(cpu, &hlt_cpus_mask)); 815eba8f137SPawel Jakub Dawidek #else 816eba8f137SPawel Jakub Dawidek return (0); 817eba8f137SPawel Jakub Dawidek #endif 818eba8f137SPawel Jakub Dawidek } 819eba8f137SPawel Jakub Dawidek 820c58794deSPawel Jakub Dawidek struct g_geom * 821c58794deSPawel Jakub Dawidek g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, 822c58794deSPawel Jakub Dawidek const struct g_eli_metadata *md, const u_char *mkey, int nkey) 823c58794deSPawel Jakub Dawidek { 824c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 825c58794deSPawel Jakub Dawidek struct g_eli_worker *wr; 826c58794deSPawel Jakub Dawidek struct g_geom *gp; 827c58794deSPawel Jakub Dawidek struct g_provider *pp; 828c58794deSPawel Jakub Dawidek struct g_consumer *cp; 829c58794deSPawel Jakub Dawidek u_int i, threads; 830c58794deSPawel Jakub Dawidek int error; 831c58794deSPawel Jakub Dawidek 832c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Creating device %s%s.", bpp->name, G_ELI_SUFFIX); 833c58794deSPawel Jakub Dawidek 834c58794deSPawel Jakub Dawidek gp = g_new_geomf(mp, "%s%s", bpp->name, G_ELI_SUFFIX); 835c58794deSPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_ELI, M_WAITOK | M_ZERO); 836c58794deSPawel Jakub Dawidek gp->start = g_eli_start; 837c58794deSPawel Jakub Dawidek /* 8384273d412SPawel Jakub Dawidek * Spoiling can happen even though we have the provider open 8394273d412SPawel Jakub Dawidek * exclusively, e.g. through media change events. 840c58794deSPawel Jakub Dawidek */ 8414273d412SPawel Jakub Dawidek gp->spoiled = g_eli_orphan; 842c58794deSPawel Jakub Dawidek gp->orphan = g_eli_orphan; 843*2f07cdf8SPawel Jakub Dawidek gp->resize = g_eli_resize; 84485059016SPawel Jakub Dawidek gp->dumpconf = g_eli_dumpconf; 845c58794deSPawel Jakub Dawidek /* 84685059016SPawel Jakub Dawidek * If detach-on-last-close feature is not enabled and we don't operate 84785059016SPawel Jakub Dawidek * on read-only provider, we can simply use g_std_access(). 848c58794deSPawel Jakub Dawidek */ 84985059016SPawel Jakub Dawidek if (md->md_flags & (G_ELI_FLAG_WO_DETACH | G_ELI_FLAG_RO)) 850c58794deSPawel Jakub Dawidek gp->access = g_eli_access; 851c58794deSPawel Jakub Dawidek else 852c58794deSPawel Jakub Dawidek gp->access = g_std_access; 853c58794deSPawel Jakub Dawidek 8544332fecaSAllan Jude eli_metadata_softc(sc, md, bpp->sectorsize, bpp->mediasize); 855c58794deSPawel Jakub Dawidek sc->sc_nkey = nkey; 856eaa3b919SPawel Jakub Dawidek 857c58794deSPawel Jakub Dawidek gp->softc = sc; 858c58794deSPawel Jakub Dawidek sc->sc_geom = gp; 859c58794deSPawel Jakub Dawidek 860c58794deSPawel Jakub Dawidek bioq_init(&sc->sc_queue); 861c58794deSPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "geli:queue", NULL, MTX_DEF); 8621e09ff3dSPawel Jakub Dawidek mtx_init(&sc->sc_ekeys_lock, "geli:ekeys", NULL, MTX_DEF); 863c58794deSPawel Jakub Dawidek 864c58794deSPawel Jakub Dawidek pp = NULL; 865c58794deSPawel Jakub Dawidek cp = g_new_consumer(gp); 866c58794deSPawel Jakub Dawidek error = g_attach(cp, bpp); 867c58794deSPawel Jakub Dawidek if (error != 0) { 868c58794deSPawel Jakub Dawidek if (req != NULL) { 869c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot attach to %s (error=%d).", 870c58794deSPawel Jakub Dawidek bpp->name, error); 871c58794deSPawel Jakub Dawidek } else { 872c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Cannot attach to %s (error=%d).", 873c58794deSPawel Jakub Dawidek bpp->name, error); 874c58794deSPawel Jakub Dawidek } 875c58794deSPawel Jakub Dawidek goto failed; 876c58794deSPawel Jakub Dawidek } 877c58794deSPawel Jakub Dawidek /* 878c58794deSPawel Jakub Dawidek * Keep provider open all the time, so we can run critical tasks, 879c58794deSPawel Jakub Dawidek * like Master Keys deletion, without wondering if we can open 880c58794deSPawel Jakub Dawidek * provider or not. 88185059016SPawel Jakub Dawidek * We don't open provider for writing only when user requested read-only 88285059016SPawel Jakub Dawidek * access. 883c58794deSPawel Jakub Dawidek */ 88485059016SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_RO) 88585059016SPawel Jakub Dawidek error = g_access(cp, 1, 0, 1); 88685059016SPawel Jakub Dawidek else 887c58794deSPawel Jakub Dawidek error = g_access(cp, 1, 1, 1); 888c58794deSPawel Jakub Dawidek if (error != 0) { 889c58794deSPawel Jakub Dawidek if (req != NULL) { 890c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot access %s (error=%d).", 891c58794deSPawel Jakub Dawidek bpp->name, error); 892c58794deSPawel Jakub Dawidek } else { 893c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Cannot access %s (error=%d).", 894c58794deSPawel Jakub Dawidek bpp->name, error); 895c58794deSPawel Jakub Dawidek } 896c58794deSPawel Jakub Dawidek goto failed; 897c58794deSPawel Jakub Dawidek } 898c58794deSPawel Jakub Dawidek 899c6a26d4cSPawel Jakub Dawidek /* 900c6a26d4cSPawel Jakub Dawidek * Remember the keys in our softc structure. 901c6a26d4cSPawel Jakub Dawidek */ 902c6a26d4cSPawel Jakub Dawidek g_eli_mkey_propagate(sc, mkey); 903c6a26d4cSPawel Jakub Dawidek 904c58794deSPawel Jakub Dawidek LIST_INIT(&sc->sc_workers); 905c58794deSPawel Jakub Dawidek 906c58794deSPawel Jakub Dawidek threads = g_eli_threads; 907dd549194SPawel Jakub Dawidek if (threads == 0) 908dd549194SPawel Jakub Dawidek threads = mp_ncpus; 9090c879bd9SPawel Jakub Dawidek sc->sc_cpubind = (mp_ncpus > 1 && threads == mp_ncpus); 910c58794deSPawel Jakub Dawidek for (i = 0; i < threads; i++) { 911eba8f137SPawel Jakub Dawidek if (g_eli_cpu_is_disabled(i)) { 912eba8f137SPawel Jakub Dawidek G_ELI_DEBUG(1, "%s: CPU %u disabled, skipping.", 9131506db21SPawel Jakub Dawidek bpp->name, i); 914eba8f137SPawel Jakub Dawidek continue; 915eba8f137SPawel Jakub Dawidek } 916c58794deSPawel Jakub Dawidek wr = malloc(sizeof(*wr), M_ELI, M_WAITOK | M_ZERO); 917c58794deSPawel Jakub Dawidek wr->w_softc = sc; 918c58794deSPawel Jakub Dawidek wr->w_number = i; 9195ad4a7c7SPawel Jakub Dawidek wr->w_active = TRUE; 920c58794deSPawel Jakub Dawidek 9213ac01bc2SPawel Jakub Dawidek error = g_eli_newsession(wr); 922c58794deSPawel Jakub Dawidek if (error != 0) { 923c58794deSPawel Jakub Dawidek free(wr, M_ELI); 924c58794deSPawel Jakub Dawidek if (req != NULL) { 925c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot set up crypto session " 926c58794deSPawel Jakub Dawidek "for %s (error=%d).", bpp->name, error); 927c58794deSPawel Jakub Dawidek } else { 928c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Cannot set up crypto session " 929c58794deSPawel Jakub Dawidek "for %s (error=%d).", bpp->name, error); 930c58794deSPawel Jakub Dawidek } 931c58794deSPawel Jakub Dawidek goto failed; 932c58794deSPawel Jakub Dawidek } 933c58794deSPawel Jakub Dawidek 9343745c395SJulian Elischer error = kproc_create(g_eli_worker, wr, &wr->w_proc, 0, 0, 935c58794deSPawel Jakub Dawidek "g_eli[%u] %s", i, bpp->name); 936c58794deSPawel Jakub Dawidek if (error != 0) { 9373ac01bc2SPawel Jakub Dawidek g_eli_freesession(wr); 938c58794deSPawel Jakub Dawidek free(wr, M_ELI); 939c58794deSPawel Jakub Dawidek if (req != NULL) { 940dddd1d53SPawel Jakub Dawidek gctl_error(req, "Cannot create kernel thread " 941dddd1d53SPawel Jakub Dawidek "for %s (error=%d).", bpp->name, error); 942c58794deSPawel Jakub Dawidek } else { 943dddd1d53SPawel Jakub Dawidek G_ELI_DEBUG(1, "Cannot create kernel thread " 944dddd1d53SPawel Jakub Dawidek "for %s (error=%d).", bpp->name, error); 945c58794deSPawel Jakub Dawidek } 946c58794deSPawel Jakub Dawidek goto failed; 947c58794deSPawel Jakub Dawidek } 948c58794deSPawel Jakub Dawidek LIST_INSERT_HEAD(&sc->sc_workers, wr, w_next); 949c58794deSPawel Jakub Dawidek } 950c58794deSPawel Jakub Dawidek 951c58794deSPawel Jakub Dawidek /* 952c58794deSPawel Jakub Dawidek * Create decrypted provider. 953c58794deSPawel Jakub Dawidek */ 954c58794deSPawel Jakub Dawidek pp = g_new_providerf(gp, "%s%s", bpp->name, G_ELI_SUFFIX); 955c6a26d4cSPawel Jakub Dawidek pp->mediasize = sc->sc_mediasize; 956c6a26d4cSPawel Jakub Dawidek pp->sectorsize = sc->sc_sectorsize; 957eaa3b919SPawel Jakub Dawidek 958c58794deSPawel Jakub Dawidek g_error_provider(pp, 0); 959c58794deSPawel Jakub Dawidek 960c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Device %s created.", pp->name); 961eaa3b919SPawel Jakub Dawidek G_ELI_DEBUG(0, "Encryption: %s %u", g_eli_algo2str(sc->sc_ealgo), 962eaa3b919SPawel Jakub Dawidek sc->sc_ekeylen); 963eaa3b919SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_AUTH) 964eaa3b919SPawel Jakub Dawidek G_ELI_DEBUG(0, " Integrity: %s", g_eli_algo2str(sc->sc_aalgo)); 965c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, " Crypto: %s", 966c58794deSPawel Jakub Dawidek sc->sc_crypto == G_ELI_CRYPTO_SW ? "software" : "hardware"); 967c58794deSPawel Jakub Dawidek return (gp); 968c58794deSPawel Jakub Dawidek failed: 969c58794deSPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 970c58794deSPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_DESTROY; 971c58794deSPawel Jakub Dawidek wakeup(sc); 972c58794deSPawel Jakub Dawidek /* 973c58794deSPawel Jakub Dawidek * Wait for kernel threads self destruction. 974c58794deSPawel Jakub Dawidek */ 975c58794deSPawel Jakub Dawidek while (!LIST_EMPTY(&sc->sc_workers)) { 976c58794deSPawel Jakub Dawidek msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO, 977c58794deSPawel Jakub Dawidek "geli:destroy", 0); 978c58794deSPawel Jakub Dawidek } 979c58794deSPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 980c58794deSPawel Jakub Dawidek if (cp->provider != NULL) { 981c58794deSPawel Jakub Dawidek if (cp->acr == 1) 982c58794deSPawel Jakub Dawidek g_access(cp, -1, -1, -1); 983c58794deSPawel Jakub Dawidek g_detach(cp); 984c58794deSPawel Jakub Dawidek } 985c58794deSPawel Jakub Dawidek g_destroy_consumer(cp); 986c58794deSPawel Jakub Dawidek g_destroy_geom(gp); 9871e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(sc); 988c58794deSPawel Jakub Dawidek bzero(sc, sizeof(*sc)); 989c58794deSPawel Jakub Dawidek free(sc, M_ELI); 990c58794deSPawel Jakub Dawidek return (NULL); 991c58794deSPawel Jakub Dawidek } 992c58794deSPawel Jakub Dawidek 993c58794deSPawel Jakub Dawidek int 994c58794deSPawel Jakub Dawidek g_eli_destroy(struct g_eli_softc *sc, boolean_t force) 995c58794deSPawel Jakub Dawidek { 996c58794deSPawel Jakub Dawidek struct g_geom *gp; 997c58794deSPawel Jakub Dawidek struct g_provider *pp; 998c58794deSPawel Jakub Dawidek 999c58794deSPawel Jakub Dawidek g_topology_assert(); 1000c58794deSPawel Jakub Dawidek 1001c58794deSPawel Jakub Dawidek if (sc == NULL) 1002c58794deSPawel Jakub Dawidek return (ENXIO); 1003c58794deSPawel Jakub Dawidek 1004c58794deSPawel Jakub Dawidek gp = sc->sc_geom; 1005c58794deSPawel Jakub Dawidek pp = LIST_FIRST(&gp->provider); 1006c58794deSPawel Jakub Dawidek if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 1007c58794deSPawel Jakub Dawidek if (force) { 1008c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Device %s is still open, so it " 100998645006SChristian Brueffer "cannot be definitely removed.", pp->name); 101019351a14SAlexander Motin sc->sc_flags |= G_ELI_FLAG_RW_DETACH; 101119351a14SAlexander Motin gp->access = g_eli_access; 101219351a14SAlexander Motin g_wither_provider(pp, ENXIO); 101319351a14SAlexander Motin return (EBUSY); 1014c58794deSPawel Jakub Dawidek } else { 1015c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, 1016c58794deSPawel Jakub Dawidek "Device %s is still open (r%dw%de%d).", pp->name, 1017c58794deSPawel Jakub Dawidek pp->acr, pp->acw, pp->ace); 1018c58794deSPawel Jakub Dawidek return (EBUSY); 1019c58794deSPawel Jakub Dawidek } 1020c58794deSPawel Jakub Dawidek } 1021c58794deSPawel Jakub Dawidek 1022c58794deSPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 1023c58794deSPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_DESTROY; 1024c58794deSPawel Jakub Dawidek wakeup(sc); 1025c58794deSPawel Jakub Dawidek while (!LIST_EMPTY(&sc->sc_workers)) { 1026c58794deSPawel Jakub Dawidek msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO, 1027c58794deSPawel Jakub Dawidek "geli:destroy", 0); 1028c58794deSPawel Jakub Dawidek } 1029c58794deSPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 1030c58794deSPawel Jakub Dawidek gp->softc = NULL; 10311e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(sc); 1032c58794deSPawel Jakub Dawidek bzero(sc, sizeof(*sc)); 1033c58794deSPawel Jakub Dawidek free(sc, M_ELI); 1034c58794deSPawel Jakub Dawidek 1035c58794deSPawel Jakub Dawidek if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)) 1036c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Device %s destroyed.", gp->name); 1037c58794deSPawel Jakub Dawidek g_wither_geom_close(gp, ENXIO); 1038c58794deSPawel Jakub Dawidek 1039c58794deSPawel Jakub Dawidek return (0); 1040c58794deSPawel Jakub Dawidek } 1041c58794deSPawel Jakub Dawidek 1042c58794deSPawel Jakub Dawidek static int 1043c58794deSPawel Jakub Dawidek g_eli_destroy_geom(struct gctl_req *req __unused, 1044c58794deSPawel Jakub Dawidek struct g_class *mp __unused, struct g_geom *gp) 1045c58794deSPawel Jakub Dawidek { 1046c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 1047c58794deSPawel Jakub Dawidek 1048c58794deSPawel Jakub Dawidek sc = gp->softc; 10495ad4a7c7SPawel Jakub Dawidek return (g_eli_destroy(sc, FALSE)); 1050c58794deSPawel Jakub Dawidek } 1051c58794deSPawel Jakub Dawidek 10529af2131bSPawel Jakub Dawidek static int 10539af2131bSPawel Jakub Dawidek g_eli_keyfiles_load(struct hmac_ctx *ctx, const char *provider) 10549af2131bSPawel Jakub Dawidek { 10551e189c08SMarcel Moolenaar u_char *keyfile, *data; 10569af2131bSPawel Jakub Dawidek char *file, name[64]; 10571e189c08SMarcel Moolenaar size_t size; 10589af2131bSPawel Jakub Dawidek int i; 10599af2131bSPawel Jakub Dawidek 10609af2131bSPawel Jakub Dawidek for (i = 0; ; i++) { 10619af2131bSPawel Jakub Dawidek snprintf(name, sizeof(name), "%s:geli_keyfile%d", provider, i); 10629af2131bSPawel Jakub Dawidek keyfile = preload_search_by_type(name); 1063edaa9008SPawel Jakub Dawidek if (keyfile == NULL && i == 0) { 1064edaa9008SPawel Jakub Dawidek /* 1065edaa9008SPawel Jakub Dawidek * If there is only one keyfile, allow simpler name. 1066edaa9008SPawel Jakub Dawidek */ 1067edaa9008SPawel Jakub Dawidek snprintf(name, sizeof(name), "%s:geli_keyfile", provider); 1068edaa9008SPawel Jakub Dawidek keyfile = preload_search_by_type(name); 1069edaa9008SPawel Jakub Dawidek } 10709af2131bSPawel Jakub Dawidek if (keyfile == NULL) 10719af2131bSPawel Jakub Dawidek return (i); /* Return number of loaded keyfiles. */ 10721e189c08SMarcel Moolenaar data = preload_fetch_addr(keyfile); 10739af2131bSPawel Jakub Dawidek if (data == NULL) { 10749af2131bSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot find key file data for %s.", 10759af2131bSPawel Jakub Dawidek name); 10769af2131bSPawel Jakub Dawidek return (0); 10779af2131bSPawel Jakub Dawidek } 10781e189c08SMarcel Moolenaar size = preload_fetch_size(keyfile); 10791e189c08SMarcel Moolenaar if (size == 0) { 10809af2131bSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot find key file size for %s.", 10819af2131bSPawel Jakub Dawidek name); 10829af2131bSPawel Jakub Dawidek return (0); 10839af2131bSPawel Jakub Dawidek } 10849af2131bSPawel Jakub Dawidek file = preload_search_info(keyfile, MODINFO_NAME); 10859af2131bSPawel Jakub Dawidek if (file == NULL) { 10869af2131bSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot find key file name for %s.", 10879af2131bSPawel Jakub Dawidek name); 10889af2131bSPawel Jakub Dawidek return (0); 10899af2131bSPawel Jakub Dawidek } 10909af2131bSPawel Jakub Dawidek G_ELI_DEBUG(1, "Loaded keyfile %s for %s (type: %s).", file, 10919af2131bSPawel Jakub Dawidek provider, name); 10921e189c08SMarcel Moolenaar g_eli_crypto_hmac_update(ctx, data, size); 10939af2131bSPawel Jakub Dawidek } 10949af2131bSPawel Jakub Dawidek } 10959af2131bSPawel Jakub Dawidek 10969af2131bSPawel Jakub Dawidek static void 10979af2131bSPawel Jakub Dawidek g_eli_keyfiles_clear(const char *provider) 10989af2131bSPawel Jakub Dawidek { 10991e189c08SMarcel Moolenaar u_char *keyfile, *data; 11009af2131bSPawel Jakub Dawidek char name[64]; 11011e189c08SMarcel Moolenaar size_t size; 11029af2131bSPawel Jakub Dawidek int i; 11039af2131bSPawel Jakub Dawidek 11049af2131bSPawel Jakub Dawidek for (i = 0; ; i++) { 11059af2131bSPawel Jakub Dawidek snprintf(name, sizeof(name), "%s:geli_keyfile%d", provider, i); 11069af2131bSPawel Jakub Dawidek keyfile = preload_search_by_type(name); 11079af2131bSPawel Jakub Dawidek if (keyfile == NULL) 11089af2131bSPawel Jakub Dawidek return; 11091e189c08SMarcel Moolenaar data = preload_fetch_addr(keyfile); 11101e189c08SMarcel Moolenaar size = preload_fetch_size(keyfile); 11111e189c08SMarcel Moolenaar if (data != NULL && size != 0) 11121e189c08SMarcel Moolenaar bzero(data, size); 11139af2131bSPawel Jakub Dawidek } 11149af2131bSPawel Jakub Dawidek } 11159af2131bSPawel Jakub Dawidek 1116c58794deSPawel Jakub Dawidek /* 1117c58794deSPawel Jakub Dawidek * Tasting is only made on boot. 1118c58794deSPawel Jakub Dawidek * We detect providers which should be attached before root is mounted. 1119c58794deSPawel Jakub Dawidek */ 1120c58794deSPawel Jakub Dawidek static struct g_geom * 1121c58794deSPawel Jakub Dawidek g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1122c58794deSPawel Jakub Dawidek { 1123c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 1124c58794deSPawel Jakub Dawidek struct g_geom *gp; 1125c58794deSPawel Jakub Dawidek struct hmac_ctx ctx; 1126c58794deSPawel Jakub Dawidek char passphrase[256]; 1127c58794deSPawel Jakub Dawidek u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 11283453dc72SMariusz Zaborski u_int i, nkey, nkeyfiles, tries, showpass; 1129c58794deSPawel Jakub Dawidek int error; 1130ec5c0e5bSAllan Jude struct keybuf *keybuf; 1131c58794deSPawel Jakub Dawidek 1132c58794deSPawel Jakub Dawidek g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 1133c58794deSPawel Jakub Dawidek g_topology_assert(); 1134c58794deSPawel Jakub Dawidek 1135df3aed4fSPawel Jakub Dawidek if (root_mounted() || g_eli_tries == 0) 1136c58794deSPawel Jakub Dawidek return (NULL); 1137c58794deSPawel Jakub Dawidek 1138c58794deSPawel Jakub Dawidek G_ELI_DEBUG(3, "Tasting %s.", pp->name); 1139c58794deSPawel Jakub Dawidek 1140c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 1141c58794deSPawel Jakub Dawidek if (error != 0) 1142c58794deSPawel Jakub Dawidek return (NULL); 1143c58794deSPawel Jakub Dawidek gp = NULL; 1144c58794deSPawel Jakub Dawidek 1145c58794deSPawel Jakub Dawidek if (strcmp(md.md_magic, G_ELI_MAGIC) != 0) 1146c58794deSPawel Jakub Dawidek return (NULL); 1147c58794deSPawel Jakub Dawidek if (md.md_version > G_ELI_VERSION) { 1148c58794deSPawel Jakub Dawidek printf("geom_eli.ko module is too old to handle %s.\n", 1149c58794deSPawel Jakub Dawidek pp->name); 1150c58794deSPawel Jakub Dawidek return (NULL); 1151c58794deSPawel Jakub Dawidek } 1152c58794deSPawel Jakub Dawidek if (md.md_provsize != pp->mediasize) 1153c58794deSPawel Jakub Dawidek return (NULL); 1154c58794deSPawel Jakub Dawidek /* Should we attach it on boot? */ 1155eaa3b919SPawel Jakub Dawidek if (!(md.md_flags & G_ELI_FLAG_BOOT)) 1156c58794deSPawel Jakub Dawidek return (NULL); 1157c58794deSPawel Jakub Dawidek if (md.md_keys == 0x00) { 1158c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "No valid keys on %s.", pp->name); 1159c58794deSPawel Jakub Dawidek return (NULL); 1160c58794deSPawel Jakub Dawidek } 11619af2131bSPawel Jakub Dawidek if (md.md_iterations == -1) { 11629af2131bSPawel Jakub Dawidek /* If there is no passphrase, we try only once. */ 11639af2131bSPawel Jakub Dawidek tries = 1; 11649af2131bSPawel Jakub Dawidek } else { 11659af2131bSPawel Jakub Dawidek /* Ask for the passphrase no more than g_eli_tries times. */ 11669af2131bSPawel Jakub Dawidek tries = g_eli_tries; 11679af2131bSPawel Jakub Dawidek } 11689af2131bSPawel Jakub Dawidek 1169ec5c0e5bSAllan Jude if ((keybuf = get_keybuf()) != NULL) { 1170ec5c0e5bSAllan Jude /* Scan the key buffer, try all GELI keys. */ 1171ec5c0e5bSAllan Jude for (i = 0; i < keybuf->kb_nents; i++) { 1172ec5c0e5bSAllan Jude if (keybuf->kb_ents[i].ke_type == KEYBUF_TYPE_GELI) { 1173ec5c0e5bSAllan Jude memcpy(key, keybuf->kb_ents[i].ke_data, 1174ec5c0e5bSAllan Jude sizeof(key)); 1175ec5c0e5bSAllan Jude 117631f7586dSMariusz Zaborski if (g_eli_mkey_decrypt_any(&md, key, 1177ec5c0e5bSAllan Jude mkey, &nkey) == 0 ) { 1178ec5c0e5bSAllan Jude explicit_bzero(key, sizeof(key)); 1179ec5c0e5bSAllan Jude goto have_key; 1180ec5c0e5bSAllan Jude } 1181ec5c0e5bSAllan Jude } 1182ec5c0e5bSAllan Jude } 1183ec5c0e5bSAllan Jude } 1184ec5c0e5bSAllan Jude 1185835c4dd4SColin Percival for (i = 0; i <= tries; i++) { 11869af2131bSPawel Jakub Dawidek g_eli_crypto_hmac_init(&ctx, NULL, 0); 1187c58794deSPawel Jakub Dawidek 1188c58794deSPawel Jakub Dawidek /* 11899af2131bSPawel Jakub Dawidek * Load all key files. 1190c58794deSPawel Jakub Dawidek */ 11919af2131bSPawel Jakub Dawidek nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name); 11929af2131bSPawel Jakub Dawidek 11939af2131bSPawel Jakub Dawidek if (nkeyfiles == 0 && md.md_iterations == -1) { 11949af2131bSPawel Jakub Dawidek /* 11959af2131bSPawel Jakub Dawidek * No key files and no passphrase, something is 11969af2131bSPawel Jakub Dawidek * definitely wrong here. 11979af2131bSPawel Jakub Dawidek * geli(8) doesn't allow for such situation, so assume 11989af2131bSPawel Jakub Dawidek * that there was really no passphrase and in that case 11999af2131bSPawel Jakub Dawidek * key files are no properly defined in loader.conf. 12009af2131bSPawel Jakub Dawidek */ 12019af2131bSPawel Jakub Dawidek G_ELI_DEBUG(0, 12029af2131bSPawel Jakub Dawidek "Found no key files in loader.conf for %s.", 12039af2131bSPawel Jakub Dawidek pp->name); 12049af2131bSPawel Jakub Dawidek return (NULL); 12059af2131bSPawel Jakub Dawidek } 12069af2131bSPawel Jakub Dawidek 12079af2131bSPawel Jakub Dawidek /* Ask for the passphrase if defined. */ 12089af2131bSPawel Jakub Dawidek if (md.md_iterations >= 0) { 1209835c4dd4SColin Percival /* Try first with cached passphrase. */ 1210835c4dd4SColin Percival if (i == 0) { 1211835c4dd4SColin Percival if (!g_eli_boot_passcache) 1212835c4dd4SColin Percival continue; 1213835c4dd4SColin Percival memcpy(passphrase, cached_passphrase, 1214835c4dd4SColin Percival sizeof(passphrase)); 1215835c4dd4SColin Percival } else { 1216c58794deSPawel Jakub Dawidek printf("Enter passphrase for %s: ", pp->name); 12173453dc72SMariusz Zaborski showpass = g_eli_visible_passphrase; 12183453dc72SMariusz Zaborski if ((md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) != 0) 12193453dc72SMariusz Zaborski showpass = GETS_ECHOPASS; 1220f6ce353eSAndriy Gapon cngets(passphrase, sizeof(passphrase), 12213453dc72SMariusz Zaborski showpass); 1222835c4dd4SColin Percival memcpy(cached_passphrase, passphrase, 1223835c4dd4SColin Percival sizeof(passphrase)); 1224835c4dd4SColin Percival } 12259af2131bSPawel Jakub Dawidek } 12269af2131bSPawel Jakub Dawidek 1227c58794deSPawel Jakub Dawidek /* 1228c58794deSPawel Jakub Dawidek * Prepare Derived-Key from the user passphrase. 1229c58794deSPawel Jakub Dawidek */ 1230c58794deSPawel Jakub Dawidek if (md.md_iterations == 0) { 1231c58794deSPawel Jakub Dawidek g_eli_crypto_hmac_update(&ctx, md.md_salt, 1232c58794deSPawel Jakub Dawidek sizeof(md.md_salt)); 1233c58794deSPawel Jakub Dawidek g_eli_crypto_hmac_update(&ctx, passphrase, 1234c58794deSPawel Jakub Dawidek strlen(passphrase)); 1235ec5c0e5bSAllan Jude explicit_bzero(passphrase, sizeof(passphrase)); 12369af2131bSPawel Jakub Dawidek } else if (md.md_iterations > 0) { 1237c58794deSPawel Jakub Dawidek u_char dkey[G_ELI_USERKEYLEN]; 1238c58794deSPawel Jakub Dawidek 1239c58794deSPawel Jakub Dawidek pkcs5v2_genkey(dkey, sizeof(dkey), md.md_salt, 1240c58794deSPawel Jakub Dawidek sizeof(md.md_salt), passphrase, md.md_iterations); 12415527ecd9SPawel Jakub Dawidek bzero(passphrase, sizeof(passphrase)); 1242c58794deSPawel Jakub Dawidek g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 1243ec5c0e5bSAllan Jude explicit_bzero(dkey, sizeof(dkey)); 1244c58794deSPawel Jakub Dawidek } 12459af2131bSPawel Jakub Dawidek 1246c58794deSPawel Jakub Dawidek g_eli_crypto_hmac_final(&ctx, key, 0); 1247c58794deSPawel Jakub Dawidek 1248c58794deSPawel Jakub Dawidek /* 1249c58794deSPawel Jakub Dawidek * Decrypt Master-Key. 1250c58794deSPawel Jakub Dawidek */ 125131f7586dSMariusz Zaborski error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey); 1252c58794deSPawel Jakub Dawidek bzero(key, sizeof(key)); 1253c58794deSPawel Jakub Dawidek if (error == -1) { 1254835c4dd4SColin Percival if (i == tries) { 12559af2131bSPawel Jakub Dawidek G_ELI_DEBUG(0, 12569af2131bSPawel Jakub Dawidek "Wrong key for %s. No tries left.", 12579af2131bSPawel Jakub Dawidek pp->name); 12589af2131bSPawel Jakub Dawidek g_eli_keyfiles_clear(pp->name); 12599af2131bSPawel Jakub Dawidek return (NULL); 1260c58794deSPawel Jakub Dawidek } 1261835c4dd4SColin Percival if (i > 0) { 1262835c4dd4SColin Percival G_ELI_DEBUG(0, 1263835c4dd4SColin Percival "Wrong key for %s. Tries left: %u.", 1264835c4dd4SColin Percival pp->name, tries - i); 1265835c4dd4SColin Percival } 1266c58794deSPawel Jakub Dawidek /* Try again. */ 1267c58794deSPawel Jakub Dawidek continue; 1268c58794deSPawel Jakub Dawidek } else if (error > 0) { 1269038c55adSPawel Jakub Dawidek G_ELI_DEBUG(0, 1270038c55adSPawel Jakub Dawidek "Cannot decrypt Master Key for %s (error=%d).", 1271c58794deSPawel Jakub Dawidek pp->name, error); 12729af2131bSPawel Jakub Dawidek g_eli_keyfiles_clear(pp->name); 1273c58794deSPawel Jakub Dawidek return (NULL); 1274c58794deSPawel Jakub Dawidek } 1275ebd05adaSBrad Davis g_eli_keyfiles_clear(pp->name); 1276c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); 1277c58794deSPawel Jakub Dawidek break; 1278c58794deSPawel Jakub Dawidek } 1279ec5c0e5bSAllan Jude have_key: 1280c58794deSPawel Jakub Dawidek 1281c58794deSPawel Jakub Dawidek /* 1282c58794deSPawel Jakub Dawidek * We have correct key, let's attach provider. 1283c58794deSPawel Jakub Dawidek */ 1284c58794deSPawel Jakub Dawidek gp = g_eli_create(NULL, mp, pp, &md, mkey, nkey); 1285c58794deSPawel Jakub Dawidek bzero(mkey, sizeof(mkey)); 1286c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 1287c58794deSPawel Jakub Dawidek if (gp == NULL) { 1288c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot create device %s%s.", pp->name, 1289c58794deSPawel Jakub Dawidek G_ELI_SUFFIX); 1290c58794deSPawel Jakub Dawidek return (NULL); 1291c58794deSPawel Jakub Dawidek } 1292c58794deSPawel Jakub Dawidek return (gp); 1293c58794deSPawel Jakub Dawidek } 1294c58794deSPawel Jakub Dawidek 1295c58794deSPawel Jakub Dawidek static void 1296c58794deSPawel Jakub Dawidek g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1297c58794deSPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 1298c58794deSPawel Jakub Dawidek { 1299c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 1300c58794deSPawel Jakub Dawidek 1301c58794deSPawel Jakub Dawidek g_topology_assert(); 1302c58794deSPawel Jakub Dawidek sc = gp->softc; 1303c58794deSPawel Jakub Dawidek if (sc == NULL) 1304c58794deSPawel Jakub Dawidek return; 1305c58794deSPawel Jakub Dawidek if (pp != NULL || cp != NULL) 1306c58794deSPawel Jakub Dawidek return; /* Nothing here. */ 13071e09ff3dSPawel Jakub Dawidek 1308743437c4SAndrey V. Elsukov sbuf_printf(sb, "%s<KeysTotal>%ju</KeysTotal>\n", indent, 13091e09ff3dSPawel Jakub Dawidek (uintmax_t)sc->sc_ekeys_total); 1310743437c4SAndrey V. Elsukov sbuf_printf(sb, "%s<KeysAllocated>%ju</KeysAllocated>\n", indent, 13111e09ff3dSPawel Jakub Dawidek (uintmax_t)sc->sc_ekeys_allocated); 1312ea35a2ecSPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 1313ea35a2ecSPawel Jakub Dawidek if (sc->sc_flags == 0) 1314ea35a2ecSPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 1315ea35a2ecSPawel Jakub Dawidek else { 1316ea35a2ecSPawel Jakub Dawidek int first = 1; 1317ea35a2ecSPawel Jakub Dawidek 1318ea35a2ecSPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 1319eaa3b919SPawel Jakub Dawidek if (sc->sc_flags & (flag)) { \ 1320ea35a2ecSPawel Jakub Dawidek if (!first) \ 1321ea35a2ecSPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 1322ea35a2ecSPawel Jakub Dawidek else \ 1323ea35a2ecSPawel Jakub Dawidek first = 0; \ 1324ea35a2ecSPawel Jakub Dawidek sbuf_printf(sb, name); \ 1325ea35a2ecSPawel Jakub Dawidek } \ 1326ea35a2ecSPawel Jakub Dawidek } while (0) 13275ad4a7c7SPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_SUSPEND, "SUSPEND"); 1328c6a26d4cSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_SINGLE_KEY, "SINGLE-KEY"); 13292bd4ade6SPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_NATIVE_BYTE_ORDER, "NATIVE-BYTE-ORDER"); 1330ea35a2ecSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_ONETIME, "ONETIME"); 1331ea35a2ecSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_BOOT, "BOOT"); 1332ea35a2ecSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_WO_DETACH, "W-DETACH"); 1333ea35a2ecSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_RW_DETACH, "RW-DETACH"); 1334eaa3b919SPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_AUTH, "AUTH"); 1335ea35a2ecSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_WOPEN, "W-OPEN"); 1336ea35a2ecSPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_DESTROY, "DESTROY"); 133785059016SPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY"); 133846e34470SPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_NODELETE, "NODELETE"); 1339d8736625SAllan Jude ADD_FLAG(G_ELI_FLAG_GELIBOOT, "GELIBOOT"); 13403453dc72SMariusz Zaborski ADD_FLAG(G_ELI_FLAG_GELIDISPLAYPASS, "GELIDISPLAYPASS"); 1341*2f07cdf8SPawel Jakub Dawidek ADD_FLAG(G_ELI_FLAG_AUTORESIZE, "AUTORESIZE"); 1342ea35a2ecSPawel Jakub Dawidek #undef ADD_FLAG 1343ea35a2ecSPawel Jakub Dawidek } 1344ea35a2ecSPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 1345ea35a2ecSPawel Jakub Dawidek 1346eaa3b919SPawel Jakub Dawidek if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) { 1347ea35a2ecSPawel Jakub Dawidek sbuf_printf(sb, "%s<UsedKey>%u</UsedKey>\n", indent, 1348ea35a2ecSPawel Jakub Dawidek sc->sc_nkey); 1349ea35a2ecSPawel Jakub Dawidek } 13501f8c92e6SPawel Jakub Dawidek sbuf_printf(sb, "%s<Version>%u</Version>\n", indent, sc->sc_version); 1351c58794deSPawel Jakub Dawidek sbuf_printf(sb, "%s<Crypto>", indent); 1352c58794deSPawel Jakub Dawidek switch (sc->sc_crypto) { 1353c58794deSPawel Jakub Dawidek case G_ELI_CRYPTO_HW: 1354c58794deSPawel Jakub Dawidek sbuf_printf(sb, "hardware"); 1355c58794deSPawel Jakub Dawidek break; 1356c58794deSPawel Jakub Dawidek case G_ELI_CRYPTO_SW: 1357c58794deSPawel Jakub Dawidek sbuf_printf(sb, "software"); 1358c58794deSPawel Jakub Dawidek break; 1359c58794deSPawel Jakub Dawidek default: 1360c58794deSPawel Jakub Dawidek sbuf_printf(sb, "UNKNOWN"); 1361c58794deSPawel Jakub Dawidek break; 1362c58794deSPawel Jakub Dawidek } 1363c58794deSPawel Jakub Dawidek sbuf_printf(sb, "</Crypto>\n"); 1364eaa3b919SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_AUTH) { 1365eaa3b919SPawel Jakub Dawidek sbuf_printf(sb, 1366eaa3b919SPawel Jakub Dawidek "%s<AuthenticationAlgorithm>%s</AuthenticationAlgorithm>\n", 1367eaa3b919SPawel Jakub Dawidek indent, g_eli_algo2str(sc->sc_aalgo)); 1368eaa3b919SPawel Jakub Dawidek } 1369eaa3b919SPawel Jakub Dawidek sbuf_printf(sb, "%s<KeyLength>%u</KeyLength>\n", indent, 1370eaa3b919SPawel Jakub Dawidek sc->sc_ekeylen); 1371038c55adSPawel Jakub Dawidek sbuf_printf(sb, "%s<EncryptionAlgorithm>%s</EncryptionAlgorithm>\n", 1372038c55adSPawel Jakub Dawidek indent, g_eli_algo2str(sc->sc_ealgo)); 1373d8d61ef8SPawel Jakub Dawidek sbuf_printf(sb, "%s<State>%s</State>\n", indent, 1374d8d61ef8SPawel Jakub Dawidek (sc->sc_flags & G_ELI_FLAG_SUSPEND) ? "SUSPENDED" : "ACTIVE"); 1375c58794deSPawel Jakub Dawidek } 1376c58794deSPawel Jakub Dawidek 1377c5d387d0SPawel Jakub Dawidek static void 1378c5d387d0SPawel Jakub Dawidek g_eli_shutdown_pre_sync(void *arg, int howto) 1379c5d387d0SPawel Jakub Dawidek { 1380c5d387d0SPawel Jakub Dawidek struct g_class *mp; 1381c5d387d0SPawel Jakub Dawidek struct g_geom *gp, *gp2; 1382c5d387d0SPawel Jakub Dawidek struct g_provider *pp; 1383c5d387d0SPawel Jakub Dawidek struct g_eli_softc *sc; 1384c5d387d0SPawel Jakub Dawidek int error; 1385c5d387d0SPawel Jakub Dawidek 1386c5d387d0SPawel Jakub Dawidek mp = arg; 1387c5d387d0SPawel Jakub Dawidek g_topology_lock(); 1388c5d387d0SPawel Jakub Dawidek LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 1389c5d387d0SPawel Jakub Dawidek sc = gp->softc; 1390c5d387d0SPawel Jakub Dawidek if (sc == NULL) 1391c5d387d0SPawel Jakub Dawidek continue; 1392c5d387d0SPawel Jakub Dawidek pp = LIST_FIRST(&gp->provider); 1393c5d387d0SPawel Jakub Dawidek KASSERT(pp != NULL, ("No provider? gp=%p (%s)", gp, gp->name)); 1394c5d387d0SPawel Jakub Dawidek if (pp->acr + pp->acw + pp->ace == 0) 13955ad4a7c7SPawel Jakub Dawidek error = g_eli_destroy(sc, TRUE); 1396c5d387d0SPawel Jakub Dawidek else { 1397c5d387d0SPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_RW_DETACH; 1398c5d387d0SPawel Jakub Dawidek gp->access = g_eli_access; 1399c5d387d0SPawel Jakub Dawidek } 1400c5d387d0SPawel Jakub Dawidek } 1401c5d387d0SPawel Jakub Dawidek g_topology_unlock(); 1402c5d387d0SPawel Jakub Dawidek } 1403c5d387d0SPawel Jakub Dawidek 1404c5d387d0SPawel Jakub Dawidek static void 1405c5d387d0SPawel Jakub Dawidek g_eli_init(struct g_class *mp) 1406c5d387d0SPawel Jakub Dawidek { 1407c5d387d0SPawel Jakub Dawidek 1408c5d387d0SPawel Jakub Dawidek g_eli_pre_sync = EVENTHANDLER_REGISTER(shutdown_pre_sync, 1409c5d387d0SPawel Jakub Dawidek g_eli_shutdown_pre_sync, mp, SHUTDOWN_PRI_FIRST); 1410c5d387d0SPawel Jakub Dawidek if (g_eli_pre_sync == NULL) 1411c5d387d0SPawel Jakub Dawidek G_ELI_DEBUG(0, "Warning! Cannot register shutdown event."); 1412c5d387d0SPawel Jakub Dawidek } 1413c5d387d0SPawel Jakub Dawidek 1414c5d387d0SPawel Jakub Dawidek static void 1415c5d387d0SPawel Jakub Dawidek g_eli_fini(struct g_class *mp) 1416c5d387d0SPawel Jakub Dawidek { 1417c5d387d0SPawel Jakub Dawidek 1418c5d387d0SPawel Jakub Dawidek if (g_eli_pre_sync != NULL) 1419c5d387d0SPawel Jakub Dawidek EVENTHANDLER_DEREGISTER(shutdown_pre_sync, g_eli_pre_sync); 1420c5d387d0SPawel Jakub Dawidek } 1421c5d387d0SPawel Jakub Dawidek 1422c58794deSPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_eli_class, g_eli); 1423f6829a05SYaroslav Tykhiy MODULE_DEPEND(g_eli, crypto, 1, 1, 1); 142474d6c131SKyle Evans MODULE_VERSION(geom_eli, 0); 1425