summaryrefslogtreecommitdiffstats
path: root/sys/geom
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2014-01-10 07:48:36 +0000
committerae <ae@FreeBSD.org>2014-01-10 07:48:36 +0000
commit2865f87f4a69c49f910445fb5c56eca59e1790ee (patch)
tree964cf2da2e701ff218146655b4ecfec921925442 /sys/geom
parent5308ec580218db5152159128ab830fcdf297c82d (diff)
downloadFreeBSD-src-2865f87f4a69c49f910445fb5c56eca59e1790ee.zip
FreeBSD-src-2865f87f4a69c49f910445fb5c56eca59e1790ee.tar.gz
MFC r259634:
Prevent users from deactivating the last component of a mirror. MFC r259929: 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. PR: 184985
Diffstat (limited to 'sys/geom')
-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
3 files changed, 25 insertions, 5 deletions
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