svn commit: r345862 - in head: lib/geom/eli sys/geom/eli

Pawel Jakub Dawidek pjd at FreeBSD.org
Wed Apr 3 23:57:39 UTC 2019


Author: pjd
Date: Wed Apr  3 23:57:37 2019
New Revision: 345862
URL: https://svnweb.freebsd.org/changeset/base/345862

Log:
  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

Modified:
  head/lib/geom/eli/geli.8
  head/lib/geom/eli/geom_eli.c
  head/sys/geom/eli/g_eli.c
  head/sys/geom/eli/g_eli.h
  head/sys/geom/eli/g_eli_ctl.c
  head/sys/geom/eli/g_eli_key_cache.c

Modified: head/lib/geom/eli/geli.8
==============================================================================
--- head/lib/geom/eli/geli.8	Wed Apr  3 23:50:52 2019	(r345861)
+++ head/lib/geom/eli/geli.8	Wed Apr  3 23:57:37 2019	(r345862)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel at dawidek.net>
+.\" Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel at 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

Modified: head/lib/geom/eli/geom_eli.c
==============================================================================
--- head/lib/geom/eli/geom_eli.c	Wed Apr  3 23:50:52 2019	(r345861)
+++ head/lib/geom/eli/geom_eli.c	Wed Apr  3 23:57:37 2019	(r345862)
@@ -1,7 +1,7 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
- * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+ * Copyright (c) 2004-2019 Pawel Jakub Dawidek <pawel at 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, con
 /*
  * 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 @@ out:
 
 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 cha
 		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);
 		}
 	}
 }

Modified: head/sys/geom/eli/g_eli.c
==============================================================================
--- head/sys/geom/eli/g_eli.c	Wed Apr  3 23:50:52 2019	(r345861)
+++ head/sys/geom/eli/g_eli.c	Wed Apr  3 23:57:37 2019	(r345862)
@@ -1,7 +1,7 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
- * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel at dawidek.net>
+ * Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel at 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, 
 
 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 @@ again:
 	}
 }
 
-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_provi
 	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 @@ end:
 	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,
 	 */
 	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, st
 		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");

Modified: head/sys/geom/eli/g_eli.h
==============================================================================
--- head/sys/geom/eli/g_eli.h	Wed Apr  3 23:50:52 2019	(r345861)
+++ head/sys/geom/eli/g_eli.h	Wed Apr  3 23:57:37 2019	(r345862)
@@ -1,7 +1,7 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
- * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel at dawidek.net>
+ * Copyright (c) 2005-2019 Pawel Jakub Dawidek <pawel at 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 struc
 		    (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_e
 #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

Modified: head/sys/geom/eli/g_eli_ctl.c
==============================================================================
--- head/sys/geom/eli/g_eli_ctl.c	Wed Apr  3 23:50:52 2019	(r345861)
+++ head/sys/geom/eli/g_eli_ctl.c	Wed Apr  3 23:57:37 2019	(r345862)
@@ -264,7 +264,7 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class
 	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
 	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_cla
 	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_cla
 	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_cla
 			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
@@ -594,6 +624,14 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_cla
 		} else if (*nodisplaypass) {
 			md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
 			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) {

Modified: head/sys/geom/eli/g_eli_key_cache.c
==============================================================================
--- head/sys/geom/eli/g_eli_key_cache.c	Wed Apr  3 23:50:52 2019	(r345861)
+++ head/sys/geom/eli/g_eli_key_cache.c	Wed Apr  3 23:57:37 2019	(r345862)
@@ -1,7 +1,7 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
- * Copyright (c) 2011 Pawel Jakub Dawidek <pawel at dawidek.net>
+ * Copyright (c) 2011-2019 Pawel Jakub Dawidek <pawel at dawidek.net>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -249,6 +249,52 @@ g_eli_key_destroy(struct g_eli_softc *sc)
 		TAILQ_INIT(&sc->sc_ekeys_queue);
 		RB_INIT(&sc->sc_ekeys_tree);
 	}
+	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);
 }
 


More information about the svn-src-head mailing list