diff options
-rw-r--r-- | sbin/geom/class/mirror/geom_mirror.c | 7 | ||||
-rw-r--r-- | sbin/geom/class/mirror/gmirror.8 | 14 | ||||
-rw-r--r-- | sys/geom/mirror/g_mirror.c | 6 | ||||
-rw-r--r-- | sys/geom/mirror/g_mirror.h | 1 | ||||
-rw-r--r-- | sys/geom/mirror/g_mirror_ctl.c | 23 |
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(); |