diff --git a/lib/geom/eli/geli.8 b/lib/geom/eli/geli.8 index cdbb1586f0f..876f4668786 100644 --- a/lib/geom/eli/geli.8 +++ b/lib/geom/eli/geli.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2005-2011 Pawel Jakub Dawidek +.\" Copyright (c) 2005-2019 Pawel Jakub Dawidek .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 24, 2018 +.Dd April 3, 2019 .Dt GELI 8 .Os .Sh NAME @@ -51,7 +51,7 @@ utility: .Pp .Nm .Cm init -.Op Fl bdgPTv +.Op Fl bdgPRTv .Op Fl a Ar aalgo .Op Fl B Ar backupfile .Op Fl e Ar ealgo @@ -81,7 +81,7 @@ utility: .Cm detach .Nm .Cm onetime -.Op Fl dT +.Op Fl dRT .Op Fl a Ar aalgo .Op Fl e Ar ealgo .Op Fl l Ar keylen @@ -89,7 +89,7 @@ utility: .Ar prov .Nm .Cm configure -.Op Fl bBdDgGtT +.Op Fl bBdDgGrRtT .Ar prov ... .Nm .Cm setkey @@ -375,6 +375,18 @@ Change decrypted provider's sector size. Increasing the sector size allows increased performance, because encryption/decryption which requires an initialization vector is done per sector; fewer sectors means less computational work. +.It Fl R +Turn off automatic expansion. +By default, if the underlying provider grows, the encrypted provider will +grow automatically too. +The metadata will be moved to the new location. +If automatic expansion if turned off and the underlying provider changes +size, attaching encrypted provider will no longer be possible as the metadata +will no longer be located in the last sector. +In this case +.Nm GELI +will only log the previous size of the underlying provider, so metadata can +be found easier, if resize was done by mistake. .It Fl T Don't pass through .Dv BIO_DELETE @@ -506,6 +518,11 @@ Change decrypted provider's sector size. For more information, see the description of the .Cm init subcommand. +.It Fl R +Turn off automatic expansion. +For more information, see the description of the +.Cm init +subcommand. .It Fl T Disable TRIM/UNMAP passthru. For more information, see the description of the @@ -540,6 +557,13 @@ The boot loader prompts for the passphrase and loads from the encrypted partition. .It Fl G Deactivate booting from this encrypted root partition. +.It Fl r +Turn on automatic expansion. +For more information, see the description of the +.Cm init +subcommand. +.It Fl R +Turn off automatic expansion. .It Fl t Enable TRIM/UNMAP passthru. For more information, see the description of the diff --git a/lib/geom/eli/geom_eli.c b/lib/geom/eli/geom_eli.c index 2da4b56c2ed..2b08bf14a18 100644 --- a/lib/geom/eli/geom_eli.c +++ b/lib/geom/eli/geom_eli.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2004-2010 Pawel Jakub Dawidek + * Copyright (c) 2004-2019 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,13 +91,13 @@ static int eli_backup_create(struct gctl_req *req, const char *prov, /* * Available commands: * - * init [-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov ... + * init [-bdgPRTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov ... * label - alias for 'init' * attach [-Cdprv] [-n keyno] [-j passfile] [-k keyfile] prov ... * detach [-fl] prov ... * stop - alias for 'detach' - * onetime [-dT] [-a aalgo] [-e ealgo] [-l keylen] prov - * configure [-bBgGtT] prov ... + * onetime [-dRT] [-a aalgo] [-e ealgo] [-l keylen] prov + * configure [-bBgGrRtT] prov ... * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov * delkey [-afv] [-n keyno] prov * suspend [-v] -a | prov ... @@ -124,12 +124,13 @@ struct g_command class_commands[] = { { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, { 'l', "keylen", "0", G_TYPE_NUMBER }, { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, + { 'R', "noautoresize", NULL, G_TYPE_BOOL }, { 's', "sectorsize", "0", G_TYPE_NUMBER }, { 'T', "notrim", NULL, G_TYPE_BOOL }, { 'V', "mdversion", "-1", G_TYPE_NUMBER }, G_OPT_SENTINEL }, - "[-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov ..." + "[-bdgPRTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov ..." }, { "label", G_FLAG_VERBOSE, eli_main, { @@ -144,6 +145,7 @@ struct g_command class_commands[] = { { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, { 'l', "keylen", "0", G_TYPE_NUMBER }, { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, + { 'R', "noautoresize", NULL, G_TYPE_BOOL }, { 's', "sectorsize", "0", G_TYPE_NUMBER }, { 'T', "notrim", NULL, G_TYPE_BOOL }, { 'V', "mdversion", "-1", G_TYPE_NUMBER }, @@ -186,11 +188,12 @@ struct g_command class_commands[] = { { 'd', "detach", NULL, G_TYPE_BOOL }, { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, { 'l', "keylen", "0", G_TYPE_NUMBER }, + { 'R', "noautoresize", NULL, G_TYPE_BOOL }, { 's', "sectorsize", "0", G_TYPE_NUMBER }, { 'T', "notrim", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - "[-dT] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov" + "[-dRT] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov" }, { "configure", G_FLAG_VERBOSE, eli_main, { @@ -200,11 +203,13 @@ struct g_command class_commands[] = { { 'D', "nodisplaypass", NULL, G_TYPE_BOOL }, { 'g', "geliboot", NULL, G_TYPE_BOOL }, { 'G', "nogeliboot", NULL, G_TYPE_BOOL }, + { 'r', "autoresize", NULL, G_TYPE_BOOL }, + { 'R', "noautoresize", NULL, G_TYPE_BOOL }, { 't', "trim", NULL, G_TYPE_BOOL }, { 'T', "notrim", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - "[-bBdDgGtT] prov ..." + "[-bBdDgGrRtT] prov ..." }, { "setkey", G_FLAG_VERBOSE, eli_main, { @@ -728,7 +733,7 @@ eli_init(struct gctl_req *req) version = val; } md.md_version = version; - md.md_flags = 0; + md.md_flags = G_ELI_FLAG_AUTORESIZE; if (gctl_get_int(req, "boot")) md.md_flags |= G_ELI_FLAG_BOOT; if (gctl_get_int(req, "geliboot")) @@ -737,6 +742,8 @@ eli_init(struct gctl_req *req) md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS; if (gctl_get_int(req, "notrim")) md.md_flags |= G_ELI_FLAG_NODELETE; + if (gctl_get_int(req, "noautoresize")) + md.md_flags &= ~G_ELI_FLAG_AUTORESIZE; md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; str = gctl_get_ascii(req, "aalgo"); if (*str != '\0') { @@ -1095,7 +1102,7 @@ eli_attach(struct gctl_req *req) static void eli_configure_detached(struct gctl_req *req, const char *prov, int boot, - int geliboot, int displaypass, int trim) + int geliboot, int displaypass, int trim, int autoresize) { struct g_eli_metadata md; bool changed = 0; @@ -1160,6 +1167,20 @@ eli_configure_detached(struct gctl_req *req, const char *prov, int boot, changed = 1; } + if (autoresize == 1 && (md.md_flags & G_ELI_FLAG_AUTORESIZE)) { + if (verbose) + printf("AUTORESIZE flag already configured for %s.\n", prov); + } else if (autoresize == 0 && !(md.md_flags & G_ELI_FLAG_AUTORESIZE)) { + if (verbose) + printf("AUTORESIZE flag not configured for %s.\n", prov); + } else if (autoresize >= 0) { + if (autoresize) + md.md_flags |= G_ELI_FLAG_AUTORESIZE; + else + md.md_flags &= ~G_ELI_FLAG_AUTORESIZE; + changed = 1; + } + if (changed) eli_metadata_store(req, prov, &md); explicit_bzero(&md, sizeof(md)); @@ -1170,8 +1191,8 @@ eli_configure(struct gctl_req *req) { const char *prov; bool boot, noboot, geliboot, nogeliboot, displaypass, nodisplaypass; - bool trim, notrim; - int doboot, dogeliboot, dodisplaypass, dotrim; + bool autoresize, noautoresize, trim, notrim; + int doboot, dogeliboot, dodisplaypass, dotrim, doautoresize; int i, nargs; nargs = gctl_get_int(req, "nargs"); @@ -1188,6 +1209,8 @@ eli_configure(struct gctl_req *req) nodisplaypass = gctl_get_int(req, "nodisplaypass"); trim = gctl_get_int(req, "trim"); notrim = gctl_get_int(req, "notrim"); + autoresize = gctl_get_int(req, "autoresize"); + noautoresize = gctl_get_int(req, "noautoresize"); doboot = -1; if (boot && noboot) { @@ -1229,8 +1252,18 @@ eli_configure(struct gctl_req *req) else if (notrim) dotrim = 0; + doautoresize = -1; + if (autoresize && noautoresize) { + gctl_error(req, "Options -r and -R are mutually exclusive."); + return; + } + if (autoresize) + doautoresize = 1; + else if (noautoresize) + doautoresize = 0; + if (doboot == -1 && dogeliboot == -1 && dodisplaypass == -1 && - dotrim == -1) { + dotrim == -1 && doautoresize == -1) { gctl_error(req, "No option given."); return; } @@ -1242,7 +1275,7 @@ eli_configure(struct gctl_req *req) prov = gctl_get_ascii(req, "arg%d", i); if (!eli_is_attached(prov)) { eli_configure_detached(req, prov, doboot, dogeliboot, - dodisplaypass, dotrim); + dodisplaypass, dotrim, doautoresize); } } } diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index 6df1fdc2d24..04d05e464c5 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005-2011 Pawel Jakub Dawidek + * Copyright (c) 2005-2019 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -151,6 +151,9 @@ EVENTHANDLER_DEFINE(mountroot, zero_intake_passcache, NULL, 0); static eventhandler_tag g_eli_pre_sync = NULL; +static int g_eli_read_metadata_offset(struct g_class *mp, struct g_provider *pp, + off_t offset, struct g_eli_metadata *md); + static int g_eli_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp); static void g_eli_init(struct g_class *mp); @@ -327,6 +330,79 @@ g_eli_orphan(struct g_consumer *cp) g_eli_destroy(sc, TRUE); } +static void +g_eli_resize(struct g_consumer *cp) +{ + struct g_eli_softc *sc; + struct g_provider *epp, *pp; + off_t oldsize; + + g_topology_assert(); + sc = cp->geom->softc; + if (sc == NULL) + return; + + if ((sc->sc_flags & G_ELI_FLAG_AUTORESIZE) == 0) { + G_ELI_DEBUG(0, "Autoresize is turned off, old size: %jd.", + (intmax_t)sc->sc_provsize); + return; + } + + pp = cp->provider; + + if ((sc->sc_flags & G_ELI_FLAG_ONETIME) == 0) { + struct g_eli_metadata md; + u_char *sector; + int error; + + sector = NULL; + + error = g_eli_read_metadata_offset(cp->geom->class, pp, + sc->sc_provsize - pp->sectorsize, &md); + if (error != 0) { + G_ELI_DEBUG(0, "Cannot read metadata from %s (error=%d).", + pp->name, error); + goto iofail; + } + + md.md_provsize = pp->mediasize; + + sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); + eli_metadata_encode(&md, sector); + error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, + pp->sectorsize); + if (error != 0) { + G_ELI_DEBUG(0, "Cannot store metadata on %s (error=%d).", + pp->name, error); + goto iofail; + } + explicit_bzero(sector, pp->sectorsize); + error = g_write_data(cp, sc->sc_provsize - pp->sectorsize, + sector, pp->sectorsize); + if (error != 0) { + G_ELI_DEBUG(0, "Cannot clear old metadata from %s (error=%d).", + pp->name, error); + goto iofail; + } +iofail: + explicit_bzero(&md, sizeof(md)); + if (sector != NULL) { + explicit_bzero(sector, pp->sectorsize); + free(sector, M_ELI); + } + } + + oldsize = sc->sc_mediasize; + sc->sc_mediasize = eli_mediasize(sc, pp->mediasize, pp->sectorsize); + g_eli_key_resize(sc); + sc->sc_provsize = pp->mediasize; + + epp = LIST_FIRST(&sc->sc_geom->provider); + g_resize_provider(epp, sc->sc_mediasize); + G_ELI_DEBUG(0, "Device %s size changed from %jd to %jd.", epp->name, + (intmax_t)oldsize, (intmax_t)sc->sc_mediasize); +} + /* * BIO_READ: * 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 @@ -620,9 +696,9 @@ g_eli_worker(void *arg) } } -int -g_eli_read_metadata(struct g_class *mp, struct g_provider *pp, - struct g_eli_metadata *md) +static int +g_eli_read_metadata_offset(struct g_class *mp, struct g_provider *pp, + off_t offset, struct g_eli_metadata *md) { struct g_geom *gp; struct g_consumer *cp; @@ -649,8 +725,7 @@ g_eli_read_metadata(struct g_class *mp, struct g_provider *pp, if (error != 0) goto end; g_topology_unlock(); - buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, - &error); + buf = g_read_data(cp, offset, pp->sectorsize, &error); g_topology_lock(); if (buf == NULL) goto end; @@ -671,6 +746,15 @@ g_eli_read_metadata(struct g_class *mp, struct g_provider *pp, return (error); } +int +g_eli_read_metadata(struct g_class *mp, struct g_provider *pp, + struct g_eli_metadata *md) +{ + + return (g_eli_read_metadata_offset(mp, pp, + pp->mediasize - pp->sectorsize, md)); +} + /* * The function is called when we had last close on provider and user requested * to close it when this situation occur. @@ -756,6 +840,7 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, */ gp->spoiled = g_eli_orphan; gp->orphan = g_eli_orphan; + gp->resize = g_eli_resize; gp->dumpconf = g_eli_dumpconf; /* * If detach-on-last-close feature is not enabled and we don't operate @@ -1253,6 +1338,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, ADD_FLAG(G_ELI_FLAG_NODELETE, "NODELETE"); ADD_FLAG(G_ELI_FLAG_GELIBOOT, "GELIBOOT"); ADD_FLAG(G_ELI_FLAG_GELIDISPLAYPASS, "GELIDISPLAYPASS"); + ADD_FLAG(G_ELI_FLAG_AUTORESIZE, "AUTORESIZE"); #undef ADD_FLAG } sbuf_printf(sb, "\n"); diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h index 5141081710a..36ab0b87649 100644 --- a/sys/geom/eli/g_eli.h +++ b/sys/geom/eli/g_eli.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005-2011 Pawel Jakub Dawidek + * Copyright (c) 2005-2019 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -104,6 +104,9 @@ #define G_ELI_FLAG_GELIBOOT 0x00000080 /* Hide passphrase length in GELIboot. */ #define G_ELI_FLAG_GELIDISPLAYPASS 0x00000100 +/* Expand provider automatically. */ +#define G_ELI_FLAG_AUTORESIZE 0x00000200 + /* RUNTIME FLAGS. */ /* Provider was open for writing. */ #define G_ELI_FLAG_WOPEN 0x00010000 @@ -211,6 +214,7 @@ struct g_eli_softc { int sc_inflight; off_t sc_mediasize; size_t sc_sectorsize; + off_t sc_provsize; u_int sc_bytes_per_sector; u_int sc_data_per_sector; #ifndef _KERNEL @@ -608,6 +612,23 @@ g_eli_hashlen(u_int algo) return (0); } +static __inline off_t +eli_mediasize(const struct g_eli_softc *sc, off_t mediasize, u_int sectorsize) +{ + + if ((sc->sc_flags & G_ELI_FLAG_ONETIME) == 0) { + mediasize -= sectorsize; + } + if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0) { + mediasize -= (mediasize % sc->sc_sectorsize); + } else { + mediasize /= sc->sc_bytes_per_sector; + mediasize *= sc->sc_sectorsize; + } + + return (mediasize); +} + static __inline void eli_metadata_softc(struct g_eli_softc *sc, const struct g_eli_metadata *md, u_int sectorsize, off_t mediasize) @@ -649,16 +670,9 @@ eli_metadata_softc(struct g_eli_softc *sc, const struct g_eli_metadata *md, (md->md_sectorsize - 1) / sc->sc_data_per_sector + 1; sc->sc_bytes_per_sector *= sectorsize; } + sc->sc_provsize = mediasize; sc->sc_sectorsize = md->md_sectorsize; - sc->sc_mediasize = mediasize; - if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) - sc->sc_mediasize -= sectorsize; - if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) - sc->sc_mediasize -= (sc->sc_mediasize % sc->sc_sectorsize); - else { - sc->sc_mediasize /= sc->sc_bytes_per_sector; - sc->sc_mediasize *= sc->sc_sectorsize; - } + sc->sc_mediasize = eli_mediasize(sc, mediasize, sectorsize); sc->sc_ekeylen = md->md_keylen; } @@ -720,6 +734,7 @@ void g_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, #ifdef _KERNEL void g_eli_key_init(struct g_eli_softc *sc); void g_eli_key_destroy(struct g_eli_softc *sc); +void g_eli_key_resize(struct g_eli_softc *sc); uint8_t *g_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize); void g_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey); #endif diff --git a/sys/geom/eli/g_eli_ctl.c b/sys/geom/eli/g_eli_ctl.c index 1c56b79c36a..b62ff5376f7 100644 --- a/sys/geom/eli/g_eli_ctl.c +++ b/sys/geom/eli/g_eli_ctl.c @@ -264,7 +264,7 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) const char *name; intmax_t *keylen, *sectorsize; u_char mkey[G_ELI_DATAIVKEYLEN]; - int *nargs, *detach, *notrim; + int *nargs, *detach, *noautoresize, *notrim; g_topology_assert(); bzero(&md, sizeof(md)); @@ -282,10 +282,15 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); md.md_version = G_ELI_VERSION; md.md_flags |= G_ELI_FLAG_ONETIME; + md.md_flags |= G_ELI_FLAG_AUTORESIZE; detach = gctl_get_paraml(req, "detach", sizeof(*detach)); if (detach != NULL && *detach) md.md_flags |= G_ELI_FLAG_WO_DETACH; + noautoresize = gctl_get_paraml(req, "noautoresize", + sizeof(*noautoresize)); + if (noautoresize != NULL && *noautoresize) + md.md_flags &= ~G_ELI_FLAG_AUTORESIZE; notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim)); if (notrim != NULL && *notrim) md.md_flags |= G_ELI_FLAG_NODELETE; @@ -405,7 +410,7 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) const char *prov; u_char *sector; int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot; - int *displaypass, *nodisplaypass; + int *displaypass, *nodisplaypass, *autoresize, *noautoresize; int zero, error, changed; u_int i; @@ -476,6 +481,20 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) if (*displaypass || *nodisplaypass) changed = 1; + autoresize = gctl_get_paraml(req, "autoresize", sizeof(*autoresize)); + if (autoresize == NULL) + autoresize = &zero; + noautoresize = gctl_get_paraml(req, "noautoresize", + sizeof(*noautoresize)); + if (noautoresize == NULL) + noautoresize = &zero; + if (*autoresize && *noautoresize) { + gctl_error(req, "Options -r and -R are mutually exclusive."); + return; + } + if (*autoresize || *noautoresize) + changed = 1; + if (!changed) { gctl_error(req, "No option given."); return; @@ -545,6 +564,17 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) continue; } + if (*autoresize && (sc->sc_flags & G_ELI_FLAG_AUTORESIZE)) { + G_ELI_DEBUG(1, "AUTORESIZE flag already configured for %s.", + prov); + continue; + } else if (*noautoresize && + !(sc->sc_flags & G_ELI_FLAG_AUTORESIZE)) { + G_ELI_DEBUG(1, "AUTORESIZE flag not configured for %s.", + prov); + continue; + } + if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) { /* * ONETIME providers don't write metadata to @@ -596,6 +626,14 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) sc->sc_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS; } + if (*autoresize) { + md.md_flags |= G_ELI_FLAG_AUTORESIZE; + sc->sc_flags |= G_ELI_FLAG_AUTORESIZE; + } else if (*noautoresize) { + md.md_flags &= ~G_ELI_FLAG_AUTORESIZE; + sc->sc_flags &= ~G_ELI_FLAG_AUTORESIZE; + } + if (sc->sc_flags & G_ELI_FLAG_ONETIME) { /* There's no metadata on disk so we are done here. */ continue; diff --git a/sys/geom/eli/g_eli_key_cache.c b/sys/geom/eli/g_eli_key_cache.c index 431c90f5d9f..db1b1a950a1 100644 --- a/sys/geom/eli/g_eli_key_cache.c +++ b/sys/geom/eli/g_eli_key_cache.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2011 Pawel Jakub Dawidek + * Copyright (c) 2011-2019 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -252,6 +252,52 @@ g_eli_key_destroy(struct g_eli_softc *sc) mtx_unlock(&sc->sc_ekeys_lock); } +void +g_eli_key_resize(struct g_eli_softc *sc) +{ + uint64_t new_ekeys_total; + off_t mediasize; + size_t blocksize; + + if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { + return; + } + + mtx_lock(&sc->sc_ekeys_lock); + + if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) { + struct g_provider *pp; + + pp = LIST_FIRST(&sc->sc_geom->consumer)->provider; + mediasize = pp->mediasize; + blocksize = pp->sectorsize; + } else { + mediasize = sc->sc_mediasize; + blocksize = sc->sc_sectorsize; + } + new_ekeys_total = ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1; + /* We only allow to grow. */ + KASSERT(new_ekeys_total >= sc->sc_ekeys_total, + ("new_ekeys_total=%ju < sc_ekeys_total=%ju", + (uintmax_t)new_ekeys_total, (uintmax_t)sc->sc_ekeys_total)); + if (new_ekeys_total <= g_eli_key_cache_limit) { + uint64_t keyno; + + for (keyno = sc->sc_ekeys_total; keyno < new_ekeys_total; + keyno++) { + (void)g_eli_key_allocate(sc, keyno); + } + KASSERT(new_ekeys_total == sc->sc_ekeys_allocated, + ("new_ekeys_total=%ju != sc_ekeys_allocated=%ju", + (uintmax_t)new_ekeys_total, + (uintmax_t)sc->sc_ekeys_allocated)); + } + + sc->sc_ekeys_total = new_ekeys_total; + + mtx_unlock(&sc->sc_ekeys_lock); +} + /* * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one * key available for all the data. If the flag is not present select the key