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