xref: /freebsd/sys/geom/mirror/g_mirror_ctl.c (revision 792bbaba989533a1fc93823df1720c8c4aaf0442)
1 /*-
2  * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/limits.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/bio.h>
38 #include <sys/sbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/malloc.h>
41 #include <sys/bitstring.h>
42 #include <vm/uma.h>
43 #include <machine/atomic.h>
44 #include <geom/geom.h>
45 #include <geom/geom_int.h>
46 #include <sys/proc.h>
47 #include <sys/kthread.h>
48 #include <geom/mirror/g_mirror.h>
49 
50 
51 static struct g_mirror_softc *
52 g_mirror_find_device(struct g_class *mp, const char *name)
53 {
54 	struct g_mirror_softc *sc;
55 	struct g_geom *gp;
56 
57 	g_topology_lock();
58 	LIST_FOREACH(gp, &mp->geom, geom) {
59 		sc = gp->softc;
60 		if (sc == NULL)
61 			continue;
62 		if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0)
63 			continue;
64 		if (strcmp(gp->name, name) == 0 ||
65 		    strcmp(sc->sc_name, name) == 0) {
66 			g_topology_unlock();
67 			sx_xlock(&sc->sc_lock);
68 			return (sc);
69 		}
70 	}
71 	g_topology_unlock();
72 	return (NULL);
73 }
74 
75 static struct g_mirror_disk *
76 g_mirror_find_disk(struct g_mirror_softc *sc, const char *name)
77 {
78 	struct g_mirror_disk *disk;
79 
80 	sx_assert(&sc->sc_lock, SX_XLOCKED);
81 	if (strncmp(name, "/dev/", 5) == 0)
82 		name += 5;
83 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
84 		if (disk->d_consumer == NULL)
85 			continue;
86 		if (disk->d_consumer->provider == NULL)
87 			continue;
88 		if (strcmp(disk->d_consumer->provider->name, name) == 0)
89 			return (disk);
90 	}
91 	return (NULL);
92 }
93 
94 static void
95 g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp)
96 {
97 	struct g_mirror_softc *sc;
98 	struct g_mirror_disk *disk;
99 	const char *name, *balancep, *prov;
100 	intmax_t *slicep, *priority;
101 	uint32_t slice;
102 	uint8_t balance;
103 	int *autosync, *noautosync, *failsync, *nofailsync, *hardcode, *dynamic;
104 	int *nargs, do_sync = 0, dirty = 1, do_priority = 0;
105 
106 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
107 	if (nargs == NULL) {
108 		gctl_error(req, "No '%s' argument.", "nargs");
109 		return;
110 	}
111 	if (*nargs != 1 && *nargs != 2) {
112 		gctl_error(req, "Invalid number of arguments.");
113 		return;
114 	}
115 	name = gctl_get_asciiparam(req, "arg0");
116 	if (name == NULL) {
117 		gctl_error(req, "No 'arg%u' argument.", 0);
118 		return;
119 	}
120 	balancep = gctl_get_asciiparam(req, "balance");
121 	if (balancep == NULL) {
122 		gctl_error(req, "No '%s' argument.", "balance");
123 		return;
124 	}
125 	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
126 	if (autosync == NULL) {
127 		gctl_error(req, "No '%s' argument.", "autosync");
128 		return;
129 	}
130 	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
131 	if (noautosync == NULL) {
132 		gctl_error(req, "No '%s' argument.", "noautosync");
133 		return;
134 	}
135 	failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync));
136 	if (failsync == NULL) {
137 		gctl_error(req, "No '%s' argument.", "failsync");
138 		return;
139 	}
140 	nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync));
141 	if (nofailsync == NULL) {
142 		gctl_error(req, "No '%s' argument.", "nofailsync");
143 		return;
144 	}
145 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
146 	if (hardcode == NULL) {
147 		gctl_error(req, "No '%s' argument.", "hardcode");
148 		return;
149 	}
150 	dynamic = gctl_get_paraml(req, "dynamic", sizeof(*dynamic));
151 	if (dynamic == NULL) {
152 		gctl_error(req, "No '%s' argument.", "dynamic");
153 		return;
154 	}
155 	priority = gctl_get_paraml(req, "priority", sizeof(*priority));
156 	if (priority == NULL) {
157 		gctl_error(req, "No '%s' argument.", "priority");
158 		return;
159 	}
160 	if (*priority < -1 || *priority > 255) {
161 		gctl_error(req, "Priority range is 0 to 255, %jd given",
162 		    *priority);
163 		return;
164 	}
165 	/*
166 	 * Since we have a priority, we also need a provider now.
167 	 * Note: be WARNS safe, by always assigning prov and only throw an
168 	 * error if *priority != -1.
169 	 */
170 	prov = gctl_get_asciiparam(req, "arg1");
171 	if (*priority > -1) {
172 		if (prov == NULL) {
173 			gctl_error(req, "Priority needs a disk name");
174 			return;
175 		}
176 		do_priority = 1;
177 	}
178 	if (*autosync && *noautosync) {
179 		gctl_error(req, "'%s' and '%s' specified.", "autosync",
180 		    "noautosync");
181 		return;
182 	}
183 	if (*failsync && *nofailsync) {
184 		gctl_error(req, "'%s' and '%s' specified.", "failsync",
185 		    "nofailsync");
186 		return;
187 	}
188 	if (*hardcode && *dynamic) {
189 		gctl_error(req, "'%s' and '%s' specified.", "hardcode",
190 		    "dynamic");
191 		return;
192 	}
193 	sc = g_mirror_find_device(mp, name);
194 	if (sc == NULL) {
195 		gctl_error(req, "No such device: %s.", name);
196 		return;
197 	}
198 	if (*balancep == '\0')
199 		balance = sc->sc_balance;
200 	else {
201 		if (balance_id(balancep) == -1) {
202 			gctl_error(req, "Invalid balance algorithm.");
203 			sx_xunlock(&sc->sc_lock);
204 			return;
205 		}
206 		balance = balance_id(balancep);
207 	}
208 	slicep = gctl_get_paraml(req, "slice", sizeof(*slicep));
209 	if (slicep == NULL) {
210 		gctl_error(req, "No '%s' argument.", "slice");
211 		sx_xunlock(&sc->sc_lock);
212 		return;
213 	}
214 	if (*slicep == -1)
215 		slice = sc->sc_slice;
216 	else
217 		slice = *slicep;
218 	/* Enforce usage() of -p not allowing any other options. */
219 	if (do_priority && (*autosync || *noautosync || *failsync ||
220 	    *nofailsync || *hardcode || *dynamic || *slicep != -1 ||
221 	    *balancep != '\0')) {
222 		sx_xunlock(&sc->sc_lock);
223 		gctl_error(req, "only -p accepted when setting priority");
224 		return;
225 	}
226 	if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync &&
227 	    !*noautosync && !*failsync && !*nofailsync && !*hardcode &&
228 	    !*dynamic && !do_priority) {
229 		sx_xunlock(&sc->sc_lock);
230 		gctl_error(req, "Nothing has changed.");
231 		return;
232 	}
233 	if ((!do_priority && *nargs != 1) || (do_priority && *nargs != 2)) {
234 		sx_xunlock(&sc->sc_lock);
235 		gctl_error(req, "Invalid number of arguments.");
236 		return;
237 	}
238 	if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
239 		sx_xunlock(&sc->sc_lock);
240 		gctl_error(req, "Not all disks connected. Try 'forget' command "
241 		    "first.");
242 		return;
243 	}
244 	sc->sc_balance = balance;
245 	sc->sc_slice = slice;
246 	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) {
247 		if (*autosync) {
248 			sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
249 			do_sync = 1;
250 		}
251 	} else {
252 		if (*noautosync)
253 			sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
254 	}
255 	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0) {
256 		if (*failsync)
257 			sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
258 	} else {
259 		if (*nofailsync) {
260 			sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
261 			dirty = 0;
262 		}
263 	}
264 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
265 		/*
266 		 * Handle priority first, since we only need one disk, do one
267 		 * operation on it and then we're done. No need to check other
268 		 * flags, as usage doesn't allow it.
269 		 */
270 		if (do_priority) {
271 			if (strcmp(disk->d_name, prov) == 0) {
272 				if (disk->d_priority == *priority)
273 					gctl_error(req, "Nothing has changed.");
274 				else {
275 					disk->d_priority = *priority;
276 					g_mirror_update_metadata(disk);
277 				}
278 				break;
279 			}
280 			continue;
281 		}
282 		if (do_sync) {
283 			if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING)
284 				disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
285 		}
286 		if (*hardcode)
287 			disk->d_flags |= G_MIRROR_DISK_FLAG_HARDCODED;
288 		else if (*dynamic)
289 			disk->d_flags &= ~G_MIRROR_DISK_FLAG_HARDCODED;
290 		if (!dirty)
291 			disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
292 		g_mirror_update_metadata(disk);
293 		if (do_sync) {
294 			if (disk->d_state == G_MIRROR_DISK_STATE_STALE) {
295 				g_mirror_event_send(disk,
296 				    G_MIRROR_DISK_STATE_DISCONNECTED,
297 				    G_MIRROR_EVENT_DONTWAIT);
298 			}
299 		}
300 	}
301 	sx_xunlock(&sc->sc_lock);
302 }
303 
304 static void
305 g_mirror_create_orphan(struct g_consumer *cp)
306 {
307 
308 	KASSERT(1 == 0, ("%s called while creating %s.", __func__,
309 	    cp->provider->name));
310 }
311 
312 static void
313 g_mirror_ctl_create(struct gctl_req *req, struct g_class *mp)
314 {
315 	struct g_mirror_metadata md;
316 	struct g_geom *gp;
317 	struct g_consumer *cp;
318 	struct g_provider *pp;
319 	struct g_mirror_softc *sc;
320 	struct sbuf *sb;
321 	const char *name;
322 	char param[16];
323 	int *nargs;
324 	intmax_t *val;
325 	int *ival;
326 	const char *sval;
327 	int bal;
328 	unsigned attached, no, sectorsize;
329 	off_t mediasize;
330 
331 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
332 	if (nargs == NULL) {
333 		gctl_error(req, "No '%s' argument.", "nargs");
334 		return;
335 	}
336 	if (*nargs <= 2) {
337 		gctl_error(req, "Too few arguments.");
338 		return;
339 	}
340 
341 	strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic));
342 	md.md_version = G_MIRROR_VERSION;
343 	name = gctl_get_asciiparam(req, "arg0");
344 	if (name == NULL) {
345 		gctl_error(req, "No 'arg%u' argument.", 0);
346 		return;
347 	}
348 	strlcpy(md.md_name, name, sizeof(md.md_name));
349 	md.md_mid = arc4random();
350 	md.md_all = *nargs - 1;
351 	md.md_genid = 0;
352 	md.md_syncid = 1;
353 	md.md_sync_offset = 0;
354 	val = gctl_get_paraml(req, "slice", sizeof(*val));
355 	if (val == NULL) {
356 		gctl_error(req, "No slice argument.");
357 		return;
358 	}
359 	md.md_slice = *val;
360 	sval = gctl_get_asciiparam(req, "balance");
361 	if (sval == NULL) {
362 		gctl_error(req, "No balance argument.");
363 		return;
364 	}
365 	bal = balance_id(sval);
366 	if (bal < 0) {
367 		gctl_error(req, "Invalid balance algorithm.");
368 		return;
369 	}
370 	md.md_balance = bal;
371 	md.md_mflags = 0;
372 	md.md_dflags = 0;
373 	ival = gctl_get_paraml(req, "noautosync", sizeof(*ival));
374 	if (ival != NULL && *ival)
375 		md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
376 	ival = gctl_get_paraml(req, "nofailsync", sizeof(*ival));
377 	if (ival != NULL && *ival)
378 		md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
379 	/* These fields not used in manual mode. */
380 	bzero(md.md_provider, sizeof(md.md_provider));
381 	md.md_provsize = 0;
382 
383 	g_topology_lock();
384 	mediasize = OFF_MAX;
385 	sectorsize = 0;
386 	gp = g_new_geomf(mp, "%s", md.md_name);
387 	gp->orphan = g_mirror_create_orphan;
388 	cp = g_new_consumer(gp);
389 	for (no = 1; no < *nargs; no++) {
390 		snprintf(param, sizeof(param), "arg%u", no);
391 		name = gctl_get_asciiparam(req, param);
392 		if (name == NULL) {
393 			gctl_error(req, "No 'arg%u' argument.", no);
394 err:
395 			g_destroy_consumer(cp);
396 			g_destroy_geom(gp);
397 			g_topology_unlock();
398 			return;
399 		}
400 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
401 			name += strlen("/dev/");
402 		pp = g_provider_by_name(name);
403 		if (pp == NULL) {
404 			G_MIRROR_DEBUG(1, "Disk %s is invalid.", name);
405 			gctl_error(req, "Disk %s is invalid.", name);
406 			goto err;
407 		}
408 		g_attach(cp, pp);
409 		if (g_access(cp, 1, 0, 0) != 0) {
410 			G_MIRROR_DEBUG(1, "Can't open disk %s.", name);
411 			gctl_error(req, "Can't open disk %s.", name);
412 err2:
413 			g_detach(cp);
414 			goto err;
415 		}
416 		if (pp->mediasize == 0 || pp->sectorsize == 0) {
417 			G_MIRROR_DEBUG(1, "Disk %s has no media.", name);
418 			gctl_error(req, "Disk %s has no media.", name);
419 			g_access(cp, -1, 0, 0);
420 			goto err2;
421 		}
422 		if (pp->mediasize < mediasize)
423 			mediasize = pp->mediasize;
424 		if (pp->sectorsize > sectorsize)
425 			sectorsize = pp->sectorsize;
426 		g_access(cp, -1, 0, 0);
427 		g_detach(cp);
428 	}
429 	g_destroy_consumer(cp);
430 	g_destroy_geom(gp);
431 	md.md_mediasize = mediasize;
432 	md.md_sectorsize = sectorsize;
433 	md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
434 
435 	gp = g_mirror_create(mp, &md, G_MIRROR_TYPE_MANUAL);
436 	if (gp == NULL) {
437 		gctl_error(req, "Can't create %s.", md.md_name);
438 		g_topology_unlock();
439 		return;
440 	}
441 
442 	sc = gp->softc;
443 	g_topology_unlock();
444 	sx_xlock(&sc->sc_lock);
445 	sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
446 	sb = sbuf_new_auto();
447 	sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name);
448 	for (attached = 0, no = 1; no < *nargs; no++) {
449 		snprintf(param, sizeof(param), "arg%u", no);
450 		name = gctl_get_asciiparam(req, param);
451 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
452 			name += strlen("/dev/");
453 		pp = g_provider_by_name(name);
454 		if (pp == NULL) {
455 			G_MIRROR_DEBUG(1, "Provider %s disappear?!", name);
456 			sbuf_printf(sb, " %s", name);
457 			continue;
458 		}
459 		md.md_did = arc4random();
460 		md.md_priority = no - 1;
461 		if (g_mirror_add_disk(sc, pp, &md) != 0) {
462 			G_MIRROR_DEBUG(1, "Disk %u (%s) not attached to %s.",
463 			    no, pp->name, gp->name);
464 			sbuf_printf(sb, " %s", pp->name);
465 			continue;
466 		}
467 		attached++;
468 	}
469 	sbuf_finish(sb);
470 	sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
471 	if (md.md_all != attached ||
472 	    (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
473 		g_mirror_destroy(gp->softc, G_MIRROR_DESTROY_HARD);
474 		gctl_error(req, "%s", sbuf_data(sb));
475 	} else
476 		sx_xunlock(&sc->sc_lock);
477 	sbuf_delete(sb);
478 }
479 
480 static void
481 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
482 {
483 	struct g_mirror_metadata md;
484 	struct g_mirror_softc *sc;
485 	struct g_mirror_disk *disk;
486 	struct g_provider *pp;
487 	const char *name;
488 	char param[16];
489 	int error, *nargs;
490 	u_int i;
491 
492 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
493 	if (nargs == NULL) {
494 		gctl_error(req, "No '%s' argument.", "nargs");
495 		return;
496 	}
497 	if (*nargs < 2) {
498 		gctl_error(req, "Too few arguments.");
499 		return;
500 	}
501 	name = gctl_get_asciiparam(req, "arg0");
502 	if (name == NULL) {
503 		gctl_error(req, "No 'arg%u' argument.", 0);
504 		return;
505 	}
506 	sc = g_mirror_find_device(mp, name);
507 	if (sc == NULL) {
508 		gctl_error(req, "No such device: %s.", name);
509 		return;
510 	}
511 	for (i = 1; i < (u_int)*nargs; i++) {
512 		snprintf(param, sizeof(param), "arg%u", i);
513 		name = gctl_get_asciiparam(req, param);
514 		if (name == NULL) {
515 			gctl_error(req, "No 'arg%u' argument.", i);
516 			continue;
517 		}
518 		disk = g_mirror_find_disk(sc, name);
519 		if (disk == NULL) {
520 			gctl_error(req, "No such provider: %s.", name);
521 			continue;
522 		}
523 		if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 &&
524 		    disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
525 			/*
526 			 * This is the last active disk. There will be nothing
527 			 * to rebuild it from, so deny this request.
528 			 */
529 			gctl_error(req,
530 			    "Provider %s is the last active provider in %s.",
531 			    name, sc->sc_geom->name);
532 			break;
533 		}
534 		/*
535 		 * Do rebuild by resetting syncid, disconnecting the disk and
536 		 * connecting it again.
537 		 */
538 		disk->d_sync.ds_syncid = 0;
539 		if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0)
540 			disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC;
541 		g_mirror_update_metadata(disk);
542 		pp = disk->d_consumer->provider;
543 		g_topology_lock();
544 		error = g_mirror_read_metadata(disk->d_consumer, &md);
545 		g_topology_unlock();
546 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
547 		    G_MIRROR_EVENT_WAIT);
548 		if (error != 0) {
549 			gctl_error(req, "Cannot read metadata from %s.",
550 			    pp->name);
551 			continue;
552 		}
553 		error = g_mirror_add_disk(sc, pp, &md);
554 		if (error != 0) {
555 			gctl_error(req, "Cannot reconnect component %s.",
556 			    pp->name);
557 			continue;
558 		}
559 	}
560 	sx_xunlock(&sc->sc_lock);
561 }
562 
563 static void
564 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp)
565 {
566 	struct g_mirror_softc *sc;
567 	struct g_mirror_disk *disk;
568 	struct g_mirror_metadata md;
569 	struct g_provider *pp;
570 	struct g_consumer *cp;
571 	intmax_t *priority;
572 	const char *name;
573 	char param[16];
574 	u_char *sector;
575 	u_int i, n;
576 	int error, *nargs, *hardcode, *inactive;
577 	struct {
578 		struct g_provider	*provider;
579 		struct g_consumer	*consumer;
580 	} *disks;
581 	off_t mdsize;
582 
583 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
584 	if (nargs == NULL) {
585 		gctl_error(req, "No '%s' argument.", "nargs");
586 		return;
587 	}
588 	if (*nargs < 2) {
589 		gctl_error(req, "Too few arguments.");
590 		return;
591 	}
592 	priority = gctl_get_paraml(req, "priority", sizeof(*priority));
593 	if (priority == NULL) {
594 		gctl_error(req, "No '%s' argument.", "priority");
595 		return;
596 	}
597 	inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive));
598 	if (inactive == NULL) {
599 		gctl_error(req, "No '%s' argument.", "inactive");
600 		return;
601 	}
602 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
603 	if (hardcode == NULL) {
604 		gctl_error(req, "No '%s' argument.", "hardcode");
605 		return;
606 	}
607 	name = gctl_get_asciiparam(req, "arg0");
608 	if (name == NULL) {
609 		gctl_error(req, "No 'arg%u' argument.", 0);
610 		return;
611 	}
612 	sc = g_mirror_find_device(mp, name);
613 	if (sc == NULL) {
614 		gctl_error(req, "No such device: %s.", name);
615 		return;
616 	}
617 	if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
618 		gctl_error(req, "Not all disks connected.");
619 		sx_xunlock(&sc->sc_lock);
620 		return;
621 	}
622 
623 	disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO);
624 	g_topology_lock();
625 	for (i = 1, n = 0; i < (u_int)*nargs; i++) {
626 		snprintf(param, sizeof(param), "arg%u", i);
627 		name = gctl_get_asciiparam(req, param);
628 		if (name == NULL) {
629 			gctl_error(req, "No 'arg%u' argument.", i);
630 			continue;
631 		}
632 		if (g_mirror_find_disk(sc, name) != NULL) {
633 			gctl_error(req, "Provider %s already inserted.", name);
634 			continue;
635 		}
636 		if (strncmp(name, "/dev/", 5) == 0)
637 			name += 5;
638 		pp = g_provider_by_name(name);
639 		if (pp == NULL) {
640 			gctl_error(req, "Unknown provider %s.", name);
641 			continue;
642 		}
643 		cp = g_new_consumer(sc->sc_geom);
644 		if (g_attach(cp, pp) != 0) {
645 			g_destroy_consumer(cp);
646 			gctl_error(req, "Cannot attach to provider %s.", name);
647 			continue;
648 		}
649 		if (g_access(cp, 0, 1, 1) != 0) {
650 			gctl_error(req, "Cannot access provider %s.", name);
651 err:
652 			g_detach(cp);
653 			g_destroy_consumer(cp);
654 			continue;
655 		}
656 		mdsize = (sc->sc_type == G_MIRROR_TYPE_AUTOMATIC) ?
657 		    pp->sectorsize : 0;
658 		if (sc->sc_provider->mediasize > pp->mediasize - mdsize) {
659 			gctl_error(req, "Provider %s too small.", name);
660 err2:
661 			g_access(cp, 0, -1, -1);
662 			goto err;
663 		}
664 		if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) {
665 			gctl_error(req, "Invalid sectorsize of provider %s.",
666 			    name);
667 			goto err2;
668 		}
669 		if (sc->sc_type != G_MIRROR_TYPE_AUTOMATIC) {
670 			g_access(cp, 0, -1, -1);
671 			g_detach(cp);
672 			g_destroy_consumer(cp);
673 			g_topology_unlock();
674 			sc->sc_ndisks++;
675 			g_mirror_fill_metadata(sc, NULL, &md);
676 			md.md_priority = *priority;
677 			if (*inactive)
678 				md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE;
679 			if (g_mirror_add_disk(sc, pp, &md) != 0) {
680 				sc->sc_ndisks--;
681 				gctl_error(req, "Disk %s not inserted.", name);
682 			}
683 			g_topology_lock();
684 			continue;
685 		}
686 		disks[n].provider = pp;
687 		disks[n].consumer = cp;
688 		n++;
689 	}
690 	if (n == 0) {
691 		g_topology_unlock();
692 		sx_xunlock(&sc->sc_lock);
693 		g_free(disks);
694 		return;
695 	}
696 	sc->sc_ndisks += n;
697 again:
698 	for (i = 0; i < n; i++) {
699 		if (disks[i].consumer == NULL)
700 			continue;
701 		g_mirror_fill_metadata(sc, NULL, &md);
702 		md.md_priority = *priority;
703 		if (*inactive)
704 			md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE;
705 		pp = disks[i].provider;
706 		if (*hardcode) {
707 			strlcpy(md.md_provider, pp->name,
708 			    sizeof(md.md_provider));
709 		} else {
710 			bzero(md.md_provider, sizeof(md.md_provider));
711 		}
712 		md.md_provsize = pp->mediasize;
713 		sector = g_malloc(pp->sectorsize, M_WAITOK);
714 		mirror_metadata_encode(&md, sector);
715 		error = g_write_data(disks[i].consumer,
716 		    pp->mediasize - pp->sectorsize, sector, pp->sectorsize);
717 		g_free(sector);
718 		if (error != 0) {
719 			gctl_error(req, "Cannot store metadata on %s.",
720 			    pp->name);
721 			g_access(disks[i].consumer, 0, -1, -1);
722 			g_detach(disks[i].consumer);
723 			g_destroy_consumer(disks[i].consumer);
724 			disks[i].consumer = NULL;
725 			disks[i].provider = NULL;
726 			sc->sc_ndisks--;
727 			goto again;
728 		}
729 	}
730 	g_topology_unlock();
731 	if (i == 0) {
732 		/* All writes failed. */
733 		sx_xunlock(&sc->sc_lock);
734 		g_free(disks);
735 		return;
736 	}
737 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
738 		g_mirror_update_metadata(disk);
739 	}
740 	/*
741 	 * Release provider and wait for retaste.
742 	 */
743 	g_topology_lock();
744 	for (i = 0; i < n; i++) {
745 		if (disks[i].consumer == NULL)
746 			continue;
747 		g_access(disks[i].consumer, 0, -1, -1);
748 		g_detach(disks[i].consumer);
749 		g_destroy_consumer(disks[i].consumer);
750 	}
751 	g_topology_unlock();
752 	sx_xunlock(&sc->sc_lock);
753 	g_free(disks);
754 }
755 
756 static void
757 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp)
758 {
759 	struct g_mirror_softc *sc;
760 	struct g_mirror_disk *disk;
761 	const char *name;
762 	char param[16];
763 	int *nargs;
764 	u_int i, active;
765 
766 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
767 	if (nargs == NULL) {
768 		gctl_error(req, "No '%s' argument.", "nargs");
769 		return;
770 	}
771 	if (*nargs < 2) {
772 		gctl_error(req, "Too few arguments.");
773 		return;
774 	}
775 	name = gctl_get_asciiparam(req, "arg0");
776 	if (name == NULL) {
777 		gctl_error(req, "No 'arg%u' argument.", 0);
778 		return;
779 	}
780 	sc = g_mirror_find_device(mp, name);
781 	if (sc == NULL) {
782 		gctl_error(req, "No such device: %s.", name);
783 		return;
784 	}
785 	if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
786 		sx_xunlock(&sc->sc_lock);
787 		gctl_error(req, "Not all disks connected. Try 'forget' command "
788 		    "first.");
789 		return;
790 	}
791 	active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
792 	for (i = 1; i < (u_int)*nargs; i++) {
793 		snprintf(param, sizeof(param), "arg%u", i);
794 		name = gctl_get_asciiparam(req, param);
795 		if (name == NULL) {
796 			gctl_error(req, "No 'arg%u' argument.", i);
797 			continue;
798 		}
799 		disk = g_mirror_find_disk(sc, name);
800 		if (disk == NULL) {
801 			gctl_error(req, "No such provider: %s.", name);
802 			continue;
803 		}
804 		if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
805 			if (active > 1)
806 				active--;
807 			else {
808 				gctl_error(req, "%s: Can't remove the last "
809 				    "ACTIVE component %s.", sc->sc_geom->name,
810 				    name);
811 				continue;
812 			}
813 		}
814 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
815 		    G_MIRROR_EVENT_DONTWAIT);
816 	}
817 	sx_xunlock(&sc->sc_lock);
818 }
819 
820 static void
821 g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp)
822 {
823 	struct g_mirror_softc *sc;
824 	struct g_mirror_disk *disk;
825 	uint64_t mediasize;
826 	const char *name, *s;
827 	char *x;
828 	int *nargs;
829 
830 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
831 	if (nargs == NULL) {
832 		gctl_error(req, "No '%s' argument.", "nargs");
833 		return;
834 	}
835 	if (*nargs != 1) {
836 		gctl_error(req, "Missing device.");
837 		return;
838 	}
839 	name = gctl_get_asciiparam(req, "arg0");
840 	if (name == NULL) {
841 		gctl_error(req, "No 'arg%u' argument.", 0);
842 		return;
843 	}
844 	s = gctl_get_asciiparam(req, "size");
845 	if (s == NULL) {
846 		gctl_error(req, "No '%s' argument.", "size");
847 		return;
848 	}
849 	mediasize = strtouq(s, &x, 0);
850 	if (*x != '\0' || mediasize == 0) {
851 		gctl_error(req, "Invalid '%s' argument.", "size");
852 		return;
853 	}
854 	sc = g_mirror_find_device(mp, name);
855 	if (sc == NULL) {
856 		gctl_error(req, "No such device: %s.", name);
857 		return;
858 	}
859 	/* Deny shrinking of an opened provider */
860 	if ((g_debugflags & 16) == 0 && sc->sc_provider_open > 0) {
861 		if (sc->sc_mediasize > mediasize) {
862 			gctl_error(req, "Device %s is busy.",
863 			    sc->sc_provider->name);
864 			sx_xunlock(&sc->sc_lock);
865 			return;
866 		}
867 	}
868 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
869 		if (mediasize > disk->d_consumer->provider->mediasize -
870 		    disk->d_consumer->provider->sectorsize) {
871 			gctl_error(req, "Provider %s is too small.",
872 			    disk->d_name);
873 			sx_xunlock(&sc->sc_lock);
874 			return;
875 		}
876 	}
877 	/* Update the size. */
878 	sc->sc_mediasize = mediasize;
879 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
880 		g_mirror_update_metadata(disk);
881 	}
882 	g_topology_lock();
883 	g_resize_provider(sc->sc_provider, mediasize);
884 	g_topology_unlock();
885 	sx_xunlock(&sc->sc_lock);
886 }
887 
888 static void
889 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
890 {
891 	struct g_mirror_softc *sc;
892 	struct g_mirror_disk *disk;
893 	const char *name;
894 	char param[16];
895 	int *nargs;
896 	u_int i, active;
897 
898 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
899 	if (nargs == NULL) {
900 		gctl_error(req, "No '%s' argument.", "nargs");
901 		return;
902 	}
903 	if (*nargs < 2) {
904 		gctl_error(req, "Too few arguments.");
905 		return;
906 	}
907 	name = gctl_get_asciiparam(req, "arg0");
908 	if (name == NULL) {
909 		gctl_error(req, "No 'arg%u' argument.", 0);
910 		return;
911 	}
912 	sc = g_mirror_find_device(mp, name);
913 	if (sc == NULL) {
914 		gctl_error(req, "No such device: %s.", name);
915 		return;
916 	}
917 	active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
918 	for (i = 1; i < (u_int)*nargs; i++) {
919 		snprintf(param, sizeof(param), "arg%u", i);
920 		name = gctl_get_asciiparam(req, param);
921 		if (name == NULL) {
922 			gctl_error(req, "No 'arg%u' argument.", i);
923 			continue;
924 		}
925 		disk = g_mirror_find_disk(sc, name);
926 		if (disk == NULL) {
927 			gctl_error(req, "No such provider: %s.", name);
928 			continue;
929 		}
930 		if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
931 			if (active > 1)
932 				active--;
933 			else {
934 				gctl_error(req, "%s: Can't deactivate the "
935 				    "last ACTIVE component %s.",
936 				    sc->sc_geom->name, name);
937 				continue;
938 			}
939 		}
940 		disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE;
941 		disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
942 		g_mirror_update_metadata(disk);
943 		sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID;
944 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
945 		    G_MIRROR_EVENT_DONTWAIT);
946 	}
947 	sx_xunlock(&sc->sc_lock);
948 }
949 
950 static void
951 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp)
952 {
953 	struct g_mirror_softc *sc;
954 	struct g_mirror_disk *disk;
955 	const char *name;
956 	char param[16];
957 	int *nargs;
958 	u_int i;
959 
960 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
961 	if (nargs == NULL) {
962 		gctl_error(req, "No '%s' argument.", "nargs");
963 		return;
964 	}
965 	if (*nargs < 1) {
966 		gctl_error(req, "Missing device(s).");
967 		return;
968 	}
969 
970 	for (i = 0; i < (u_int)*nargs; i++) {
971 		snprintf(param, sizeof(param), "arg%u", i);
972 		name = gctl_get_asciiparam(req, param);
973 		if (name == NULL) {
974 			gctl_error(req, "No 'arg%u' argument.", i);
975 			return;
976 		}
977 		sc = g_mirror_find_device(mp, name);
978 		if (sc == NULL) {
979 			gctl_error(req, "No such device: %s.", name);
980 			return;
981 		}
982 		if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) {
983 			sx_xunlock(&sc->sc_lock);
984 			G_MIRROR_DEBUG(1,
985 			    "All disks connected in %s, skipping.",
986 			    sc->sc_name);
987 			continue;
988 		}
989 		sc->sc_ndisks = g_mirror_ndisks(sc, -1);
990 		LIST_FOREACH(disk, &sc->sc_disks, d_next) {
991 			g_mirror_update_metadata(disk);
992 		}
993 		sx_xunlock(&sc->sc_lock);
994 	}
995 }
996 
997 static void
998 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe)
999 {
1000 	struct g_mirror_softc *sc;
1001 	int *force, *nargs, error;
1002 	const char *name;
1003 	char param[16];
1004 	u_int i;
1005 	int how;
1006 
1007 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1008 	if (nargs == NULL) {
1009 		gctl_error(req, "No '%s' argument.", "nargs");
1010 		return;
1011 	}
1012 	if (*nargs < 1) {
1013 		gctl_error(req, "Missing device(s).");
1014 		return;
1015 	}
1016 	force = gctl_get_paraml(req, "force", sizeof(*force));
1017 	if (force == NULL) {
1018 		gctl_error(req, "No '%s' argument.", "force");
1019 		return;
1020 	}
1021 	if (*force)
1022 		how = G_MIRROR_DESTROY_HARD;
1023 	else
1024 		how = G_MIRROR_DESTROY_SOFT;
1025 
1026 	for (i = 0; i < (u_int)*nargs; i++) {
1027 		snprintf(param, sizeof(param), "arg%u", i);
1028 		name = gctl_get_asciiparam(req, param);
1029 		if (name == NULL) {
1030 			gctl_error(req, "No 'arg%u' argument.", i);
1031 			return;
1032 		}
1033 		sc = g_mirror_find_device(mp, name);
1034 		if (sc == NULL) {
1035 			gctl_error(req, "No such device: %s.", name);
1036 			return;
1037 		}
1038 		g_cancel_event(sc);
1039 		if (wipe)
1040 			sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE;
1041 		error = g_mirror_destroy(sc, how);
1042 		if (error != 0) {
1043 			gctl_error(req, "Cannot destroy device %s (error=%d).",
1044 			    sc->sc_geom->name, error);
1045 			if (wipe)
1046 				sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE;
1047 			sx_xunlock(&sc->sc_lock);
1048 			return;
1049 		}
1050 		/* No need to unlock, because lock is already dead. */
1051 	}
1052 }
1053 
1054 void
1055 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1056 {
1057 	uint32_t *version;
1058 
1059 	g_topology_assert();
1060 
1061 	version = gctl_get_paraml(req, "version", sizeof(*version));
1062 	if (version == NULL) {
1063 		gctl_error(req, "No '%s' argument.", "version");
1064 		return;
1065 	}
1066 	if (*version != G_MIRROR_VERSION) {
1067 		gctl_error(req, "Userland and kernel parts are out of sync.");
1068 		return;
1069 	}
1070 
1071 	g_topology_unlock();
1072 	if (strcmp(verb, "configure") == 0)
1073 		g_mirror_ctl_configure(req, mp);
1074 	else if (strcmp(verb, "create") == 0)
1075 		g_mirror_ctl_create(req, mp);
1076 	else if (strcmp(verb, "rebuild") == 0)
1077 		g_mirror_ctl_rebuild(req, mp);
1078 	else if (strcmp(verb, "insert") == 0)
1079 		g_mirror_ctl_insert(req, mp);
1080 	else if (strcmp(verb, "remove") == 0)
1081 		g_mirror_ctl_remove(req, mp);
1082 	else if (strcmp(verb, "resize") == 0)
1083 		g_mirror_ctl_resize(req, mp);
1084 	else if (strcmp(verb, "deactivate") == 0)
1085 		g_mirror_ctl_deactivate(req, mp);
1086 	else if (strcmp(verb, "forget") == 0)
1087 		g_mirror_ctl_forget(req, mp);
1088 	else if (strcmp(verb, "stop") == 0)
1089 		g_mirror_ctl_stop(req, mp, 0);
1090 	else if (strcmp(verb, "destroy") == 0)
1091 		g_mirror_ctl_stop(req, mp, 1);
1092 	else
1093 		gctl_error(req, "Unknown verb.");
1094 	g_topology_lock();
1095 }
1096