summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/geom/class/mirror/geom_mirror.c7
-rw-r--r--sbin/geom/class/mirror/gmirror.814
-rw-r--r--sys/geom/mirror/g_mirror.c6
-rw-r--r--sys/geom/mirror/g_mirror.h1
-rw-r--r--sys/geom/mirror/g_mirror_ctl.c23
5 files changed, 45 insertions, 6 deletions
diff --git a/sbin/geom/class/mirror/geom_mirror.c b/sbin/geom/class/mirror/geom_mirror.c
index 17cfccb..30f5f84 100644
--- a/sbin/geom/class/mirror/geom_mirror.c
+++ b/sbin/geom/class/mirror/geom_mirror.c
@@ -82,6 +82,13 @@ struct g_command class_commands[] = {
{ "deactivate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
"[-v] name prov ..."
},
+ { "destroy", G_FLAG_VERBOSE, NULL,
+ {
+ { 'f', "force", NULL, G_TYPE_BOOL },
+ G_OPT_SENTINEL
+ },
+ "[-fv] name ..."
+ },
{ "dump", 0, mirror_main, G_NULL_OPTS,
"prov ..."
},
diff --git a/sbin/geom/class/mirror/gmirror.8 b/sbin/geom/class/mirror/gmirror.8
index cabeac6..bb48eca 100644
--- a/sbin/geom/class/mirror/gmirror.8
+++ b/sbin/geom/class/mirror/gmirror.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 20, 2013
+.Dd December 27, 2013
.Dt GMIRROR 8
.Os
.Sh NAME
@@ -86,6 +86,10 @@
.Ar name
.Ar prov ...
.Nm
+.Cm destroy
+.Op Fl fv
+.Ar name ...
+.Nm
.Cm forget
.Op Fl v
.Ar name ...
@@ -227,6 +231,14 @@ Activate the given component(s), which were marked as inactive before.
.It Cm deactivate
Mark the given component(s) as inactive, so it will not be automatically
connected to the mirror.
+.It Cm destroy
+Stop the given mirror and clear metadata on all its components.
+.Pp
+Additional options include:
+.Bl -tag -width ".Fl f"
+.It Fl f
+Stop the given mirror even if it is opened.
+.El
.It Cm forget
Forget about components which are not connected.
This command is useful when a disk has failed and cannot be reconnected, preventing the
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c
index 37d52c5..beb473f 100644
--- a/sys/geom/mirror/g_mirror.c
+++ b/sys/geom/mirror/g_mirror.c
@@ -642,7 +642,8 @@ g_mirror_write_metadata(struct g_mirror_disk *disk,
length = cp->provider->sectorsize;
offset = cp->provider->mediasize - length;
sector = malloc((size_t)length, M_MIRROR, M_WAITOK | M_ZERO);
- if (md != NULL) {
+ if (md != NULL &&
+ (sc->sc_flags & G_MIRROR_DEVICE_FLAG_WIPE) == 0) {
/*
* Handle the case, when the size of parent provider reduced.
*/
@@ -749,7 +750,8 @@ g_mirror_update_metadata(struct g_mirror_disk *disk)
sc = disk->d_softc;
sx_assert(&sc->sc_lock, SX_LOCKED);
- g_mirror_fill_metadata(sc, disk, &md);
+ if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_WIPE) == 0)
+ g_mirror_fill_metadata(sc, disk, &md);
error = g_mirror_write_metadata(disk, &md);
if (error == 0) {
G_MIRROR_DEBUG(2, "Metadata on %s updated.",
diff --git a/sys/geom/mirror/g_mirror.h b/sys/geom/mirror/g_mirror.h
index 96270c8..d203b97 100644
--- a/sys/geom/mirror/g_mirror.h
+++ b/sys/geom/mirror/g_mirror.h
@@ -160,6 +160,7 @@ struct g_mirror_event {
#define G_MIRROR_DEVICE_FLAG_WAIT 0x0200000000000000ULL
#define G_MIRROR_DEVICE_FLAG_DESTROYING 0x0400000000000000ULL
#define G_MIRROR_DEVICE_FLAG_TASTING 0x0800000000000000ULL
+#define G_MIRROR_DEVICE_FLAG_WIPE 0x1000000000000000ULL
#define G_MIRROR_DEVICE_STATE_STARTING 0
#define G_MIRROR_DEVICE_STATE_RUNNING 1
diff --git a/sys/geom/mirror/g_mirror_ctl.c b/sys/geom/mirror/g_mirror_ctl.c
index 1748d7b..2b56765 100644
--- a/sys/geom/mirror/g_mirror_ctl.c
+++ b/sys/geom/mirror/g_mirror_ctl.c
@@ -695,7 +695,7 @@ g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
const char *name;
char param[16];
int *nargs;
- u_int i;
+ u_int i, active;
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
if (nargs == NULL) {
@@ -716,6 +716,7 @@ g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No such device: %s.", name);
return;
}
+ active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
for (i = 1; i < (u_int)*nargs; i++) {
snprintf(param, sizeof(param), "arg%u", i);
name = gctl_get_asciiparam(req, param);
@@ -728,6 +729,16 @@ g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No such provider: %s.", name);
continue;
}
+ if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
+ if (active > 1)
+ active--;
+ else {
+ gctl_error(req, "%s: Can't deactivate the "
+ "last ACTIVE component %s.",
+ sc->sc_geom->name, name);
+ continue;
+ }
+ }
disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE;
disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
g_mirror_update_metadata(disk);
@@ -786,7 +797,7 @@ g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp)
}
static void
-g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp)
+g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe)
{
struct g_mirror_softc *sc;
int *force, *nargs, error;
@@ -827,10 +838,14 @@ g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp)
return;
}
g_cancel_event(sc);
+ if (wipe)
+ sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE;
error = g_mirror_destroy(sc, how);
if (error != 0) {
gctl_error(req, "Cannot destroy device %s (error=%d).",
sc->sc_geom->name, error);
+ if (wipe)
+ sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE;
sx_xunlock(&sc->sc_lock);
return;
}
@@ -871,7 +886,9 @@ g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb)
else if (strcmp(verb, "forget") == 0)
g_mirror_ctl_forget(req, mp);
else if (strcmp(verb, "stop") == 0)
- g_mirror_ctl_stop(req, mp);
+ g_mirror_ctl_stop(req, mp, 0);
+ else if (strcmp(verb, "destroy") == 0)
+ g_mirror_ctl_stop(req, mp, 1);
else
gctl_error(req, "Unknown verb.");
g_topology_lock();
OpenPOWER on IntegriCloud