Bug 178359 - [geom] [patch] geom_eli: support external metadata
Summary: [geom] [patch] geom_eli: support external metadata
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 9.1-STABLE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-05-06 00:10 UTC by Andrew Romanenko
Modified: 2018-01-03 05:16 UTC (History)
0 users

See Also:


Attachments
geli.patch (23.33 KB, patch)
2013-05-06 00:10 UTC, Andrew Romanenko
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Andrew Romanenko 2013-05-06 00:10:00 UTC
	Add support external metadata for geom eli.
	For i386 all works fine.
	Need check manpage for grammatical errors (i don't spell english very well)
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2013-05-06 01:54:16 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-geom

Over to maintainer(s).
Comment 2 Mark Linimon 2013-05-07 02:39:59 UTC
----- Forwarded message from Scot Hetzel <swhetzel@gmail.com> -----

Date: Sun, 5 May 2013 22:51:10 -0500
From: Scot Hetzel <swhetzel@gmail.com>
To: freebsd-bugs@freebsd.org
Cc: Andrew Romanenko <melanhit@gmail.com>, freebsd-geom@freebsd.org
Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata

I had a quick look at the patch and noticed that it is using -H for
init method, but -h for the attach, configure, setkey, delkey, resume,
resize, and dump methods.

The patch also shows that it removes the -h option from the init
method.  I looked at the -Current and release/9.1.0 sources for
geom_eli.8 and they don't have the -h option.  I suspect it was a
local modification that was made before this patch was created.

It would be best that init, attach, configure, setkey, delkey, resume,
resize, and dump methods use the same option (-h or -H) to specify the
headerfile.

-- 
DISCLAIMER:

No electrons were maimed while sending this message. Only slightly bruised.

----- End forwarded message -----
Comment 3 Mark Linimon 2013-05-07 02:40:23 UTC
----- Forwarded message from Scot Hetzel <swhetzel@gmail.com> -----

Date: Sun, 5 May 2013 23:32:13 -0500
From: Scot Hetzel <swhetzel@gmail.com>
To: freebsd-bugs@freebsd.org
Cc: Andrew Romanenko <melanhit@gmail.com>, freebsd-geom@freebsd.org
Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata

My mistake, the -h option was in the geom_eli.c file, but only in the
comment for the commands.  According to the original commit:

https://svnweb.freebsd.org/base?view=revision&revision=148456

The -h was never in the class_commands for the init method.  Not sure
what it was there for (maybe to display the usuage?).

> It would be best that init, attach, configure, setkey, delkey, resume,
> resize, and dump methods use the same option (-h or -H) to specify the
> headerfile.
>
So for now it looks like using -H would be the better option for all
these methods.

-- 
DISCLAIMER:

No electrons were maimed while sending this message. Only slightly bruised.

----- End forwarded message -----
Comment 4 Mark Linimon 2013-05-07 02:40:48 UTC
----- Forwarded message from Andrew Romanenko <melanhit@gmail.com> -----

Date: Mon, 06 May 2013 14:29:11 +0300
From: Andrew Romanenko <melanhit@gmail.com>
To: Scot Hetzel <swhetzel@gmail.com>
Cc: freebsd-bugs@freebsd.org, freebsd-geom@freebsd.org
Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata
User-Agent: Mozilla/5.0 (X11; Linux i686;
	rv:17.0) Gecko/20130407 Thunderbird/17.0.5

Fixed, using '-H' for all methods
(updated patch in the attachment)


--- sbin/geom/class/eli/geom_eli.c.orig	2013-05-03 00:00:34.551720905 +0300
+++ sbin/geom/class/eli/geom_eli.c	2013-05-05 23:57:52.631347936 +0300
@@ -60,7 +60,6 @@
 
 #define	GELI_BACKUP_DIR	"/var/backups/"
 #define	GELI_ENC_ALGO	"aes"
-
 static void eli_main(struct gctl_req *req, unsigned flags);
 static void eli_init(struct gctl_req *req);
 static void eli_attach(struct gctl_req *req);
@@ -81,23 +80,23 @@
 /*
  * Available commands:
  *
- * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
+ * init [-bPv] [-a aalgo] [-B backupfile] [-H headerfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
  * label - alias for 'init'
- * attach [-dprv] [-j passfile] [-k keyfile] prov
+ * attach [-dprv] [-H headerfile] [-j passfile] [-k keyfile] prov
  * detach [-fl] prov ...
  * stop - alias for 'detach'
  * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
- * configure [-bB] prov ...
- * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
- * delkey [-afv] [-n keyno] prov
+ * configure [-bB] [-H headerfile] prov ...
+ * setkey [-pPv] [-H headerfile] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
+ * delkey [-afv] [-H headerfile] [-n keyno] prov
  * suspend [-v] -a | prov ...
- * resume [-pv] [-j passfile] [-k keyfile] prov
+ * resume [-pv] [-H headerfile] [-j passfile] [-k keyfile] prov
  * kill [-av] [prov ...]
  * backup [-v] prov file
  * restore [-fv] file prov
- * resize [-v] -s oldsize prov
+ * resize [-v] [-H headerfile] -s oldsize prov
  * clear [-v] prov ...
- * dump [-v] prov ...
+ * dump [-v] [-H headerfile] prov ...
  */
 struct g_command class_commands[] = {
 	{ "init", G_FLAG_VERBOSE, eli_main,
@@ -112,9 +111,10 @@
 		{ 'l', "keylen", "0", G_TYPE_NUMBER },
 		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
 		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
+	    "[-bPv] [-H headerfile] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
 	},
 	{ "label", G_FLAG_VERBOSE, eli_main,
 	    {
@@ -128,6 +128,7 @@
 		{ 'l', "keylen", "0", G_TYPE_NUMBER },
 		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
 		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
 	    "- an alias for 'init'"
@@ -139,9 +140,10 @@
 		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
 		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
 		{ 'r', "readonly", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-dprv] [-j passfile] [-k keyfile] prov"
+	    "[-dprv] [-H headerfile] [-j passfile] [-k keyfile] prov"
 	},
 	{ "detach", 0, NULL,
 	    {
@@ -174,9 +176,10 @@
 	    {
 		{ 'b', "boot", NULL, G_TYPE_BOOL },
 		{ 'B', "noboot", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-bB] prov ..."
+	    "[-bB] [-H headerfile] prov ..."
 	},
 	{ "setkey", G_FLAG_VERBOSE, eli_main,
 	    {
@@ -188,18 +191,20 @@
 		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
 		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
 		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
+	    "[-pPv] [-H headerfile] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
 	},
 	{ "delkey", G_FLAG_VERBOSE, eli_main,
 	    {
 		{ 'a', "all", NULL, G_TYPE_BOOL },
 		{ 'f', "force", NULL, G_TYPE_BOOL },
 		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-afv] [-n keyno] prov"
+	    "[-afv] [-H headerfile] [-n keyno] prov"
 	},
 	{ "suspend", G_FLAG_VERBOSE, NULL,
 	    {
@@ -213,9 +218,10 @@
 		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
 		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
 		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-pv] [-j passfile] [-k keyfile] prov"
+	    "[-pv] [-H headerfile] [-j passfile] [-k keyfile] prov"
 	},
 	{ "kill", G_FLAG_VERBOSE, eli_main,
 	    {
@@ -237,15 +243,20 @@
 	{ "resize", G_FLAG_VERBOSE, eli_main,
 	    {
 		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-v] -s oldsize prov"
+	    "[-v] [-H headerfile] -s oldsize prov"
 	},
 	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
 	    "[-v] prov ..."
 	},
-	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
-	    "[-v] prov ..."
+	{ "dump", G_FLAG_VERBOSE, eli_main,
+		{
+		{ 'H', "header", "", G_TYPE_STRING },
+		G_OPT_SENTINEL
+		},
+	    "[-v] [-H headerfile]  prov ..."
 	},
 	G_CMD_SENTINEL
 };
@@ -653,7 +664,7 @@
 	unsigned char sector[sizeof(struct g_eli_metadata)];
 	unsigned char key[G_ELI_USERKEYLEN];
 	char backfile[MAXPATHLEN];
-	const char *str, *prov;
+	const char *str, *prov, *header;
 	unsigned secsize;
 	off_t mediasize;
 	intmax_t val;
@@ -776,17 +787,39 @@
 		return;
 	}
 
+	header = gctl_get_ascii(req, "header");
+
+	/* Store header if it present */
+	if(header[0] != '\0') {
+		error = eli_metadata_store(req, header, &md);
+
+		if(error != 0) {
+			gctl_error(req, "Cannot store header %s: %s.", header,
+					strerror(error));
+			return;
+		}
+
+		str = gctl_get_ascii(req, "backupfile");
+		if(str[0] != '\0')
+			if(strcmp(str, "none") != 0)
+				printf("Warning: options -B and -h are mutualy exlusive\n");
+
+		return;
+	}
+
 	eli_metadata_encode(&md, sector);
 	bzero(&md, sizeof(md));
+
 	error = g_metadata_store(prov, sector, sizeof(sector));
 	bzero(sector, sizeof(sector));
 	if (error != 0) {
 		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
-		    strerror(error));
+			strerror(error));
 		return;
 	}
 	if (verbose)
 		printf("Metadata value stored on %s.\n", prov);
+
 	/* Backup metadata to a file. */
 	str = gctl_get_ascii(req, "backupfile");
 	if (str[0] != '\0') {
@@ -820,10 +853,14 @@
 {
 	struct g_eli_metadata md;
 	unsigned char key[G_ELI_USERKEYLEN];
-	const char *prov;
+	unsigned char *hd;
+	const char *prov, *str, *header;
 	off_t mediasize;
+	ssize_t hdsize;
 	int nargs;
 
+	hd = NULL;
+
 	nargs = gctl_get_int(req, "nargs");
 	if (nargs != 1) {
 		gctl_error(req, "Invalid number of arguments.");
@@ -831,9 +868,16 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if (header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
+	hdsize = g_get_sectorsize(prov);
 	mediasize = g_get_mediasize(prov);
 	if (md.md_provsize != (uint64_t)mediasize) {
 		gctl_error(req, "Provider size mismatch.");
@@ -845,20 +889,43 @@
 		return;
 	}
 
+	if(header[0] != '\0') {
+		hd = malloc(hdsize);
+		if(hd == NULL) {
+			gctl_error(req, "Cannot allocate %zd bytes of memory.", hdsize);
+			return;
+		}
+
+		bzero(hd, hdsize);
+		eli_metadata_encode(&md, hd);
+	} else {
+		hdsize = sizeof(hd);
+	}
+
+	gctl_ro_param(req, "hd", hdsize, hd);
 	gctl_ro_param(req, "key", sizeof(key), key);
 	if (gctl_issue(req) == NULL) {
 		if (verbose)
 			printf("Attached to %s.\n", prov);
 	}
 	bzero(key, sizeof(key));
+	if(hd != NULL)
+		free(hd);
 }
 
 static void
 eli_configure_detached(struct gctl_req *req, const char *prov, bool boot)
 {
 	struct g_eli_metadata md;
+	const char *str, *header;
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if (header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
 	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
@@ -872,7 +939,13 @@
 			md.md_flags |= G_ELI_FLAG_BOOT;
 		else
 			md.md_flags &= ~G_ELI_FLAG_BOOT;
-		eli_metadata_store(req, prov, &md);
+
+		if(header[0] != '\0')
+			str = header;
+		else
+			str = prov;
+
+		eli_metadata_store(req, str, &md);
 	}
 	bzero(&md, sizeof(md));
 }
@@ -880,7 +953,7 @@
 static void
 eli_configure(struct gctl_req *req)
 {
-	const char *prov;
+	const char *prov, *header;
 	bool boot, noboot;
 	int i, nargs;
 
@@ -902,14 +975,29 @@
 		return;
 	}
 
+	header = gctl_get_ascii(req, "header");
+
 	/* First attached providers. */
-	gctl_issue(req);
+	if(header[0] != '\0') {
+		if(nargs != 1) {
+			gctl_error(req, "Too many arguments.");
+			return;
+		}
+
+		prov = gctl_get_ascii(req, "arg0");
+		eli_configure_detached(req, prov, boot);
+		return;
+	} else {
+		gctl_issue(req);
+	}
+
 	/* Now the rest. */
 	for (i = 0; i < nargs; i++) {
 		prov = gctl_get_ascii(req, "arg%d", i);
 		if (!eli_is_attached(prov))
 			eli_configure_detached(req, prov, boot);
 	}
+
 }
 
 static void
@@ -950,6 +1038,7 @@
 eli_setkey_detached(struct gctl_req *req, const char *prov,
  struct g_eli_metadata *md)
 {
+	const char *header, *str;
 	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
 	unsigned char *mkeydst;
 	unsigned int nkey;
@@ -1035,7 +1124,14 @@
 	}
 
 	/* Store metadata with fresh key. */
-	eli_metadata_store(req, prov, md);
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	eli_metadata_store(req, str, md);
+
 	bzero(md, sizeof(*md));
 }
 
@@ -1043,7 +1139,7 @@
 eli_setkey(struct gctl_req *req)
 {
 	struct g_eli_metadata md;
-	const char *prov;
+	const char *prov, *header, *str;
 	int nargs;
 
 	nargs = gctl_get_int(req, "nargs");
@@ -1053,10 +1149,16 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
-	if (eli_is_attached(prov))
+	if (eli_is_attached(prov) && header[0] == '\0')
 		eli_setkey_attached(req, &md);
 	else
 		eli_setkey_detached(req, prov, &md);
@@ -1079,12 +1181,19 @@
 eli_delkey_detached(struct gctl_req *req, const char *prov)
 {
 	struct g_eli_metadata md;
+	const char *header, *str;
 	unsigned char *mkeydst;
 	unsigned int nkey;
 	intmax_t val;
 	bool all, force;
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
 	all = gctl_get_int(req, "all");
@@ -1116,6 +1225,11 @@
 		arc4rand(mkeydst, G_ELI_MKEYLEN);
 	}
 
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
 	eli_metadata_store(req, prov, &md);
 	bzero(&md, sizeof(md));
 }
@@ -1123,7 +1237,7 @@
 static void
 eli_delkey(struct gctl_req *req)
 {
-	const char *prov;
+	const char *prov, *header;
 	int nargs;
 
 	nargs = gctl_get_int(req, "nargs");
@@ -1133,7 +1247,9 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_is_attached(prov))
+	header = gctl_get_ascii(req, "header");
+
+	if (eli_is_attached(prov) && header[0] == '\0')
 		eli_delkey_attached(req, prov);
 	else
 		eli_delkey_detached(req, prov);
@@ -1144,10 +1260,14 @@
 {
 	struct g_eli_metadata md;
 	unsigned char key[G_ELI_USERKEYLEN];
-	const char *prov;
+	unsigned char *hd;
+	const char *prov, *str, *header;
 	off_t mediasize;
+	ssize_t hdsize;
 	int nargs;
 
+	hd = NULL;
+
 	nargs = gctl_get_int(req, "nargs");
 	if (nargs != 1) {
 		gctl_error(req, "Invalid number of arguments.");
@@ -1155,10 +1275,18 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if (header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
 	mediasize = g_get_mediasize(prov);
+	hdsize = g_get_sectorsize(prov);
+
 	if (md.md_provsize != (uint64_t)mediasize) {
 		gctl_error(req, "Provider size mismatch.");
 		return;
@@ -1169,12 +1297,30 @@
 		return;
 	}
 
+	if(header[0] != '\0') {
+		hd = malloc(hdsize);
+		if(hd == NULL) {
+			gctl_error(req, "Cannot allocate %zd bytes of memory.", hdsize);
+			return;
+		}
+
+		bzero(hd, hdsize);
+		eli_metadata_encode(&md, hd);
+	} else {
+		hdsize = sizeof(hd);
+	}
+
+	gctl_ro_param(req, "hd", hdsize, hd);
 	gctl_ro_param(req, "key", sizeof(key), key);
+
 	if (gctl_issue(req) == NULL) {
 		if (verbose)
 			printf("Resumed %s.\n", prov);
 	}
 	bzero(key, sizeof(key));
+
+	if(hd != NULL)
+		free(hd);
 }
 
 static int
@@ -1469,11 +1615,11 @@
 eli_resize(struct gctl_req *req)
 {
 	struct g_eli_metadata md;
-	const char *prov;
+	const char *prov, *header;
 	unsigned char *sector;
 	ssize_t secsize;
 	off_t mediasize, oldsize;
-	int nargs, provfd;
+	int nargs, provfd, error;
 
 	nargs = gctl_get_int(req, "nargs");
 	if (nargs != 1) {
@@ -1486,14 +1632,18 @@
 	sector = NULL;
 	secsize = 0;
 
-	provfd = g_open(prov, 1);
-	if (provfd == -1) {
-		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
-		goto out;
+	header = gctl_get_ascii(req, "header");
+
+	if(header[0] == '\0') {
+		provfd = g_open(prov, 1);
+		if (provfd == -1) {
+			gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
+			goto out;
+		}
 	}
 
-	mediasize = g_mediasize(provfd);
-	secsize = g_sectorsize(provfd);
+	mediasize = g_get_mediasize(prov);
+	secsize = g_get_sectorsize(prov);
 	if (mediasize == -1 || secsize == -1) {
 		gctl_error(req, "Cannot get information about %s: %s.", prov,
 		    strerror(errno));
@@ -1517,16 +1667,24 @@
 	}
 
 	/* Read metadata from the 'oldsize' offset. */
-	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
-		gctl_error(req, "Cannot read old metadata: %s.",
-		    strerror(errno));
-		goto out;
-	}
+	if(header[0] != '\0') {
+		if (eli_metadata_read(req, header, &md) == -1) {
+			gctl_error(req, "Cannot read old metadata: %s.",
+					header);
+			goto out;
+		}
+	} else {
+		if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
+			gctl_error(req, "Cannot read old metadata: %s.",
+				strerror(errno));
+			goto out;
+		}
 
-	/* Check if this sector contains geli metadata. */
-	if (eli_metadata_decode(sector, &md) != 0) {
-		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
-		goto out;
+		/* Check if this sector contains geli metadata. */
+		if (eli_metadata_decode(sector, &md) != 0) {
+			gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
+			goto out;
+		}
 	}
 
 	/*
@@ -1544,15 +1702,25 @@
 	 */
 	md.md_provsize = mediasize;
 	eli_metadata_encode(&md, sector);
-	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
-		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
-		goto out;
-	}
-	(void)g_flush(provfd);
 
-	/* Now trash the old metadata. */
-	if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
-		goto out;
+	if(header[0] != '\0') {
+		error = eli_metadata_store(req, header, &md);
+		if(error != 0) {
+			gctl_error(req, "Cannot store header %s: %s.", header,
+					strerror(error));
+			goto out;
+		}
+	} else {
+		if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
+			gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
+			goto out;
+		}
+		(void)g_flush(provfd);
+
+		/* Now trash the old metadata. */
+		if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
+			goto out;
+	}
 out:
 	if (provfd >= 0)
 		(void)g_close(provfd);
@@ -1592,7 +1760,7 @@
 eli_dump(struct gctl_req *req)
 {
 	struct g_eli_metadata md, tmpmd;
-	const char *name;
+	const char *name, *header;
 	int error, i, nargs;
 
 	nargs = gctl_get_int(req, "nargs");
@@ -1601,15 +1769,40 @@
 		return;
 	}
 
-	for (i = 0; i < nargs; i++) {
-		name = gctl_get_ascii(req, "arg%d", i);
-		error = g_metadata_read(name, (unsigned char *)&tmpmd,
-		    sizeof(tmpmd), G_ELI_MAGIC);
-		if (error != 0) {
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0') {
+		if(nargs != 1) {
+			gctl_error(req, "Too many arguments.");
+			return;
+		}
+
+		if (eli_metadata_read(req, header, &tmpmd) == -1)
+			return;
+
+		name = gctl_get_ascii(req, "arg0");
+
+		if (strcmp(tmpmd.md_magic, G_ELI_MAGIC) != 0) {
+			error = EINVAL;
 			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
-			    name, strerror(error));
+					name, strerror(error));
 			gctl_error(req, "Not fully done.");
-			continue;
+			return;
+		}
+
+		name = header;
+	}
+
+	for (i = 0; i < nargs; i++) {
+		if(header[0] == '\0') {
+			name = gctl_get_ascii(req, "arg%d", i);
+			error = g_metadata_read(name, (unsigned char *)&tmpmd,
+				sizeof(tmpmd), G_ELI_MAGIC);
+			if (error != 0) {
+				fprintf(stderr, "Cannot read metadata from %s: %s.\n",
+					name, strerror(error));
+				gctl_error(req, "Not fully done.");
+				continue;
+			}
 		}
 		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
 			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
--- sbin/geom/class/eli/geli.8.orig	2013-04-29 01:45:56.000000000 +0300
+++ sbin/geom/class/eli/geli.8	2013-05-05 16:49:57.642188841 +0300
@@ -52,6 +52,7 @@
 .Nm
 .Cm init
 .Op Fl bPv
+.Op Fl H Ar headerfile
 .Op Fl a Ar aalgo
 .Op Fl B Ar backupfile
 .Op Fl e Ar ealgo
@@ -67,6 +68,7 @@
 .Nm
 .Cm attach
 .Op Fl dprv
+.Op Fl H Ar headerfile
 .Op Fl j Ar passfile
 .Op Fl k Ar keyfile
 .Ar prov
@@ -88,10 +90,12 @@
 .Nm
 .Cm configure
 .Op Fl bB
+.Op Fl H Ar headerfile
 .Ar prov ...
 .Nm
 .Cm setkey
 .Op Fl pPv
+.Op Fl H Ar headerfile
 .Op Fl i Ar iterations
 .Op Fl j Ar passfile
 .Op Fl J Ar newpassfile
@@ -102,6 +106,7 @@
 .Nm
 .Cm delkey
 .Op Fl afv
+.Op Fl H Ar headerfile
 .Op Fl n Ar keyno
 .Ar prov
 .Nm
@@ -125,12 +130,14 @@
 .Nm
 .Cm resume
 .Op Fl pv
+.Op Fl H Ar headerfile
 .Op Fl j Ar passfile
 .Op Fl k Ar keyfile
 .Ar prov
 .Nm
 .Cm resize
 .Op Fl v
+.Op Fl H Ar headerfile
 .Fl s Ar oldsize
 .Ar prov
 .Nm
@@ -140,6 +147,7 @@
 .Nm
 .Cm dump
 .Op Fl v
+.Op Fl H Ar headerfile
 .Ar prov ...
 .Nm
 .Cm list
@@ -240,6 +248,8 @@
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl J Ar newpassfile"
+.It Fl H Ar headerfile
+Store GELI metadata (header) in the external file
 .It Fl a Ar aalgo
 Enable data integrity verification (authentication) using the given algorithm.
 This will reduce size of available storage and also reduce speed.
@@ -341,6 +351,8 @@
 option for the
 .Cm detach
 subcommand.
+.It Fl H Ar headerfile
+Read metadata from a file instead from a provider
 .It Fl j Ar passfile
 Specifies a file which contains the passphrase or its part.
 For more information see the description of the
@@ -415,7 +427,9 @@
 Change configuration of the given providers.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl b"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl b
 Set the BOOT flag on the given providers.
 For more information, see the description of the
@@ -437,6 +451,8 @@
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl J Ar newpassfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl i Ar iterations
 Number of iterations to use with PKCS#5v2.
 If 0 is given, PKCS#5v2 will not be used.
@@ -472,7 +488,9 @@
 subcommand.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl a Ar keyno"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl a
 Destroy all keys (does not need
 .Fl f
@@ -567,7 +585,9 @@
 utility is stored is bad idea.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl j Ar passfile"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl j Ar passfile
 Specifies a file which contains the passphrase or its part.
 For more information see the description of the
@@ -593,7 +613,9 @@
 provider and the provider size is updated.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl s Ar oldsize"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl s Ar oldsize
 The size of the provider before it was resized.
 .El
@@ -764,6 +786,9 @@
 # dd if=/dev/random of=/dev/da1s3a bs=1m
 # dd if=/dev/random of=/boot/keys/da1s3a.key bs=128k count=1
 # geli init -b -P -K /boot/keys/da1s3a.key da1s3a
+# dd if=/dev/random of=/dev/ada1 bs=1m
+# dd if=/dev/random of=/boot/keys/ada1.key bs=8 count=8
+# geli init -b -H /boot/hd/ada1.hd -P -K /boot/keys/ada1.key ada1
 .Ed
 .Pp
 The providers are initialized, now we have to add those lines to
@@ -782,6 +807,13 @@
 geli_da1s3a_keyfile0_load="YES"
 geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0"
 geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key"
+
+geli_ada1_header_load="YES"
+geli_ada1_header_type="ada1:geli_header"
+geli_ada1_header_name="/boot/hd/ada1.hd"
+geli_ada1_keyfile0_load="YES"
+geli_ada1_keyfile0_type="ada1:geli_keyfile0"
+geli_ada1_keyfile0_name="/boot/keys/ada1.key"
 .Ed
 .Pp
 Not only configure encryption, but also data integrity verification using
--- sys/geom/eli/g_eli_ctl.c.orig	2013-05-04 01:21:45.381136674 +0300
+++ sys/geom/eli/g_eli_ctl.c	2013-05-05 03:20:20.180243224 +0300
@@ -56,10 +56,11 @@
 	struct g_eli_metadata md;
 	struct g_provider *pp;
 	const char *name;
-	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
+	u_char *key, *hd, mkey[G_ELI_DATAIVKEYLEN];
 	int *nargs, *detach, *readonly;
 	int keysize, error;
 	u_int nkey;
+	ssize_t hdsize;
 
 	g_topology_assert();
 
@@ -97,11 +98,18 @@
 		gctl_error(req, "Provider %s is invalid.", name);
 		return;
 	}
-	error = g_eli_read_metadata(mp, pp, &md);
-	if (error != 0) {
-		gctl_error(req, "Cannot read metadata from %s (error=%d).",
-		    name, error);
-		return;
+
+	hd = gctl_get_param(req, "hd", &hdsize);
+
+	if(hdsize == pp->sectorsize) {
+		eli_metadata_decode(hd, &md);
+	} else {
+		error = g_eli_read_metadata(mp, pp, &md);
+		if (error != 0) {
+			gctl_error(req, "Cannot read metadata from %s (error=%d).",
+				name, error);
+			return;
+		}
 	}
 	if (md.md_keys == 0x00) {
 		bzero(&md, sizeof(md));
@@ -448,8 +456,8 @@
 		error = g_eli_read_metadata(mp, pp, &md);
 		if (error != 0) {
 			gctl_error(req,
-			    "Cannot read metadata from %s (error=%d).",
-			    prov, error);
+				"Cannot read metadata from %s (error=%d).",
+				prov, error);
 			continue;
 		}
 
@@ -464,12 +472,13 @@
 		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);
+			pp->sectorsize);
 		if (error != 0) {
 			gctl_error(req,
-			    "Cannot store metadata on %s (error=%d).",
-			    prov, error);
+				"Cannot store metadata on %s (error=%d).",
+				prov, error);
 		}
+		
 		bzero(&md, sizeof(md));
 		bzero(sector, sizeof(sector));
 		free(sector, M_ELI);
@@ -815,9 +824,10 @@
 	struct g_provider *pp;
 	struct g_consumer *cp;
 	const char *name;
-	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
+	u_char *key, *hd, mkey[G_ELI_DATAIVKEYLEN];
 	int *nargs, keysize, error;
 	u_int nkey;
+	ssize_t hdsize;
 
 	g_topology_assert();
 
@@ -843,12 +853,20 @@
 	}
 	cp = LIST_FIRST(&sc->sc_geom->consumer);
 	pp = cp->provider;
-	error = g_eli_read_metadata(mp, pp, &md);
-	if (error != 0) {
-		gctl_error(req, "Cannot read metadata from %s (error=%d).",
-		    name, error);
-		return;
+
+	hd = gctl_get_param(req, "hd", &hdsize);
+
+	if(hdsize == pp->sectorsize) {
+		eli_metadata_decode(hd, &md);
+	} else {
+		error = g_eli_read_metadata(mp, pp, &md);
+		if (error != 0) {
+			gctl_error(req, "Cannot read metadata from %s (error=%d).",
+				name, error);
+			return;
+		}
 	}
+
 	if (md.md_keys == 0x00) {
 		bzero(&md, sizeof(md));
 		gctl_error(req, "No valid keys on %s.", pp->name);

----- End forwarded message -----
Comment 5 Mark Linimon 2013-05-08 22:35:55 UTC
----- Forwarded message from Andrew Romanenko <melanhit@gmail.com> -----

Date: Tue, 07 May 2013 10:26:07 +0300
From: Andrew Romanenko <melanhit@gmail.com>
To: Scot Hetzel <swhetzel@gmail.com>
Cc: freebsd-bugs@freebsd.org, freebsd-geom@freebsd.org
Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata
User-Agent: Mozilla/5.0 (X11; Linux i686;
	rv:17.0) Gecko/20130407 Thunderbird/17.0.5

On 05/06/2013 07:32 AM, Scot Hetzel wrote:
> On Sun, May 5, 2013 at 10:51 PM, Scot Hetzel <swhetzel@gmail.com> wrote:
>> On Sun, May 5, 2013 at 7:54 PM,  <linimon@freebsd.org> wrote:
>>> Old Synopsis: geom_eli: support external metadata
>>> New Synopsis: [geom] [patch] geom_eli: support external metadata
>>>
>>> Responsible-Changed-From-To: freebsd-bugs->freebsd-geom
>>> Responsible-Changed-By: linimon
>>> Responsible-Changed-When: Mon May 6 00:54:16 UTC 2013
>>> Responsible-Changed-Why:
>>> Over to maintainer(s).
>>>
>>> http://www.freebsd.org/cgi/query-pr.cgi?pr=178359
>> I had a quick look at the patch and noticed that it is using -H for
>> init method, but -h for the attach, configure, setkey, delkey, resume,
>> resize, and dump methods.
>>
>> The patch also shows that it removes the -h option from the init
>> method.  I looked at the -Current and release/9.1.0 sources for
>> geom_eli.8 and they don't have the -h option.  I suspect it was a
>> local modification that was made before this patch was created.
>>
> My mistake, the -h option was in the geom_eli.c file, but only in the
> comment for the commands.  According to the original commit:
>
> https://svnweb.freebsd.org/base?view=revision&revision=148456
>
> The -h was never in the class_commands for the init method.  Not sure
> what it was there for (maybe to display the usuage?).
>
>> It would be best that init, attach, configure, setkey, delkey, resume,
>> resize, and dump methods use the same option (-h or -H) to specify the
>> headerfile.
>>
> So for now it looks like using -H would be the better option for all
> these methods.
>
I forgot to include patch sys/geom/eli/g_eli.c (sorry, it's my mistake).
Finished and full version of the patch in an attachment

--- sbin/geom/class/eli/geom_eli.c.orig	2013-05-03 00:00:34.551720905 +0300
+++ sbin/geom/class/eli/geom_eli.c	2013-05-05 23:57:52.631347936 +0300
@@ -60,7 +60,6 @@
 
 #define	GELI_BACKUP_DIR	"/var/backups/"
 #define	GELI_ENC_ALGO	"aes"
-
 static void eli_main(struct gctl_req *req, unsigned flags);
 static void eli_init(struct gctl_req *req);
 static void eli_attach(struct gctl_req *req);
@@ -81,23 +80,23 @@
 /*
  * Available commands:
  *
- * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
+ * init [-bPv] [-a aalgo] [-B backupfile] [-H headerfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
  * label - alias for 'init'
- * attach [-dprv] [-j passfile] [-k keyfile] prov
+ * attach [-dprv] [-H headerfile] [-j passfile] [-k keyfile] prov
  * detach [-fl] prov ...
  * stop - alias for 'detach'
  * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
- * configure [-bB] prov ...
- * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
- * delkey [-afv] [-n keyno] prov
+ * configure [-bB] [-H headerfile] prov ...
+ * setkey [-pPv] [-H headerfile] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
+ * delkey [-afv] [-H headerfile] [-n keyno] prov
  * suspend [-v] -a | prov ...
- * resume [-pv] [-j passfile] [-k keyfile] prov
+ * resume [-pv] [-H headerfile] [-j passfile] [-k keyfile] prov
  * kill [-av] [prov ...]
  * backup [-v] prov file
  * restore [-fv] file prov
- * resize [-v] -s oldsize prov
+ * resize [-v] [-H headerfile] -s oldsize prov
  * clear [-v] prov ...
- * dump [-v] prov ...
+ * dump [-v] [-H headerfile] prov ...
  */
 struct g_command class_commands[] = {
 	{ "init", G_FLAG_VERBOSE, eli_main,
@@ -112,9 +111,10 @@
 		{ 'l', "keylen", "0", G_TYPE_NUMBER },
 		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
 		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
+	    "[-bPv] [-H headerfile] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
 	},
 	{ "label", G_FLAG_VERBOSE, eli_main,
 	    {
@@ -128,6 +128,7 @@
 		{ 'l', "keylen", "0", G_TYPE_NUMBER },
 		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
 		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
 	    "- an alias for 'init'"
@@ -139,9 +140,10 @@
 		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
 		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
 		{ 'r', "readonly", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-dprv] [-j passfile] [-k keyfile] prov"
+	    "[-dprv] [-H headerfile] [-j passfile] [-k keyfile] prov"
 	},
 	{ "detach", 0, NULL,
 	    {
@@ -174,9 +176,10 @@
 	    {
 		{ 'b', "boot", NULL, G_TYPE_BOOL },
 		{ 'B', "noboot", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-bB] prov ..."
+	    "[-bB] [-H headerfile] prov ..."
 	},
 	{ "setkey", G_FLAG_VERBOSE, eli_main,
 	    {
@@ -188,18 +191,20 @@
 		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
 		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
 		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
+	    "[-pPv] [-H headerfile] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
 	},
 	{ "delkey", G_FLAG_VERBOSE, eli_main,
 	    {
 		{ 'a', "all", NULL, G_TYPE_BOOL },
 		{ 'f', "force", NULL, G_TYPE_BOOL },
 		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-afv] [-n keyno] prov"
+	    "[-afv] [-H headerfile] [-n keyno] prov"
 	},
 	{ "suspend", G_FLAG_VERBOSE, NULL,
 	    {
@@ -213,9 +218,10 @@
 		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
 		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
 		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-pv] [-j passfile] [-k keyfile] prov"
+	    "[-pv] [-H headerfile] [-j passfile] [-k keyfile] prov"
 	},
 	{ "kill", G_FLAG_VERBOSE, eli_main,
 	    {
@@ -237,15 +243,20 @@
 	{ "resize", G_FLAG_VERBOSE, eli_main,
 	    {
 		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
+		{ 'H', "header", "", G_TYPE_STRING },
 		G_OPT_SENTINEL
 	    },
-	    "[-v] -s oldsize prov"
+	    "[-v] [-H headerfile] -s oldsize prov"
 	},
 	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
 	    "[-v] prov ..."
 	},
-	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
-	    "[-v] prov ..."
+	{ "dump", G_FLAG_VERBOSE, eli_main,
+		{
+		{ 'H', "header", "", G_TYPE_STRING },
+		G_OPT_SENTINEL
+		},
+	    "[-v] [-H headerfile]  prov ..."
 	},
 	G_CMD_SENTINEL
 };
@@ -653,7 +664,7 @@
 	unsigned char sector[sizeof(struct g_eli_metadata)];
 	unsigned char key[G_ELI_USERKEYLEN];
 	char backfile[MAXPATHLEN];
-	const char *str, *prov;
+	const char *str, *prov, *header;
 	unsigned secsize;
 	off_t mediasize;
 	intmax_t val;
@@ -776,17 +787,39 @@
 		return;
 	}
 
+	header = gctl_get_ascii(req, "header");
+
+	/* Store header if it present */
+	if(header[0] != '\0') {
+		error = eli_metadata_store(req, header, &md);
+
+		if(error != 0) {
+			gctl_error(req, "Cannot store header %s: %s.", header,
+					strerror(error));
+			return;
+		}
+
+		str = gctl_get_ascii(req, "backupfile");
+		if(str[0] != '\0')
+			if(strcmp(str, "none") != 0)
+				printf("Warning: options -B and -H are mutualy exlusive\n");
+
+		return;
+	}
+
 	eli_metadata_encode(&md, sector);
 	bzero(&md, sizeof(md));
+
 	error = g_metadata_store(prov, sector, sizeof(sector));
 	bzero(sector, sizeof(sector));
 	if (error != 0) {
 		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
-		    strerror(error));
+			strerror(error));
 		return;
 	}
 	if (verbose)
 		printf("Metadata value stored on %s.\n", prov);
+
 	/* Backup metadata to a file. */
 	str = gctl_get_ascii(req, "backupfile");
 	if (str[0] != '\0') {
@@ -820,10 +853,14 @@
 {
 	struct g_eli_metadata md;
 	unsigned char key[G_ELI_USERKEYLEN];
-	const char *prov;
+	unsigned char *hd;
+	const char *prov, *str, *header;
 	off_t mediasize;
+	ssize_t hdsize;
 	int nargs;
 
+	hd = NULL;
+
 	nargs = gctl_get_int(req, "nargs");
 	if (nargs != 1) {
 		gctl_error(req, "Invalid number of arguments.");
@@ -831,9 +868,16 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if (header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
+	hdsize = g_get_sectorsize(prov);
 	mediasize = g_get_mediasize(prov);
 	if (md.md_provsize != (uint64_t)mediasize) {
 		gctl_error(req, "Provider size mismatch.");
@@ -845,20 +889,43 @@
 		return;
 	}
 
+	if(header[0] != '\0') {
+		hd = malloc(hdsize);
+		if(hd == NULL) {
+			gctl_error(req, "Cannot allocate %zd bytes of memory.", hdsize);
+			return;
+		}
+
+		bzero(hd, hdsize);
+		eli_metadata_encode(&md, hd);
+	} else {
+		hdsize = sizeof(hd);
+	}
+
+	gctl_ro_param(req, "hd", hdsize, hd);
 	gctl_ro_param(req, "key", sizeof(key), key);
 	if (gctl_issue(req) == NULL) {
 		if (verbose)
 			printf("Attached to %s.\n", prov);
 	}
 	bzero(key, sizeof(key));
+	if(hd != NULL)
+		free(hd);
 }
 
 static void
 eli_configure_detached(struct gctl_req *req, const char *prov, bool boot)
 {
 	struct g_eli_metadata md;
+	const char *str, *header;
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if (header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
 	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
@@ -872,7 +939,13 @@
 			md.md_flags |= G_ELI_FLAG_BOOT;
 		else
 			md.md_flags &= ~G_ELI_FLAG_BOOT;
-		eli_metadata_store(req, prov, &md);
+
+		if(header[0] != '\0')
+			str = header;
+		else
+			str = prov;
+
+		eli_metadata_store(req, str, &md);
 	}
 	bzero(&md, sizeof(md));
 }
@@ -880,7 +953,7 @@
 static void
 eli_configure(struct gctl_req *req)
 {
-	const char *prov;
+	const char *prov, *header;
 	bool boot, noboot;
 	int i, nargs;
 
@@ -902,14 +975,29 @@
 		return;
 	}
 
+	header = gctl_get_ascii(req, "header");
+
 	/* First attached providers. */
-	gctl_issue(req);
+	if(header[0] != '\0') {
+		if(nargs != 1) {
+			gctl_error(req, "Too many arguments.");
+			return;
+		}
+
+		prov = gctl_get_ascii(req, "arg0");
+		eli_configure_detached(req, prov, boot);
+		return;
+	} else {
+		gctl_issue(req);
+	}
+
 	/* Now the rest. */
 	for (i = 0; i < nargs; i++) {
 		prov = gctl_get_ascii(req, "arg%d", i);
 		if (!eli_is_attached(prov))
 			eli_configure_detached(req, prov, boot);
 	}
+
 }
 
 static void
@@ -950,6 +1038,7 @@
 eli_setkey_detached(struct gctl_req *req, const char *prov,
  struct g_eli_metadata *md)
 {
+	const char *header, *str;
 	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
 	unsigned char *mkeydst;
 	unsigned int nkey;
@@ -1035,7 +1124,14 @@
 	}
 
 	/* Store metadata with fresh key. */
-	eli_metadata_store(req, prov, md);
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	eli_metadata_store(req, str, md);
+
 	bzero(md, sizeof(*md));
 }
 
@@ -1043,7 +1139,7 @@
 eli_setkey(struct gctl_req *req)
 {
 	struct g_eli_metadata md;
-	const char *prov;
+	const char *prov, *header, *str;
 	int nargs;
 
 	nargs = gctl_get_int(req, "nargs");
@@ -1053,10 +1149,16 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
-	if (eli_is_attached(prov))
+	if (eli_is_attached(prov) && header[0] == '\0')
 		eli_setkey_attached(req, &md);
 	else
 		eli_setkey_detached(req, prov, &md);
@@ -1079,12 +1181,19 @@
 eli_delkey_detached(struct gctl_req *req, const char *prov)
 {
 	struct g_eli_metadata md;
+	const char *header, *str;
 	unsigned char *mkeydst;
 	unsigned int nkey;
 	intmax_t val;
 	bool all, force;
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
 	all = gctl_get_int(req, "all");
@@ -1116,6 +1225,11 @@
 		arc4rand(mkeydst, G_ELI_MKEYLEN);
 	}
 
+	if(header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
 	eli_metadata_store(req, prov, &md);
 	bzero(&md, sizeof(md));
 }
@@ -1123,7 +1237,7 @@
 static void
 eli_delkey(struct gctl_req *req)
 {
-	const char *prov;
+	const char *prov, *header;
 	int nargs;
 
 	nargs = gctl_get_int(req, "nargs");
@@ -1133,7 +1247,9 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_is_attached(prov))
+	header = gctl_get_ascii(req, "header");
+
+	if (eli_is_attached(prov) && header[0] == '\0')
 		eli_delkey_attached(req, prov);
 	else
 		eli_delkey_detached(req, prov);
@@ -1144,10 +1260,14 @@
 {
 	struct g_eli_metadata md;
 	unsigned char key[G_ELI_USERKEYLEN];
-	const char *prov;
+	unsigned char *hd;
+	const char *prov, *str, *header;
 	off_t mediasize;
+	ssize_t hdsize;
 	int nargs;
 
+	hd = NULL;
+
 	nargs = gctl_get_int(req, "nargs");
 	if (nargs != 1) {
 		gctl_error(req, "Invalid number of arguments.");
@@ -1155,10 +1275,18 @@
 	}
 	prov = gctl_get_ascii(req, "arg0");
 
-	if (eli_metadata_read(req, prov, &md) == -1)
+	header = gctl_get_ascii(req, "header");
+	if (header[0] != '\0')
+		str = header;
+	else
+		str = prov;
+
+	if (eli_metadata_read(req, str, &md) == -1)
 		return;
 
 	mediasize = g_get_mediasize(prov);
+	hdsize = g_get_sectorsize(prov);
+
 	if (md.md_provsize != (uint64_t)mediasize) {
 		gctl_error(req, "Provider size mismatch.");
 		return;
@@ -1169,12 +1297,30 @@
 		return;
 	}
 
+	if(header[0] != '\0') {
+		hd = malloc(hdsize);
+		if(hd == NULL) {
+			gctl_error(req, "Cannot allocate %zd bytes of memory.", hdsize);
+			return;
+		}
+
+		bzero(hd, hdsize);
+		eli_metadata_encode(&md, hd);
+	} else {
+		hdsize = sizeof(hd);
+	}
+
+	gctl_ro_param(req, "hd", hdsize, hd);
 	gctl_ro_param(req, "key", sizeof(key), key);
+
 	if (gctl_issue(req) == NULL) {
 		if (verbose)
 			printf("Resumed %s.\n", prov);
 	}
 	bzero(key, sizeof(key));
+
+	if(hd != NULL)
+		free(hd);
 }
 
 static int
@@ -1469,11 +1615,11 @@
 eli_resize(struct gctl_req *req)
 {
 	struct g_eli_metadata md;
-	const char *prov;
+	const char *prov, *header;
 	unsigned char *sector;
 	ssize_t secsize;
 	off_t mediasize, oldsize;
-	int nargs, provfd;
+	int nargs, provfd, error;
 
 	nargs = gctl_get_int(req, "nargs");
 	if (nargs != 1) {
@@ -1486,14 +1632,18 @@
 	sector = NULL;
 	secsize = 0;
 
-	provfd = g_open(prov, 1);
-	if (provfd == -1) {
-		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
-		goto out;
+	header = gctl_get_ascii(req, "header");
+
+	if(header[0] == '\0') {
+		provfd = g_open(prov, 1);
+		if (provfd == -1) {
+			gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
+			goto out;
+		}
 	}
 
-	mediasize = g_mediasize(provfd);
-	secsize = g_sectorsize(provfd);
+	mediasize = g_get_mediasize(prov);
+	secsize = g_get_sectorsize(prov);
 	if (mediasize == -1 || secsize == -1) {
 		gctl_error(req, "Cannot get information about %s: %s.", prov,
 		    strerror(errno));
@@ -1517,16 +1667,24 @@
 	}
 
 	/* Read metadata from the 'oldsize' offset. */
-	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
-		gctl_error(req, "Cannot read old metadata: %s.",
-		    strerror(errno));
-		goto out;
-	}
+	if(header[0] != '\0') {
+		if (eli_metadata_read(req, header, &md) == -1) {
+			gctl_error(req, "Cannot read old metadata: %s.",
+					header);
+			goto out;
+		}
+	} else {
+		if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
+			gctl_error(req, "Cannot read old metadata: %s.",
+				strerror(errno));
+			goto out;
+		}
 
-	/* Check if this sector contains geli metadata. */
-	if (eli_metadata_decode(sector, &md) != 0) {
-		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
-		goto out;
+		/* Check if this sector contains geli metadata. */
+		if (eli_metadata_decode(sector, &md) != 0) {
+			gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
+			goto out;
+		}
 	}
 
 	/*
@@ -1544,15 +1702,25 @@
 	 */
 	md.md_provsize = mediasize;
 	eli_metadata_encode(&md, sector);
-	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
-		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
-		goto out;
-	}
-	(void)g_flush(provfd);
 
-	/* Now trash the old metadata. */
-	if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
-		goto out;
+	if(header[0] != '\0') {
+		error = eli_metadata_store(req, header, &md);
+		if(error != 0) {
+			gctl_error(req, "Cannot store header %s: %s.", header,
+					strerror(error));
+			goto out;
+		}
+	} else {
+		if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
+			gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
+			goto out;
+		}
+		(void)g_flush(provfd);
+
+		/* Now trash the old metadata. */
+		if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
+			goto out;
+	}
 out:
 	if (provfd >= 0)
 		(void)g_close(provfd);
@@ -1592,7 +1760,7 @@
 eli_dump(struct gctl_req *req)
 {
 	struct g_eli_metadata md, tmpmd;
-	const char *name;
+	const char *name, *header;
 	int error, i, nargs;
 
 	nargs = gctl_get_int(req, "nargs");
@@ -1601,15 +1769,40 @@
 		return;
 	}
 
-	for (i = 0; i < nargs; i++) {
-		name = gctl_get_ascii(req, "arg%d", i);
-		error = g_metadata_read(name, (unsigned char *)&tmpmd,
-		    sizeof(tmpmd), G_ELI_MAGIC);
-		if (error != 0) {
+	header = gctl_get_ascii(req, "header");
+	if(header[0] != '\0') {
+		if(nargs != 1) {
+			gctl_error(req, "Too many arguments.");
+			return;
+		}
+
+		if (eli_metadata_read(req, header, &tmpmd) == -1)
+			return;
+
+		name = gctl_get_ascii(req, "arg0");
+
+		if (strcmp(tmpmd.md_magic, G_ELI_MAGIC) != 0) {
+			error = EINVAL;
 			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
-			    name, strerror(error));
+					name, strerror(error));
 			gctl_error(req, "Not fully done.");
-			continue;
+			return;
+		}
+
+		name = header;
+	}
+
+	for (i = 0; i < nargs; i++) {
+		if(header[0] == '\0') {
+			name = gctl_get_ascii(req, "arg%d", i);
+			error = g_metadata_read(name, (unsigned char *)&tmpmd,
+				sizeof(tmpmd), G_ELI_MAGIC);
+			if (error != 0) {
+				fprintf(stderr, "Cannot read metadata from %s: %s.\n",
+					name, strerror(error));
+				gctl_error(req, "Not fully done.");
+				continue;
+			}
 		}
 		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
 			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
--- sbin/geom/class/eli/geli.8.orig	2013-04-29 01:45:56.000000000 +0300
+++ sbin/geom/class/eli/geli.8	2013-05-05 16:49:57.642188841 +0300
@@ -52,6 +52,7 @@
 .Nm
 .Cm init
 .Op Fl bPv
+.Op Fl H Ar headerfile
 .Op Fl a Ar aalgo
 .Op Fl B Ar backupfile
 .Op Fl e Ar ealgo
@@ -67,6 +68,7 @@
 .Nm
 .Cm attach
 .Op Fl dprv
+.Op Fl H Ar headerfile
 .Op Fl j Ar passfile
 .Op Fl k Ar keyfile
 .Ar prov
@@ -88,10 +90,12 @@
 .Nm
 .Cm configure
 .Op Fl bB
+.Op Fl H Ar headerfile
 .Ar prov ...
 .Nm
 .Cm setkey
 .Op Fl pPv
+.Op Fl H Ar headerfile
 .Op Fl i Ar iterations
 .Op Fl j Ar passfile
 .Op Fl J Ar newpassfile
@@ -102,6 +106,7 @@
 .Nm
 .Cm delkey
 .Op Fl afv
+.Op Fl H Ar headerfile
 .Op Fl n Ar keyno
 .Ar prov
 .Nm
@@ -125,12 +130,14 @@
 .Nm
 .Cm resume
 .Op Fl pv
+.Op Fl H Ar headerfile
 .Op Fl j Ar passfile
 .Op Fl k Ar keyfile
 .Ar prov
 .Nm
 .Cm resize
 .Op Fl v
+.Op Fl H Ar headerfile
 .Fl s Ar oldsize
 .Ar prov
 .Nm
@@ -140,6 +147,7 @@
 .Nm
 .Cm dump
 .Op Fl v
+.Op Fl H Ar headerfile
 .Ar prov ...
 .Nm
 .Cm list
@@ -240,6 +248,8 @@
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl J Ar newpassfile"
+.It Fl H Ar headerfile
+Store GELI metadata (header) in the external file
 .It Fl a Ar aalgo
 Enable data integrity verification (authentication) using the given algorithm.
 This will reduce size of available storage and also reduce speed.
@@ -341,6 +351,8 @@
 option for the
 .Cm detach
 subcommand.
+.It Fl H Ar headerfile
+Read metadata from a file instead from a provider
 .It Fl j Ar passfile
 Specifies a file which contains the passphrase or its part.
 For more information see the description of the
@@ -415,7 +427,9 @@
 Change configuration of the given providers.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl b"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl b
 Set the BOOT flag on the given providers.
 For more information, see the description of the
@@ -437,6 +451,8 @@
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl J Ar newpassfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl i Ar iterations
 Number of iterations to use with PKCS#5v2.
 If 0 is given, PKCS#5v2 will not be used.
@@ -472,7 +488,9 @@
 subcommand.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl a Ar keyno"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl a
 Destroy all keys (does not need
 .Fl f
@@ -567,7 +585,9 @@
 utility is stored is bad idea.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl j Ar passfile"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl j Ar passfile
 Specifies a file which contains the passphrase or its part.
 For more information see the description of the
@@ -593,7 +613,9 @@
 provider and the provider size is updated.
 .Pp
 Additional options include:
-.Bl -tag -width ".Fl s Ar oldsize"
+.Bl -tag -width ".Fl H Ar headerfile"
+.It Fl H Ar headerfile
+Handle external metadata
 .It Fl s Ar oldsize
 The size of the provider before it was resized.
 .El
@@ -764,6 +786,9 @@
 # dd if=/dev/random of=/dev/da1s3a bs=1m
 # dd if=/dev/random of=/boot/keys/da1s3a.key bs=128k count=1
 # geli init -b -P -K /boot/keys/da1s3a.key da1s3a
+# dd if=/dev/random of=/dev/ada1 bs=1m
+# dd if=/dev/random of=/boot/keys/ada1.key bs=8 count=8
+# geli init -b -H /boot/hd/ada1.hd -P -K /boot/keys/ada1.key ada1
 .Ed
 .Pp
 The providers are initialized, now we have to add those lines to
@@ -782,6 +807,13 @@
 geli_da1s3a_keyfile0_load="YES"
 geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0"
 geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key"
+
+geli_ada1_header_load="YES"
+geli_ada1_header_type="ada1:geli_header"
+geli_ada1_header_name="/boot/hd/ada1.hd"
+geli_ada1_keyfile0_load="YES"
+geli_ada1_keyfile0_type="ada1:geli_keyfile0"
+geli_ada1_keyfile0_name="/boot/keys/ada1.key"
 .Ed
 .Pp
 Not only configure encryption, but also data integrity verification using
--- sys/geom/eli/g_eli_ctl.c.orig	2013-05-04 01:21:45.381136674 +0300
+++ sys/geom/eli/g_eli_ctl.c	2013-05-05 03:20:20.180243224 +0300
@@ -56,10 +56,11 @@
 	struct g_eli_metadata md;
 	struct g_provider *pp;
 	const char *name;
-	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
+	u_char *key, *hd, mkey[G_ELI_DATAIVKEYLEN];
 	int *nargs, *detach, *readonly;
 	int keysize, error;
 	u_int nkey;
+	ssize_t hdsize;
 
 	g_topology_assert();
 
@@ -97,11 +98,18 @@
 		gctl_error(req, "Provider %s is invalid.", name);
 		return;
 	}
-	error = g_eli_read_metadata(mp, pp, &md);
-	if (error != 0) {
-		gctl_error(req, "Cannot read metadata from %s (error=%d).",
-		    name, error);
-		return;
+
+	hd = gctl_get_param(req, "hd", &hdsize);
+
+	if(hdsize == pp->sectorsize) {
+		eli_metadata_decode(hd, &md);
+	} else {
+		error = g_eli_read_metadata(mp, pp, &md);
+		if (error != 0) {
+			gctl_error(req, "Cannot read metadata from %s (error=%d).",
+				name, error);
+			return;
+		}
 	}
 	if (md.md_keys == 0x00) {
 		bzero(&md, sizeof(md));
@@ -448,8 +456,8 @@
 		error = g_eli_read_metadata(mp, pp, &md);
 		if (error != 0) {
 			gctl_error(req,
-			    "Cannot read metadata from %s (error=%d).",
-			    prov, error);
+				"Cannot read metadata from %s (error=%d).",
+				prov, error);
 			continue;
 		}
 
@@ -464,12 +472,13 @@
 		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);
+			pp->sectorsize);
 		if (error != 0) {
 			gctl_error(req,
-			    "Cannot store metadata on %s (error=%d).",
-			    prov, error);
+				"Cannot store metadata on %s (error=%d).",
+				prov, error);
 		}
+		
 		bzero(&md, sizeof(md));
 		bzero(sector, sizeof(sector));
 		free(sector, M_ELI);
@@ -815,9 +824,10 @@
 	struct g_provider *pp;
 	struct g_consumer *cp;
 	const char *name;
-	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
+	u_char *key, *hd, mkey[G_ELI_DATAIVKEYLEN];
 	int *nargs, keysize, error;
 	u_int nkey;
+	ssize_t hdsize;
 
 	g_topology_assert();
 
@@ -843,12 +853,20 @@
 	}
 	cp = LIST_FIRST(&sc->sc_geom->consumer);
 	pp = cp->provider;
-	error = g_eli_read_metadata(mp, pp, &md);
-	if (error != 0) {
-		gctl_error(req, "Cannot read metadata from %s (error=%d).",
-		    name, error);
-		return;
+
+	hd = gctl_get_param(req, "hd", &hdsize);
+
+	if(hdsize == pp->sectorsize) {
+		eli_metadata_decode(hd, &md);
+	} else {
+		error = g_eli_read_metadata(mp, pp, &md);
+		if (error != 0) {
+			gctl_error(req, "Cannot read metadata from %s (error=%d).",
+				name, error);
+			return;
+		}
 	}
+
 	if (md.md_keys == 0x00) {
 		bzero(&md, sizeof(md));
 		gctl_error(req, "No valid keys on %s.", pp->name);
--- sys/geom/eli/g_eli.c.orig	2013-05-07 10:08:29.000000000 +0300
+++ sys/geom/eli/g_eli.c	2013-05-04 00:26:03.620416070 +0300
@@ -1013,6 +1013,47 @@
 	}
 }
 
+static int
+g_eli_header_load(struct g_eli_metadata *md, const char *provider)
+{
+	unsigned char *headfile, *data;
+	char *file, name[64];
+	size_t size;
+
+	snprintf(name, sizeof(name), "%s:geli_header", provider);
+	headfile = preload_search_by_type(name);
+	if (headfile == NULL)
+		return (1);
+
+	data = preload_fetch_addr(headfile);
+	if (data == NULL) {
+		G_ELI_DEBUG(0, "Cannot find header file data for %s.",
+				name);
+		return (1);
+	}
+
+	size = preload_fetch_size(headfile);
+	if (size == 0) {
+		G_ELI_DEBUG(0, "Cannot find header file size for %s.",
+				name);
+		return (1);
+	}
+
+	file = preload_search_info(headfile, MODINFO_NAME);
+	if (file == NULL) {
+		G_ELI_DEBUG(0, "Cannot find header file name for %s.",
+				name);
+		return (1);
+	}
+
+	G_ELI_DEBUG(1, "Loaded header %s for %s (type: %s).", file,
+			provider, name);
+
+	eli_metadata_decode(data, md);
+
+	return (0);
+}
+
 /*
  * Tasting is only made on boot.
  * We detect providers which should be attached before root is mounted.
@@ -1036,9 +1077,11 @@
 
 	G_ELI_DEBUG(3, "Tasting %s.", pp->name);
 
-	error = g_eli_read_metadata(mp, pp, &md);
-	if (error != 0)
-		return (NULL);
+	if(g_eli_header_load(&md, pp->name) != 0) {
+		error = g_eli_read_metadata(mp, pp, &md);
+		if (error != 0)
+			return (NULL);
+	}
 	gp = NULL;
 
 	if (strcmp(md.md_magic, G_ELI_MAGIC) != 0)

_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscribe@freebsd.org"


----- End forwarded message -----
Comment 6 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:00:50 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped