Bug 184985

Summary: gmirror panic on deactivated mirror
Product: Base System Reporter: Kurt Lidl <lidl>
Component: kernAssignee: Andrey V. Elsukov <ae>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 9.2-RELEASE   
Hardware: Any   
OS: Any   

Description Kurt Lidl freebsd_committer freebsd_triage 2013-12-19 04:50:00 UTC
I have verified the following problem on both a virtual machine running 9.2-RELEASE,
as well as a virtual machine running 10.0-RC2.  (This problem was originally spotted
on a real machine, but it's been narrowed down using just virtual machines.)

The machine panics when 'gmirror status' is run after a gmirror is completely
deactivated.

The machine MUST have >1 CPU for the panic to occur.  With only a single processor on
the machine, the panic will not occur.

Panic looks like this under 10.0-RC2:
root@b524-fbsd10rc2:/var/crash # kgdb /boot/kernel/kernel vmcore.0
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "amd64-marcel-freebsd"...

Unread portion of the kernel message buffer:
GEOM_MIRROR: Device scratch: provider ada0p3 disconnected.
GEOM_MIRROR: Device scratch: provider mirror/scratch destroyed.
GEOM_MIRROR: Device scratch destroyed.


Fatal trap 12: page fault while in kernel mode
cpuid = 1; apic id = 01
fault virtual address	= 0x378
fault code		= supervisor read data, page not present
instruction pointer	= 0x20:0xffffffff808b78c6
stack pointer	        = 0x28:0xfffffe001ddfea10
frame pointer	        = 0x28:0xfffffe001ddfeab0
code segment		= base rx0, limit 0xfffff, type 0x1b
			= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags	= interrupt enabled, resume, IOPL = 0
current process		= 13 (g_event)
trap number		= 12
panic: page fault
cpuid = 1
KDB: stack backtrace:
#0 0xffffffff808e7d60 at kdb_backtrace+0x60
#1 0xffffffff808af845 at panic+0x155
#2 0xffffffff80c8e612 at trap_fatal+0x3a2
#3 0xffffffff80c8e8e9 at trap_pfault+0x2c9
#4 0xffffffff80c8e076 at trap+0x5e6
#5 0xffffffff80c75312 at calltrap+0x8
#6 0xffffffff808b7442 at _sx_xlock+0x62
#7 0xffffffff81a371bf at g_mirror_dumpconf+0x12f
#8 0xffffffff8081a35c at g_conf_specific+0x14c
#9 0xffffffff8081acd6 at g_run_events+0x166
#10 0xffffffff8088191a at fork_exit+0x9a
#11 0xffffffff80c7584e at fork_trampoline+0xe
Uptime: 33s
Dumping 78 out of 487 MB:..21%..41%..61%..82%

Reading symbols from /boot/kernel/zfs.ko.symbols...done.
Loaded symbols for /boot/kernel/zfs.ko.symbols
Reading symbols from /boot/kernel/opensolaris.ko.symbols...done.
Loaded symbols for /boot/kernel/opensolaris.ko.symbols
Reading symbols from /boot/kernel/geom_mirror.ko.symbols...done.
Loaded symbols for /boot/kernel/geom_mirror.ko.symbols
#0  doadump (textdump=<value optimized out>) at pcpu.h:219
219	pcpu.h: No such file or directory.
	in pcpu.h
(kgdb) bt
#0  doadump (textdump=<value optimized out>) at pcpu.h:219
#1  0xffffffff808af4c0 in kern_reboot (howto=260)
    at /usr/src/sys/kern/kern_shutdown.c:447
#2  0xffffffff808af884 in panic (fmt=<value optimized out>)
    at /usr/src/sys/kern/kern_shutdown.c:754
#3  0xffffffff80c8e612 in trap_fatal (frame=<value optimized out>, 
    eva=<value optimized out>) at /usr/src/sys/amd64/amd64/trap.c:882
#4  0xffffffff80c8e8e9 in trap_pfault (frame=0xfffffe001ddfe960, usermode=0)
    at /usr/src/sys/amd64/amd64/trap.c:699
#5  0xffffffff80c8e076 in trap (frame=0xfffffe001ddfe960)
    at /usr/src/sys/amd64/amd64/trap.c:463
#6  0xffffffff80c75312 in calltrap ()
    at /usr/src/sys/amd64/amd64/exception.S:232
#7  0xffffffff808b78c6 in _sx_xlock_hard (sx=0xfffff80018321240, 
    tid=18446735277652013056, opts=<value optimized out>, 
    file=0x2beff0 <Address 0x2beff0 out of bounds>, line=0)
    at /usr/src/sys/kern/kern_sx.c:556
#8  0xffffffff808b7442 in _sx_xlock (sx=0x2beff0, opts=0, 
    file=<value optimized out>, line=2879472) at sx.h:152
#9  0xffffffff81a371bf in g_mirror_dumpconf (sb=0xfffff80018310540, 
    indent=0xffffffff80ea9f7d "\t", gp=<value optimized out>, 
    cp=<value optimized out>, pp=<value optimized out>)
    at /usr/src/sys/modules/geom/geom_mirror/../../../geom/mirror/g_mirror.c:320---Type <return> to continue, or q <return> to quit--- 
2
#10 0xffffffff8081a35c in g_conf_specific (sb=0xfffff80018310540, mp=0x0, 
    gp=0x0, pp=0x0, cp=0x0) at /usr/src/sys/geom/geom_dump.c:238
#11 0xffffffff8081acd6 in g_run_events () at /usr/src/sys/geom/geom_event.c:257
#12 0xffffffff8088191a in fork_exit (
    callout=0xffffffff8081c8e0 <g_event_procbody>, arg=0x0, 
    frame=0xfffffe001ddfec00) at /usr/src/sys/kern/kern_fork.c:995
#13 0xffffffff80c7584e in fork_trampoline ()
    at /usr/src/sys/amd64/amd64/exception.S:606
#14 0x0000000000000000 in ?? ()
Current language:  auto; currently minimal
(kgdb)

How-To-Repeat: Assuming, an unused partition on /dev/ada0p3:

while :
do
  gmirror label -v scratch /dev/ada0p3
  newfs /dev/mirror/scratch
  mount /dev/mirror/scratch /mnt
  umount -f /mnt
  gmirror deactivate scratch /dev/ada0p3
  gmirror status scratch
done

The machine will panic on the final 'gmirror status scratch' command.
This happens 100% of the time on the first run through the loop on 9.2-RELEASE.
On 10.0-RC2, it may take two or three iterations of the loop before the panic.
Comment 1 Andrey V. Elsukov freebsd_committer freebsd_triage 2013-12-19 13:53:59 UTC
Responsible Changed
From-To: freebsd-bugs->ae

Take it.
Comment 2 dfilter service freebsd_committer freebsd_triage 2013-12-19 22:13:19 UTC
Author: ae
Date: Thu Dec 19 22:13:12 2013
New Revision: 259634
URL: http://svnweb.freebsd.org/changeset/base/259634

Log:
  Prevent users from deactivating the last component of a mirror.
  
  PR:		184985
  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	Thu Dec 19 21:35:33 2013	(r259633)
+++ head/sys/geom/mirror/g_mirror_ctl.c	Thu Dec 19 22:13:12 2013	(r259634)
@@ -695,7 +695,7 @@ g_mirror_ctl_deactivate(struct gctl_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) {
@@ -716,6 +716,7 @@ g_mirror_ctl_deactivate(struct gctl_req 
 		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 
 			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);
_______________________________________________
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 3 Andrey V. Elsukov freebsd_committer freebsd_triage 2013-12-19 22:13:30 UTC
State Changed
From-To: open->patched

Patched in head/. Thanks!
Comment 4 dfilter service freebsd_committer freebsd_triage 2014-01-10 07:48:45 UTC
Author: ae
Date: Fri Jan 10 07:48:36 2014
New Revision: 260503
URL: http://svnweb.freebsd.org/changeset/base/260503

Log:
  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

Modified:
  stable/10/sbin/geom/class/mirror/geom_mirror.c
  stable/10/sbin/geom/class/mirror/gmirror.8
  stable/10/sys/geom/mirror/g_mirror.c
  stable/10/sys/geom/mirror/g_mirror.h
  stable/10/sys/geom/mirror/g_mirror_ctl.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sbin/geom/class/mirror/geom_mirror.c
==============================================================================
--- stable/10/sbin/geom/class/mirror/geom_mirror.c	Fri Jan 10 07:43:40 2014	(r260502)
+++ stable/10/sbin/geom/class/mirror/geom_mirror.c	Fri Jan 10 07:48:36 2014	(r260503)
@@ -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 ..."
 	},

Modified: stable/10/sbin/geom/class/mirror/gmirror.8
==============================================================================
--- stable/10/sbin/geom/class/mirror/gmirror.8	Fri Jan 10 07:43:40 2014	(r260502)
+++ stable/10/sbin/geom/class/mirror/gmirror.8	Fri Jan 10 07:48:36 2014	(r260503)
@@ -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 w
 .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

Modified: stable/10/sys/geom/mirror/g_mirror.c
==============================================================================
--- stable/10/sys/geom/mirror/g_mirror.c	Fri Jan 10 07:43:40 2014	(r260502)
+++ stable/10/sys/geom/mirror/g_mirror.c	Fri Jan 10 07:48:36 2014	(r260503)
@@ -642,7 +642,8 @@ g_mirror_write_metadata(struct g_mirror_
 	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
 	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.",

Modified: stable/10/sys/geom/mirror/g_mirror.h
==============================================================================
--- stable/10/sys/geom/mirror/g_mirror.h	Fri Jan 10 07:43:40 2014	(r260502)
+++ stable/10/sys/geom/mirror/g_mirror.h	Fri Jan 10 07:48:36 2014	(r260503)
@@ -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

Modified: stable/10/sys/geom/mirror/g_mirror_ctl.c
==============================================================================
--- stable/10/sys/geom/mirror/g_mirror_ctl.c	Fri Jan 10 07:43:40 2014	(r260502)
+++ stable/10/sys/geom/mirror/g_mirror_ctl.c	Fri Jan 10 07:48:36 2014	(r260503)
@@ -695,7 +695,7 @@ g_mirror_ctl_deactivate(struct gctl_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) {
@@ -716,6 +716,7 @@ g_mirror_ctl_deactivate(struct gctl_req 
 		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 
 			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
 }
 
 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, 
 			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, st
 	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();
_______________________________________________
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 dfilter service freebsd_committer freebsd_triage 2014-01-10 12:09:47 UTC
Author: ae
Date: Fri Jan 10 12:09:38 2014
New Revision: 260507
URL: http://svnweb.freebsd.org/changeset/base/260507

Log:
  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

Modified:
  stable/9/sbin/geom/class/mirror/geom_mirror.c
  stable/9/sbin/geom/class/mirror/gmirror.8
  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/sbin/geom/class/mirror/   (props changed)
  stable/9/sys/   (props changed)

Modified: stable/9/sbin/geom/class/mirror/geom_mirror.c
==============================================================================
--- stable/9/sbin/geom/class/mirror/geom_mirror.c	Fri Jan 10 10:39:01 2014	(r260506)
+++ stable/9/sbin/geom/class/mirror/geom_mirror.c	Fri Jan 10 12:09:38 2014	(r260507)
@@ -80,6 +80,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 ..."
 	},

Modified: stable/9/sbin/geom/class/mirror/gmirror.8
==============================================================================
--- stable/9/sbin/geom/class/mirror/gmirror.8	Fri Jan 10 10:39:01 2014	(r260506)
+++ stable/9/sbin/geom/class/mirror/gmirror.8	Fri Jan 10 12:09:38 2014	(r260507)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 8, 2009
+.Dd December 27, 2013
 .Dt GMIRROR 8
 .Os
 .Sh NAME
@@ -81,6 +81,10 @@
 .Ar name
 .Ar prov ...
 .Nm
+.Cm destroy
+.Op Fl fv
+.Ar name ...
+.Nm
 .Cm forget
 .Op Fl v
 .Ar name ...
@@ -212,6 +216,14 @@ Activate the given component(s), which w
 .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

Modified: stable/9/sys/geom/mirror/g_mirror.c
==============================================================================
--- stable/9/sys/geom/mirror/g_mirror.c	Fri Jan 10 10:39:01 2014	(r260506)
+++ stable/9/sys/geom/mirror/g_mirror.c	Fri Jan 10 12:09:38 2014	(r260507)
@@ -638,7 +638,8 @@ g_mirror_write_metadata(struct g_mirror_
 	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)
 		mirror_metadata_encode(md, sector);
 	error = g_write_data(cp, offset, sector, length);
 	free(sector, M_MIRROR);
@@ -737,7 +738,8 @@ g_mirror_update_metadata(struct g_mirror
 	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.",

Modified: stable/9/sys/geom/mirror/g_mirror.h
==============================================================================
--- stable/9/sys/geom/mirror/g_mirror.h	Fri Jan 10 10:39:01 2014	(r260506)
+++ stable/9/sys/geom/mirror/g_mirror.h	Fri Jan 10 12:09:38 2014	(r260507)
@@ -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

Modified: stable/9/sys/geom/mirror/g_mirror_ctl.c
==============================================================================
--- stable/9/sys/geom/mirror/g_mirror_ctl.c	Fri Jan 10 10:39:01 2014	(r260506)
+++ stable/9/sys/geom/mirror/g_mirror_ctl.c	Fri Jan 10 12:09:38 2014	(r260507)
@@ -624,7 +624,7 @@ g_mirror_ctl_deactivate(struct gctl_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) {
@@ -645,6 +645,7 @@ g_mirror_ctl_deactivate(struct gctl_req 
 		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);
@@ -657,6 +658,16 @@ g_mirror_ctl_deactivate(struct gctl_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 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);
@@ -715,7 +726,7 @@ g_mirror_ctl_forget(struct gctl_req *req
 }
 
 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;
@@ -756,10 +767,14 @@ g_mirror_ctl_stop(struct gctl_req *req, 
 			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;
 		}
@@ -798,7 +813,9 @@ g_mirror_config(struct gctl_req *req, st
 	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();
_______________________________________________
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 6 Andrey V. Elsukov freebsd_committer freebsd_triage 2014-01-10 12:11:12 UTC
State Changed
From-To: patched->closed

Merged to stable/9 and stable/10.