Bug 154860

Summary: gmirror(8): [panic] geom_mirror panices system on specific sector contents
Product: Base System Reporter: Eugene Grosbein <ports>
Component: kernAssignee: Andrey V. Elsukov <ae>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 8.2-PRERELEASE   
Hardware: Any   
OS: Any   

Description Eugene Grosbein 2011-02-18 09:20:10 UTC
	My 8.2-PRERELEASE/amd64 system has two HDDs:
	ad8 and ad14 having equal sector number:

# atacontrol cap ad8

Protocol              SATA revision 2.x
device model          WDC WD3200AAJS-00L7A0
serial number         WD-WMAV2DP22862
firmware revision     01.03E01
cylinders             16383
heads                 16
sectors/track         63
lba supported         268435455 sectors
lba48 supported       625142448 sectors

	Both disks were combined to one gmirror /dev/mirror/gm0.
	After unclean system shutdown this mirror became dirty
	and started rebuilding process from ad8 to ad14.
	Meantime, background fsck started to repair /usr/local
	and /home simultaneously (they are mounted in fstab by UFS labels).

	I/O contention was high so I decided to remove ad14 from the mirror
	to speedup fsck hoping reinsert ad14 to the mirror later:

gmirror remove gm0 ad14

	Immediately I've got kernel panic and system rebooted at once.
	Then it paniced again just at the moment of gmirror initialization.
	And again, and again... So I was forced to use loader
	to disable loading of geom_mirror.ko and go to single user mode
	mounting root from ad14.

	I've attempted to load geom_mirror.ko from single user mode
	and it panices the system at once.

	So I've saved contents of last sector of ad8 and ad14 to files.
	Last sector of ad14 contained only zero bytes. Last sector of ad8
	comes here gzipped and uuencoded.

begin 644 sector.gz
M'XL(`&8G7DT``W-W]?>ULO+U#`KR#V+X__\_"P,#0WJN`4,QIV$#D/L_8=>A
M!;_E+R\I/!>6S@B48P`3#`(,#$P,<5=;O4`<)A!1=H6%`0&8&'"`!(B>RR^8
<MW]9=E';:`-?=&/LV:,,HV!@``"LL=3X``(`````
`
end

	Then I've erased this sector with zeroes and this allowed
	me to load geom_mirror.ko without following panic
	and recreate my mirror.

Fix: 

Unknown.
How-To-Repeat: 
1. Perform unclean shutdown of system booting from gmirror to make it dirty.
2. After reboot, remove dirty component of gmirror (this paniced my system).
3. Then geom_mirror panices all the time until its signature erased from HDD.
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2011-02-19 05:53:17 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-geom

Over to maintainer(s).
Comment 2 Andrey V. Elsukov freebsd_committer freebsd_triage 2011-02-20 16:09:46 UTC
Responsible Changed
From-To: freebsd-geom->ae

Take it.
Comment 3 dfilter service freebsd_committer freebsd_triage 2012-05-18 10:19:21 UTC
Author: ae
Date: Fri May 18 09:19:07 2012
New Revision: 235599
URL: http://svn.freebsd.org/changeset/base/235599

Log:
  Introduce new device flag G_MIRROR_DEVICE_FLAG_TASTING. It should
  protect geom from destroying while it is tasting.
  
  PR:		kern/154860
  Reviewed by:	pjd
  MFC after:	1 week

Modified:
  head/sys/geom/mirror/g_mirror.c
  head/sys/geom/mirror/g_mirror.h

Modified: head/sys/geom/mirror/g_mirror.c
==============================================================================
--- head/sys/geom/mirror/g_mirror.c	Fri May 18 05:36:04 2012	(r235598)
+++ head/sys/geom/mirror/g_mirror.c	Fri May 18 09:19:07 2012	(r235599)
@@ -1693,6 +1693,8 @@ g_mirror_can_destroy(struct g_mirror_sof
 	gp = sc->sc_geom;
 	if (gp->softc == NULL)
 		return (1);
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_TASTING) != 0)
+		return (0);
 	LIST_FOREACH(cp, &gp->consumer, consumer) {
 		if (g_mirror_is_busy(sc, cp))
 			return (0);
@@ -3054,6 +3056,7 @@ g_mirror_taste(struct g_class *mp, struc
 	G_MIRROR_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
 	g_topology_unlock();
 	sx_xlock(&sc->sc_lock);
+	sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
 	error = g_mirror_add_disk(sc, pp, &md);
 	if (error != 0) {
 		G_MIRROR_DEBUG(0, "Cannot add disk %s to %s (error=%d).",
@@ -3066,6 +3069,12 @@ g_mirror_taste(struct g_class *mp, struc
 		}
 		gp = NULL;
 	}
+	sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
+		g_mirror_destroy(sc, G_MIRROR_DESTROY_HARD);
+		g_topology_lock();
+		return (NULL);
+	}
 	sx_xunlock(&sc->sc_lock);
 	g_topology_lock();
 	return (gp);

Modified: head/sys/geom/mirror/g_mirror.h
==============================================================================
--- head/sys/geom/mirror/g_mirror.h	Fri May 18 05:36:04 2012	(r235598)
+++ head/sys/geom/mirror/g_mirror.h	Fri May 18 09:19:07 2012	(r235599)
@@ -157,6 +157,7 @@ struct g_mirror_event {
 #define	G_MIRROR_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
 #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_STATE_STARTING		0
 #define	G_MIRROR_DEVICE_STATE_RUNNING		1
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 4 dfilter service freebsd_committer freebsd_triage 2012-05-18 10:22:32 UTC
Author: ae
Date: Fri May 18 09:22:21 2012
New Revision: 235600
URL: http://svn.freebsd.org/changeset/base/235600

Log:
  Prevent removing of the last active component from a mirror.
  
  PR:		kern/154860
  Reviewed by:	pjd
  MFC after:	1 week

Modified:
  head/sys/geom/mirror/g_mirror_ctl.c

Modified: head/sys/geom/mirror/g_mirror_ctl.c
==============================================================================
--- head/sys/geom/mirror/g_mirror_ctl.c	Fri May 18 09:19:07 2012	(r235599)
+++ head/sys/geom/mirror/g_mirror_ctl.c	Fri May 18 09:22:21 2012	(r235600)
@@ -560,7 +560,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 	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) {
@@ -587,6 +587,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 		    "first.");
 		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);
@@ -599,6 +600,16 @@ g_mirror_ctl_remove(struct gctl_req *req
 			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 remove the last "
+				    "ACTIVE component %s.", sc->sc_geom->name,
+				    name);
+				continue;
+			}
+		}
 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
 		    G_MIRROR_EVENT_DONTWAIT);
 	}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 5 Andrey V. Elsukov freebsd_committer freebsd_triage 2012-05-18 10:27:38 UTC
State Changed
From-To: open->patched

Patched in head/. Thanks!
Comment 6 dfilter service freebsd_committer freebsd_triage 2012-05-25 05:26:31 UTC
Author: ae
Date: Fri May 25 04:26:14 2012
New Revision: 235968
URL: http://svn.freebsd.org/changeset/base/235968

Log:
  MFC r235599:
    Introduce new device flag G_MIRROR_DEVICE_FLAG_TASTING. It should
    protect geom from destroying while it is tasting.
  
  MFC r235600:
    Prevent removing of the last active component from a mirror.
  
  PR:		kern/154860
  Reviewed by:	pjd
  Tested by:	Eugene Grosbein

Modified:
  stable/9/sys/geom/mirror/g_mirror.c
  stable/9/sys/geom/mirror/g_mirror.h
  stable/9/sys/geom/mirror/g_mirror_ctl.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/geom/mirror/g_mirror.c
==============================================================================
--- stable/9/sys/geom/mirror/g_mirror.c	Fri May 25 03:46:56 2012	(r235967)
+++ stable/9/sys/geom/mirror/g_mirror.c	Fri May 25 04:26:14 2012	(r235968)
@@ -1692,6 +1692,8 @@ g_mirror_can_destroy(struct g_mirror_sof
 	gp = sc->sc_geom;
 	if (gp->softc == NULL)
 		return (1);
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_TASTING) != 0)
+		return (0);
 	LIST_FOREACH(cp, &gp->consumer, consumer) {
 		if (g_mirror_is_busy(sc, cp))
 			return (0);
@@ -3053,6 +3055,7 @@ g_mirror_taste(struct g_class *mp, struc
 	G_MIRROR_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
 	g_topology_unlock();
 	sx_xlock(&sc->sc_lock);
+	sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
 	error = g_mirror_add_disk(sc, pp, &md);
 	if (error != 0) {
 		G_MIRROR_DEBUG(0, "Cannot add disk %s to %s (error=%d).",
@@ -3065,6 +3068,12 @@ g_mirror_taste(struct g_class *mp, struc
 		}
 		gp = NULL;
 	}
+	sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
+		g_mirror_destroy(sc, G_MIRROR_DESTROY_HARD);
+		g_topology_lock();
+		return (NULL);
+	}
 	sx_xunlock(&sc->sc_lock);
 	g_topology_lock();
 	return (gp);

Modified: stable/9/sys/geom/mirror/g_mirror.h
==============================================================================
--- stable/9/sys/geom/mirror/g_mirror.h	Fri May 25 03:46:56 2012	(r235967)
+++ stable/9/sys/geom/mirror/g_mirror.h	Fri May 25 04:26:14 2012	(r235968)
@@ -157,6 +157,7 @@ struct g_mirror_event {
 #define	G_MIRROR_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
 #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_STATE_STARTING		0
 #define	G_MIRROR_DEVICE_STATE_RUNNING		1

Modified: stable/9/sys/geom/mirror/g_mirror_ctl.c
==============================================================================
--- stable/9/sys/geom/mirror/g_mirror_ctl.c	Fri May 25 03:46:56 2012	(r235967)
+++ stable/9/sys/geom/mirror/g_mirror_ctl.c	Fri May 25 04:26:14 2012	(r235968)
@@ -560,7 +560,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 	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) {
@@ -587,6 +587,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 		    "first.");
 		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);
@@ -599,6 +600,16 @@ g_mirror_ctl_remove(struct gctl_req *req
 			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 remove the last "
+				    "ACTIVE component %s.", sc->sc_geom->name,
+				    name);
+				continue;
+			}
+		}
 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
 		    G_MIRROR_EVENT_DONTWAIT);
 	}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 7 dfilter service freebsd_committer freebsd_triage 2012-05-25 05:27:06 UTC
Author: ae
Date: Fri May 25 04:26:44 2012
New Revision: 235969
URL: http://svn.freebsd.org/changeset/base/235969

Log:
  MFC r235599:
    Introduce new device flag G_MIRROR_DEVICE_FLAG_TASTING. It should
    protect geom from destroying while it is tasting.
  
  MFC r235600:
    Prevent removing of the last active component from a mirror.
  
  PR:		kern/154860
  Reviewed by:	pjd
  Tested by:	Eugene Grosbein

Modified:
  stable/8/sys/geom/mirror/g_mirror.c
  stable/8/sys/geom/mirror/g_mirror.h
  stable/8/sys/geom/mirror/g_mirror_ctl.c
Directory Properties:
  stable/8/sys/   (props changed)

Modified: stable/8/sys/geom/mirror/g_mirror.c
==============================================================================
--- stable/8/sys/geom/mirror/g_mirror.c	Fri May 25 04:26:14 2012	(r235968)
+++ stable/8/sys/geom/mirror/g_mirror.c	Fri May 25 04:26:44 2012	(r235969)
@@ -1690,6 +1690,8 @@ g_mirror_can_destroy(struct g_mirror_sof
 	gp = sc->sc_geom;
 	if (gp->softc == NULL)
 		return (1);
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_TASTING) != 0)
+		return (0);
 	LIST_FOREACH(cp, &gp->consumer, consumer) {
 		if (g_mirror_is_busy(sc, cp))
 			return (0);
@@ -3051,6 +3053,7 @@ g_mirror_taste(struct g_class *mp, struc
 	G_MIRROR_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
 	g_topology_unlock();
 	sx_xlock(&sc->sc_lock);
+	sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
 	error = g_mirror_add_disk(sc, pp, &md);
 	if (error != 0) {
 		G_MIRROR_DEBUG(0, "Cannot add disk %s to %s (error=%d).",
@@ -3063,6 +3066,12 @@ g_mirror_taste(struct g_class *mp, struc
 		}
 		gp = NULL;
 	}
+	sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
+		g_mirror_destroy(sc, G_MIRROR_DESTROY_HARD);
+		g_topology_lock();
+		return (NULL);
+	}
 	sx_xunlock(&sc->sc_lock);
 	g_topology_lock();
 	return (gp);

Modified: stable/8/sys/geom/mirror/g_mirror.h
==============================================================================
--- stable/8/sys/geom/mirror/g_mirror.h	Fri May 25 04:26:14 2012	(r235968)
+++ stable/8/sys/geom/mirror/g_mirror.h	Fri May 25 04:26:44 2012	(r235969)
@@ -157,6 +157,7 @@ struct g_mirror_event {
 #define	G_MIRROR_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
 #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_STATE_STARTING		0
 #define	G_MIRROR_DEVICE_STATE_RUNNING		1

Modified: stable/8/sys/geom/mirror/g_mirror_ctl.c
==============================================================================
--- stable/8/sys/geom/mirror/g_mirror_ctl.c	Fri May 25 04:26:14 2012	(r235968)
+++ stable/8/sys/geom/mirror/g_mirror_ctl.c	Fri May 25 04:26:44 2012	(r235969)
@@ -560,7 +560,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 	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) {
@@ -587,6 +587,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 		    "first.");
 		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);
@@ -599,6 +600,16 @@ g_mirror_ctl_remove(struct gctl_req *req
 			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 remove the last "
+				    "ACTIVE component %s.", sc->sc_geom->name,
+				    name);
+				continue;
+			}
+		}
 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
 		    G_MIRROR_EVENT_DONTWAIT);
 	}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 8 Andrey V. Elsukov freebsd_committer freebsd_triage 2012-05-25 05:27:34 UTC
State Changed
From-To: patched->closed

Merged to stable/[7-9]. Thanks!
Comment 9 dfilter service freebsd_committer freebsd_triage 2012-05-25 05:27:39 UTC
Author: ae
Date: Fri May 25 04:27:08 2012
New Revision: 235970
URL: http://svn.freebsd.org/changeset/base/235970

Log:
  MFC r235599:
    Introduce new device flag G_MIRROR_DEVICE_FLAG_TASTING. It should
    protect geom from destroying while it is tasting.
  
  MFC r235600:
    Prevent removing of the last active component from a mirror.
  
  PR:		kern/154860
  Reviewed by:	pjd
  Tested by:	Eugene Grosbein

Modified:
  stable/7/sys/geom/mirror/g_mirror.c
  stable/7/sys/geom/mirror/g_mirror.h
  stable/7/sys/geom/mirror/g_mirror_ctl.c
Directory Properties:
  stable/7/sys/   (props changed)

Modified: stable/7/sys/geom/mirror/g_mirror.c
==============================================================================
--- stable/7/sys/geom/mirror/g_mirror.c	Fri May 25 04:26:44 2012	(r235969)
+++ stable/7/sys/geom/mirror/g_mirror.c	Fri May 25 04:27:08 2012	(r235970)
@@ -1690,6 +1690,8 @@ g_mirror_can_destroy(struct g_mirror_sof
 	gp = sc->sc_geom;
 	if (gp->softc == NULL)
 		return (1);
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_TASTING) != 0)
+		return (0);
 	LIST_FOREACH(cp, &gp->consumer, consumer) {
 		if (g_mirror_is_busy(sc, cp))
 			return (0);
@@ -3041,6 +3043,7 @@ g_mirror_taste(struct g_class *mp, struc
 	G_MIRROR_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
 	g_topology_unlock();
 	sx_xlock(&sc->sc_lock);
+	sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
 	error = g_mirror_add_disk(sc, pp, &md);
 	if (error != 0) {
 		G_MIRROR_DEBUG(0, "Cannot add disk %s to %s (error=%d).",
@@ -3053,6 +3056,12 @@ g_mirror_taste(struct g_class *mp, struc
 		}
 		gp = NULL;
 	}
+	sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
+	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
+		g_mirror_destroy(sc, G_MIRROR_DESTROY_HARD);
+		g_topology_lock();
+		return (NULL);
+	}
 	sx_xunlock(&sc->sc_lock);
 	g_topology_lock();
 	return (gp);

Modified: stable/7/sys/geom/mirror/g_mirror.h
==============================================================================
--- stable/7/sys/geom/mirror/g_mirror.h	Fri May 25 04:26:44 2012	(r235969)
+++ stable/7/sys/geom/mirror/g_mirror.h	Fri May 25 04:27:08 2012	(r235970)
@@ -157,6 +157,7 @@ struct g_mirror_event {
 #define	G_MIRROR_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
 #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_STATE_STARTING		0
 #define	G_MIRROR_DEVICE_STATE_RUNNING		1

Modified: stable/7/sys/geom/mirror/g_mirror_ctl.c
==============================================================================
--- stable/7/sys/geom/mirror/g_mirror_ctl.c	Fri May 25 04:26:44 2012	(r235969)
+++ stable/7/sys/geom/mirror/g_mirror_ctl.c	Fri May 25 04:27:08 2012	(r235970)
@@ -560,7 +560,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 	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) {
@@ -587,6 +587,7 @@ g_mirror_ctl_remove(struct gctl_req *req
 		    "first.");
 		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);
@@ -599,6 +600,16 @@ g_mirror_ctl_remove(struct gctl_req *req
 			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 remove the last "
+				    "ACTIVE component %s.", sc->sc_geom->name,
+				    name);
+				continue;
+			}
+		}
 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
 		    G_MIRROR_EVENT_DONTWAIT);
 	}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"