summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2010-10-25 16:23:35 +0000
committerae <ae@FreeBSD.org>2010-10-25 16:23:35 +0000
commitf2e3b4bcd699858df3ffa6299abadfc23542cd78 (patch)
tree7922c1be74433f8b2df00417317645e73ea0a404 /sbin
parent92a9dc30a2b7193511b8724be22dee58f2a0f0ea (diff)
downloadFreeBSD-src-f2e3b4bcd699858df3ffa6299abadfc23542cd78.zip
FreeBSD-src-f2e3b4bcd699858df3ffa6299abadfc23542cd78.tar.gz
Reimplemented "gpart destroy -F". Now it does all work in kernel.
This was needed for recover implementation. Implement the recover command for GPT. Now GPT will marked as corrupt when any of three types of corruption will be detected: 1. Damaged primary GPT header or table 2. Damaged secondary GPT header or table 3. Secondary header is not located in the last LBA Marked GPT becomes read-only. Any changes with corrupt table are prohibited. Only "destroy" and "recover" commands are allowed. Discussed with: geom@ (mostly silence) Tested by: Ilya A. Arhipov Approved by: mav (mentor) MFC after: 2 weeks
Diffstat (limited to 'sbin')
-rw-r--r--sbin/geom/class/part/geom_part.c96
-rw-r--r--sbin/geom/class/part/gpart.887
2 files changed, 99 insertions, 84 deletions
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index 55db274..15bfa0b 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -67,7 +67,6 @@ static char ssize[32];
#define GPART_PARAM_BOOTCODE "bootcode"
#define GPART_PARAM_INDEX "index"
#define GPART_PARAM_PARTCODE "partcode"
-#define GPART_PARAM_FORCE "force"
static struct gclass *find_class(struct gmesh *, const char *);
static struct ggeom * find_geom(struct gclass *, const char *);
@@ -85,7 +84,6 @@ static void gpart_show_geom(struct ggeom *, const char *);
static int gpart_show_hasopt(struct gctl_req *, const char *, const char *);
static void gpart_write_partcode(struct ggeom *, int, void *, ssize_t);
static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *);
-static void gpart_destroy(struct gctl_req *, unsigned int);
static void gpart_print_error(const char *);
struct g_command PUBSYM(class_commands)[] = {
@@ -123,8 +121,8 @@ struct g_command PUBSYM(class_commands)[] = {
G_OPT_SENTINEL },
"-i index [-f flags] geom"
},
- { "destroy", 0, gpart_destroy, {
- { 'F', GPART_PARAM_FORCE, NULL, G_TYPE_BOOL },
+ { "destroy", 0, gpart_issue, {
+ { 'F', "force", NULL, G_TYPE_BOOL },
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
G_OPT_SENTINEL },
"[-F] [-f flags] geom"
@@ -167,6 +165,11 @@ struct g_command PUBSYM(class_commands)[] = {
G_OPT_SENTINEL },
"[-s size] -i index [-f flags] geom"
},
+ { "recover", 0, gpart_issue, {
+ { 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
+ G_OPT_SENTINEL },
+ "[-f flags] geom"
+ },
G_CMD_SENTINEL
};
@@ -539,13 +542,17 @@ gpart_show_geom(struct ggeom *gp, const char *element)
s = find_geomcfg(gp, "last");
last = (off_t)strtoimax(s, NULL, 0);
wblocks = strlen(s);
+ s = find_geomcfg(gp, "state");
+ if (s != NULL && *s != 'C')
+ s = NULL;
wname = strlen(gp->lg_name);
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
secsz = pp->lg_sectorsize;
- printf("=>%*jd %*jd %*s %s (%s)\n",
+ printf("=>%*jd %*jd %*s %s (%s)%s\n",
wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1),
wname, gp->lg_name,
- scheme, fmtsize(pp->lg_mediasize));
+ scheme, fmtsize(pp->lg_mediasize),
+ s ? " [CORRUPT]": "");
while ((pp = find_provider(gp, first)) != NULL) {
s = find_provcfg(pp, "start");
@@ -858,83 +865,6 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl)
}
static void
-gpart_destroy(struct gctl_req *req, unsigned int fl)
-{
- struct gmesh mesh;
- struct gclass *classp;
- struct gctl_req *req2;
- struct ggeom *gp;
- struct gprovider *pp;
- const char *s;
- int error, val;
- intmax_t idx;
-
- if (gctl_has_param(req, GPART_PARAM_FORCE)) {
- val = gctl_get_int(req, GPART_PARAM_FORCE);
- error = gctl_delete_param(req, GPART_PARAM_FORCE);
- if (error)
- errc(EXIT_FAILURE, error, "internal error");
- if (val == 0)
- goto done;
- s = gctl_get_ascii(req, "class");
- if (s == NULL)
- abort();
- error = geom_gettree(&mesh);
- if (error != 0)
- errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
- classp = find_class(&mesh, s);
- if (classp == NULL) {
- geom_deletetree(&mesh);
- errx(EXIT_FAILURE, "Class %s not found.", s);
- }
- s = gctl_get_ascii(req, "arg0");
- if (s == NULL)
- abort();
- gp = find_geom(classp, s);
- if (gp == NULL)
- errx(EXIT_FAILURE, "No such geom: %s.", s);
- val = 0;
- LIST_FOREACH(pp, &gp->lg_provider, lg_provider){
- s = find_provcfg(pp, "index");
- if (s == NULL)
- errx(EXIT_FAILURE, "Index not found for %s.",
- pp->lg_name);
- idx = strtoimax(s, NULL, 0);
- req2 = gctl_get_handle();
- gctl_ro_param(req2, "class", -1, classp->lg_name);
- gctl_ro_param(req2, "arg0", -1, gp->lg_name);
- gctl_ro_param(req2, "verb", -1, "delete");
- gctl_ro_param(req2, GPART_PARAM_INDEX,
- sizeof(intmax_t), &idx);
- gctl_ro_param(req2, "flags", -1, "X");
- s = gctl_issue(req2);
- if (s != NULL && s[0] != '\0') {
- gpart_print_error(s);
- gctl_free(req2);
- if (val) { /* try to undo changes */
- req2 = gctl_get_handle();
- gctl_ro_param(req2, "verb", -1,
- "undo");
- gctl_ro_param(req2, "class", -1,
- classp->lg_name);
- gctl_ro_param(req2, "arg0", -1,
- gp->lg_name);
- gctl_issue(req2);
- gctl_free(req2);
- }
- geom_deletetree(&mesh);
- exit(EXIT_FAILURE);
- }
- gctl_free(req2);
- val = 1;
- }
- geom_deletetree(&mesh);
- }
-done:
- gpart_issue(req, fl);
-}
-
-static void
gpart_print_error(const char *errstr)
{
char *errmsg;
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index cb9b5c9..f01e56a 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 28, 2010
+.Dd October 25, 2010
.Dt GPART 8
.Os
.Sh NAME
@@ -129,6 +129,11 @@ utility:
.Op Fl t Ar type
.Op Fl f Ar flags
.Ar geom
+.\" ==== RECOVER ====
+.Nm
+.Cm recover
+.Op Fl f Ar flags
+.Ar geom
.\" ==== RESIZE ====
.Nm
.Cm resize
@@ -353,6 +358,23 @@ See the section entitled
below for a discussion
about its use.
.El
+.\" ==== RECOVER ====
+.It Cm recover
+Recover corrupt partition's scheme metadata on the geom
+.Ar geom .
+See the section entitled
+.Sx "RECOVERING"
+below for the additional information.
+.Pp
+Additional options include:
+.Bl -tag -width 10n
+.It Fl f Ar flags
+Additional operational flags.
+See the section entitled
+.Sx "OPERATIONAL FLAGS"
+below for a discussion
+about its use.
+.El
.\" ==== RESIZE ====
.It Cm resize
Resize a partition from geom
@@ -629,6 +651,68 @@ the
action or reverted with the
.Cm undo
action.
+.Sh RECOVERING
+The GEOM class PART supports recovering of partition tables only for GPT.
+The GUID partition table has a primary and secondary (backup) copy of
+metadata for redundance. They are stored in the begining and in the end
+of device respectively. Therefore it is acceptable to have some corruptions
+in the metadata that are not fatal to work with GPT. When kernel detects
+corrupt metadata it marks this table as corrupt and reports about corruption.
+Any changes in corrupt table are prohibited except
+.Cm destroy
+and
+.Cm recover .
+.Pp
+In case when only first sector is corrupt kernel can not detect GPT even
+if partition table is not corrupt. You can write protective MBR with
+.Xr dd 1
+command to restore ability of GPT detection. The copy of protective MBR is
+usually located in the
+.Pa /boot/pmbr
+file.
+.Pp
+In case when some of metadata is corrupt you will get to know about this
+from kernel's messages like these:
+.Bd -literal -offset indent
+GEOM: provider: the primary GPT table is corrupt or invalid.
+GEOM: provider: using the secondary instead -- recovery strongly advised.
+.Ed
+.Pp
+or
+.Bd -literal -offset indent
+GEOM: provider: the secondary GPT table is corrupt or invalid.
+GEOM: provider: using the primary only -- recovery suggested.
+.Ed
+.Pp
+Also
+.Cm gpart
+commands like
+.Cm show ,
+.Cm status
+and
+.Cm list
+will report about corrupt table.
+.Pp
+In case when the size of device has changed (e.g. volume expansion) the
+secondary GPT header will become located not in the last sector. This is
+not a metadata corruption, but it is dangerous because any corruption of
+the primary GPT will lead to lost of partition table. Kernel reports about
+this problem with message:
+.Bd -literal -offset indent
+GEOM: provider: the secondary GPT header is not in the last LBA.
+.Ed
+.Pp
+A corrupt table can be recovered with
+.Cm gpart recover
+command. This command does reconstruction of corrupt metadata using
+known valid metadata. Also it can relocate secondary GPT to the end of
+device.
+.Pp
+.Pa NOTE :
+The GEOM class PART can detect the same partition table on different GEOM
+providers and some of them will marked as corrupt. Be careful when choising
+a provider for recovering. If you did incorrect choise you can destroy
+metadata of another GEOM class, e.g. GEOM MIRROR or GEOM LABEL.
.Sh EXIT STATUS
Exit status is 0 on success, and 1 if the command fails.
.Sh EXAMPLES
@@ -687,6 +771,7 @@ After having created all required partitions, embed bootstrap code into them.
/sbin/gpart bootcode -p /boot/boot1 da0
.Ed
.Sh SEE ALSO
+.Xr dd 1 ,
.Xr geom 4 ,
.Xr geom 8
.Sh HISTORY
OpenPOWER on IntegriCloud