From ae3bc0acff3ffc184a1eab4fb7d2c0f76f47e9e9 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Fri, 27 Dec 2013 02:43:53 +0000 Subject: [PATCH] Add an ability to stop gmirror and clear its metadata in one command. This fixes the problem, when gmirror starts again just after stop. The problem occurs when gmirror's component has geom label with equal size. E.g. gpt and gptid have the same size as partition, diskid has the same size as entire disk. When gmirror's geom has been destroyed, glabel creates its providers and this initiate retaste. Now "gmirror destroy" command is available. It destroys geom and also erases gmirror's metadata. MFC after: 2 weeks --- sbin/geom/class/mirror/geom_mirror.c | 7 +++++++ sbin/geom/class/mirror/gmirror.8 | 14 +++++++++++++- sys/geom/mirror/g_mirror.c | 6 ++++-- sys/geom/mirror/g_mirror.h | 1 + sys/geom/mirror/g_mirror_ctl.c | 10 ++++++++-- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/sbin/geom/class/mirror/geom_mirror.c b/sbin/geom/class/mirror/geom_mirror.c index 17cfccbd31b2..30f5f8494556 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 cabeac6c4854..bb48ecab7e31 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 37d52c52f94e..beb473fe08c5 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 96270c8bf2b7..d203b97b6392 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 29bc56c62c33..2b567652e0bb 100644 --- a/sys/geom/mirror/g_mirror_ctl.c +++ b/sys/geom/mirror/g_mirror_ctl.c @@ -797,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; @@ -838,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; } @@ -882,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();