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