Implement automatic online expansion of GELI providers - if the underlying
provider grows, GELI will expand automatically and will move the metadata to the new location of the last sector. This functionality is turned on by default. It can be turned off with the -R flag, but it is not recommended - if the underlying provider grows and automatic expansion is turned off, it won't be possible to attach this provider again, as the metadata is no longer located in the last sector. If the automatic expansion is turned off and the underlying provider grows, GELI will only log a message with the previous size of the provider, so recovery can be easier. Obtained from: Fudo Security
This commit is contained in:
parent
b4f850c006
commit
2f07cdf871
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345862
@ -1,4 +1,4 @@
|
||||
.\" Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
.\" Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
.\" 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
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* Copyright (c) 2004-2019 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* 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, "</Flags>\n");
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* 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
|
||||
|
@ -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;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* Copyright (c) 2011-2019 Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||
* 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
|
||||
|
Loading…
Reference in New Issue
Block a user