xref: /freebsd/sys/geom/part/g_part.c (revision 045c8f526484cb3b97f5fd693987f4376fa43c5f)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2002, 2005-2009 Marcel Moolenaar
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  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/bio.h>
34 #include <sys/endian.h>
35 #include <sys/kernel.h>
36 #include <sys/kobj.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/queue.h>
42 #include <sys/sbuf.h>
43 #include <sys/sysctl.h>
44 #include <sys/systm.h>
45 #include <sys/uuid.h>
46 #include <geom/geom.h>
47 #include <geom/geom_ctl.h>
48 #include <geom/geom_int.h>
49 #include <geom/part/g_part.h>
50 
51 #include "g_part_if.h"
52 
53 static kobj_method_t g_part_null_methods[] = {
54 	{ 0, 0 }
55 };
56 
57 static struct g_part_scheme g_part_null_scheme = {
58 	"(none)",
59 	g_part_null_methods,
60 	sizeof(struct g_part_table),
61 };
62 
63 TAILQ_HEAD(, g_part_scheme) g_part_schemes =
64     TAILQ_HEAD_INITIALIZER(g_part_schemes);
65 
66 struct g_part_alias_list {
67 	const char *lexeme;
68 	enum g_part_alias alias;
69 } g_part_alias_list[G_PART_ALIAS_COUNT] = {
70 	{ "apple-apfs", G_PART_ALIAS_APPLE_APFS },
71 	{ "apple-boot", G_PART_ALIAS_APPLE_BOOT },
72 	{ "apple-core-storage", G_PART_ALIAS_APPLE_CORE_STORAGE },
73 	{ "apple-hfs", G_PART_ALIAS_APPLE_HFS },
74 	{ "apple-label", G_PART_ALIAS_APPLE_LABEL },
75 	{ "apple-raid", G_PART_ALIAS_APPLE_RAID },
76 	{ "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE },
77 	{ "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY },
78 	{ "apple-ufs", G_PART_ALIAS_APPLE_UFS },
79 	{ "apple-zfs", G_PART_ALIAS_APPLE_ZFS },
80 	{ "bios-boot", G_PART_ALIAS_BIOS_BOOT },
81 	{ "chromeos-firmware", G_PART_ALIAS_CHROMEOS_FIRMWARE },
82 	{ "chromeos-kernel", G_PART_ALIAS_CHROMEOS_KERNEL },
83 	{ "chromeos-reserved", G_PART_ALIAS_CHROMEOS_RESERVED },
84 	{ "chromeos-root", G_PART_ALIAS_CHROMEOS_ROOT },
85 	{ "dragonfly-ccd", G_PART_ALIAS_DFBSD_CCD },
86 	{ "dragonfly-hammer", G_PART_ALIAS_DFBSD_HAMMER },
87 	{ "dragonfly-hammer2", G_PART_ALIAS_DFBSD_HAMMER2 },
88 	{ "dragonfly-label32", G_PART_ALIAS_DFBSD },
89 	{ "dragonfly-label64", G_PART_ALIAS_DFBSD64 },
90 	{ "dragonfly-legacy", G_PART_ALIAS_DFBSD_LEGACY },
91 	{ "dragonfly-swap", G_PART_ALIAS_DFBSD_SWAP },
92 	{ "dragonfly-ufs", G_PART_ALIAS_DFBSD_UFS },
93 	{ "dragonfly-vinum", G_PART_ALIAS_DFBSD_VINUM },
94 	{ "ebr", G_PART_ALIAS_EBR },
95 	{ "efi", G_PART_ALIAS_EFI },
96 	{ "fat16", G_PART_ALIAS_MS_FAT16 },
97 	{ "fat32", G_PART_ALIAS_MS_FAT32 },
98 	{ "fat32lba", G_PART_ALIAS_MS_FAT32LBA },
99 	{ "freebsd", G_PART_ALIAS_FREEBSD },
100 	{ "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT },
101 	{ "freebsd-nandfs", G_PART_ALIAS_FREEBSD_NANDFS },
102 	{ "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP },
103 	{ "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS },
104 	{ "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM },
105 	{ "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS },
106 	{ "hifive-fsbl", G_PART_ALIAS_HIFIVE_FSBL },
107 	{ "hifive-bbl", G_PART_ALIAS_HIFIVE_BBL },
108 	{ "linux-data", G_PART_ALIAS_LINUX_DATA },
109 	{ "linux-lvm", G_PART_ALIAS_LINUX_LVM },
110 	{ "linux-raid", G_PART_ALIAS_LINUX_RAID },
111 	{ "linux-swap", G_PART_ALIAS_LINUX_SWAP },
112 	{ "mbr", G_PART_ALIAS_MBR },
113 	{ "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA },
114 	{ "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA },
115 	{ "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA },
116 	{ "ms-recovery", G_PART_ALIAS_MS_RECOVERY },
117 	{ "ms-reserved", G_PART_ALIAS_MS_RESERVED },
118 	{ "ms-spaces", G_PART_ALIAS_MS_SPACES },
119 	{ "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD },
120 	{ "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD },
121 	{ "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS },
122 	{ "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS },
123 	{ "netbsd-raid", G_PART_ALIAS_NETBSD_RAID },
124 	{ "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP },
125 	{ "ntfs", G_PART_ALIAS_MS_NTFS },
126 	{ "openbsd-data", G_PART_ALIAS_OPENBSD_DATA },
127 	{ "prep-boot", G_PART_ALIAS_PREP_BOOT },
128         { "solaris-boot", G_PART_ALIAS_SOLARIS_BOOT },
129         { "solaris-root", G_PART_ALIAS_SOLARIS_ROOT },
130         { "solaris-swap", G_PART_ALIAS_SOLARIS_SWAP },
131         { "solaris-backup", G_PART_ALIAS_SOLARIS_BACKUP },
132         { "solaris-var", G_PART_ALIAS_SOLARIS_VAR },
133         { "solaris-home", G_PART_ALIAS_SOLARIS_HOME },
134         { "solaris-altsec", G_PART_ALIAS_SOLARIS_ALTSEC },
135 	{ "solaris-reserved", G_PART_ALIAS_SOLARIS_RESERVED },
136 	{ "vmware-reserved", G_PART_ALIAS_VMRESERVED },
137 	{ "vmware-vmfs", G_PART_ALIAS_VMFS },
138 	{ "vmware-vmkdiag", G_PART_ALIAS_VMKDIAG },
139 	{ "vmware-vsanhdr", G_PART_ALIAS_VMVSANHDR },
140 };
141 
142 SYSCTL_DECL(_kern_geom);
143 SYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
144     "GEOM_PART stuff");
145 u_int geom_part_check_integrity = 1;
146 SYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity,
147     CTLFLAG_RWTUN, &geom_part_check_integrity, 1,
148     "Enable integrity checking");
149 static u_int auto_resize = 1;
150 SYSCTL_UINT(_kern_geom_part, OID_AUTO, auto_resize,
151     CTLFLAG_RWTUN, &auto_resize, 1,
152     "Enable auto resize");
153 static u_int allow_nesting = 0;
154 SYSCTL_UINT(_kern_geom_part, OID_AUTO, allow_nesting,
155     CTLFLAG_RWTUN, &allow_nesting, 0,
156     "Allow additional levels of nesting");
157 char g_part_separator[MAXPATHLEN] = "";
158 SYSCTL_STRING(_kern_geom_part, OID_AUTO, separator,
159     CTLFLAG_RDTUN, &g_part_separator, sizeof(g_part_separator),
160     "Partition name separator");
161 
162 /*
163  * The GEOM partitioning class.
164  */
165 static g_ctl_req_t g_part_ctlreq;
166 static g_ctl_destroy_geom_t g_part_destroy_geom;
167 static g_fini_t g_part_fini;
168 static g_init_t g_part_init;
169 static g_taste_t g_part_taste;
170 
171 static g_access_t g_part_access;
172 static g_dumpconf_t g_part_dumpconf;
173 static g_orphan_t g_part_orphan;
174 static g_spoiled_t g_part_spoiled;
175 static g_start_t g_part_start;
176 static g_resize_t g_part_resize;
177 static g_ioctl_t g_part_ioctl;
178 
179 static struct g_class g_part_class = {
180 	.name = "PART",
181 	.version = G_VERSION,
182 	/* Class methods. */
183 	.ctlreq = g_part_ctlreq,
184 	.destroy_geom = g_part_destroy_geom,
185 	.fini = g_part_fini,
186 	.init = g_part_init,
187 	.taste = g_part_taste,
188 	/* Geom methods. */
189 	.access = g_part_access,
190 	.dumpconf = g_part_dumpconf,
191 	.orphan = g_part_orphan,
192 	.spoiled = g_part_spoiled,
193 	.start = g_part_start,
194 	.resize = g_part_resize,
195 	.ioctl = g_part_ioctl,
196 };
197 
198 DECLARE_GEOM_CLASS(g_part_class, g_part);
199 MODULE_VERSION(g_part, 0);
200 
201 /*
202  * Support functions.
203  */
204 
205 static void g_part_wither(struct g_geom *, int);
206 
207 const char *
208 g_part_alias_name(enum g_part_alias alias)
209 {
210 	int i;
211 
212 	for (i = 0; i < G_PART_ALIAS_COUNT; i++) {
213 		if (g_part_alias_list[i].alias != alias)
214 			continue;
215 		return (g_part_alias_list[i].lexeme);
216 	}
217 
218 	return (NULL);
219 }
220 
221 void
222 g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs,
223     u_int *bestheads)
224 {
225 	static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 };
226 	off_t chs, cylinders;
227 	u_int heads;
228 	int idx;
229 
230 	*bestchs = 0;
231 	*bestheads = 0;
232 	for (idx = 0; candidate_heads[idx] != 0; idx++) {
233 		heads = candidate_heads[idx];
234 		cylinders = blocks / heads / sectors;
235 		if (cylinders < heads || cylinders < sectors)
236 			break;
237 		if (cylinders > 1023)
238 			continue;
239 		chs = cylinders * heads * sectors;
240 		if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) {
241 			*bestchs = chs;
242 			*bestheads = heads;
243 		}
244 	}
245 }
246 
247 static void
248 g_part_geometry(struct g_part_table *table, struct g_consumer *cp,
249     off_t blocks)
250 {
251 	static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 };
252 	off_t chs, bestchs;
253 	u_int heads, sectors;
254 	int idx;
255 
256 	if (g_getattr("GEOM::fwsectors", cp, &sectors) != 0 || sectors == 0 ||
257 	    g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) {
258 		table->gpt_fixgeom = 0;
259 		table->gpt_heads = 0;
260 		table->gpt_sectors = 0;
261 		bestchs = 0;
262 		for (idx = 0; candidate_sectors[idx] != 0; idx++) {
263 			sectors = candidate_sectors[idx];
264 			g_part_geometry_heads(blocks, sectors, &chs, &heads);
265 			if (chs == 0)
266 				continue;
267 			/*
268 			 * Prefer a geometry with sectors > 1, but only if
269 			 * it doesn't bump down the number of heads to 1.
270 			 */
271 			if (chs > bestchs || (chs == bestchs && heads > 1 &&
272 			    table->gpt_sectors == 1)) {
273 				bestchs = chs;
274 				table->gpt_heads = heads;
275 				table->gpt_sectors = sectors;
276 			}
277 		}
278 		/*
279 		 * If we didn't find a geometry at all, then the disk is
280 		 * too big. This means we can use the maximum number of
281 		 * heads and sectors.
282 		 */
283 		if (bestchs == 0) {
284 			table->gpt_heads = 255;
285 			table->gpt_sectors = 63;
286 		}
287 	} else {
288 		table->gpt_fixgeom = 1;
289 		table->gpt_heads = heads;
290 		table->gpt_sectors = sectors;
291 	}
292 }
293 
294 static void
295 g_part_get_physpath_done(struct bio *bp)
296 {
297 	struct g_geom *gp;
298 	struct g_part_entry *entry;
299 	struct g_part_table *table;
300 	struct g_provider *pp;
301 	struct bio *pbp;
302 
303 	pbp = bp->bio_parent;
304 	pp = pbp->bio_to;
305 	gp = pp->geom;
306 	table = gp->softc;
307 	entry = pp->private;
308 
309 	if (bp->bio_error == 0) {
310 		char *end;
311 		size_t len, remainder;
312 		len = strlcat(bp->bio_data, "/", bp->bio_length);
313 		if (len < bp->bio_length) {
314 			end = bp->bio_data + len;
315 			remainder = bp->bio_length - len;
316 			G_PART_NAME(table, entry, end, remainder);
317 		}
318 	}
319 	g_std_done(bp);
320 }
321 
322 #define	DPRINTF(...)	if (bootverbose) {	\
323 	printf("GEOM_PART: " __VA_ARGS__);	\
324 }
325 
326 static int
327 g_part_check_integrity(struct g_part_table *table, struct g_consumer *cp)
328 {
329 	struct g_part_entry *e1, *e2;
330 	struct g_provider *pp;
331 	off_t offset;
332 	int failed;
333 
334 	failed = 0;
335 	pp = cp->provider;
336 	if (table->gpt_last < table->gpt_first) {
337 		DPRINTF("last LBA is below first LBA: %jd < %jd\n",
338 		    (intmax_t)table->gpt_last, (intmax_t)table->gpt_first);
339 		failed++;
340 	}
341 	if (table->gpt_last > pp->mediasize / pp->sectorsize - 1) {
342 		DPRINTF("last LBA extends beyond mediasize: "
343 		    "%jd > %jd\n", (intmax_t)table->gpt_last,
344 		    (intmax_t)pp->mediasize / pp->sectorsize - 1);
345 		failed++;
346 	}
347 	LIST_FOREACH(e1, &table->gpt_entry, gpe_entry) {
348 		if (e1->gpe_deleted || e1->gpe_internal)
349 			continue;
350 		if (e1->gpe_start < table->gpt_first) {
351 			DPRINTF("partition %d has start offset below first "
352 			    "LBA: %jd < %jd\n", e1->gpe_index,
353 			    (intmax_t)e1->gpe_start,
354 			    (intmax_t)table->gpt_first);
355 			failed++;
356 		}
357 		if (e1->gpe_start > table->gpt_last) {
358 			DPRINTF("partition %d has start offset beyond last "
359 			    "LBA: %jd > %jd\n", e1->gpe_index,
360 			    (intmax_t)e1->gpe_start,
361 			    (intmax_t)table->gpt_last);
362 			failed++;
363 		}
364 		if (e1->gpe_end < e1->gpe_start) {
365 			DPRINTF("partition %d has end offset below start "
366 			    "offset: %jd < %jd\n", e1->gpe_index,
367 			    (intmax_t)e1->gpe_end,
368 			    (intmax_t)e1->gpe_start);
369 			failed++;
370 		}
371 		if (e1->gpe_end > table->gpt_last) {
372 			DPRINTF("partition %d has end offset beyond last "
373 			    "LBA: %jd > %jd\n", e1->gpe_index,
374 			    (intmax_t)e1->gpe_end,
375 			    (intmax_t)table->gpt_last);
376 			failed++;
377 		}
378 		if (pp->stripesize > 0) {
379 			offset = e1->gpe_start * pp->sectorsize;
380 			if (e1->gpe_offset > offset)
381 				offset = e1->gpe_offset;
382 			if ((offset + pp->stripeoffset) % pp->stripesize) {
383 				DPRINTF("partition %d on (%s, %s) is not "
384 				    "aligned on %ju bytes\n", e1->gpe_index,
385 				    pp->name, table->gpt_scheme->name,
386 				    (uintmax_t)pp->stripesize);
387 				/* Don't treat this as a critical failure */
388 			}
389 		}
390 		e2 = e1;
391 		while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) {
392 			if (e2->gpe_deleted || e2->gpe_internal)
393 				continue;
394 			if (e1->gpe_start >= e2->gpe_start &&
395 			    e1->gpe_start <= e2->gpe_end) {
396 				DPRINTF("partition %d has start offset inside "
397 				    "partition %d: start[%d] %jd >= start[%d] "
398 				    "%jd <= end[%d] %jd\n",
399 				    e1->gpe_index, e2->gpe_index,
400 				    e2->gpe_index, (intmax_t)e2->gpe_start,
401 				    e1->gpe_index, (intmax_t)e1->gpe_start,
402 				    e2->gpe_index, (intmax_t)e2->gpe_end);
403 				failed++;
404 			}
405 			if (e1->gpe_end >= e2->gpe_start &&
406 			    e1->gpe_end <= e2->gpe_end) {
407 				DPRINTF("partition %d has end offset inside "
408 				    "partition %d: start[%d] %jd >= end[%d] "
409 				    "%jd <= end[%d] %jd\n",
410 				    e1->gpe_index, e2->gpe_index,
411 				    e2->gpe_index, (intmax_t)e2->gpe_start,
412 				    e1->gpe_index, (intmax_t)e1->gpe_end,
413 				    e2->gpe_index, (intmax_t)e2->gpe_end);
414 				failed++;
415 			}
416 			if (e1->gpe_start < e2->gpe_start &&
417 			    e1->gpe_end > e2->gpe_end) {
418 				DPRINTF("partition %d contains partition %d: "
419 				    "start[%d] %jd > start[%d] %jd, end[%d] "
420 				    "%jd < end[%d] %jd\n",
421 				    e1->gpe_index, e2->gpe_index,
422 				    e1->gpe_index, (intmax_t)e1->gpe_start,
423 				    e2->gpe_index, (intmax_t)e2->gpe_start,
424 				    e2->gpe_index, (intmax_t)e2->gpe_end,
425 				    e1->gpe_index, (intmax_t)e1->gpe_end);
426 				failed++;
427 			}
428 		}
429 	}
430 	if (failed != 0) {
431 		printf("GEOM_PART: integrity check failed (%s, %s)\n",
432 		    pp->name, table->gpt_scheme->name);
433 		if (geom_part_check_integrity != 0)
434 			return (EINVAL);
435 		table->gpt_corrupt = 1;
436 	}
437 	return (0);
438 }
439 #undef	DPRINTF
440 
441 struct g_part_entry *
442 g_part_new_entry(struct g_part_table *table, int index, quad_t start,
443     quad_t end)
444 {
445 	struct g_part_entry *entry, *last;
446 
447 	last = NULL;
448 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
449 		if (entry->gpe_index == index)
450 			break;
451 		if (entry->gpe_index > index) {
452 			entry = NULL;
453 			break;
454 		}
455 		last = entry;
456 	}
457 	if (entry == NULL) {
458 		entry = g_malloc(table->gpt_scheme->gps_entrysz,
459 		    M_WAITOK | M_ZERO);
460 		entry->gpe_index = index;
461 		if (last == NULL)
462 			LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
463 		else
464 			LIST_INSERT_AFTER(last, entry, gpe_entry);
465 	} else
466 		entry->gpe_offset = 0;
467 	entry->gpe_start = start;
468 	entry->gpe_end = end;
469 	return (entry);
470 }
471 
472 static void
473 g_part_new_provider(struct g_geom *gp, struct g_part_table *table,
474     struct g_part_entry *entry)
475 {
476 	struct g_consumer *cp;
477 	struct g_provider *pp;
478 	struct g_geom_alias *gap;
479 	off_t offset;
480 
481 	cp = LIST_FIRST(&gp->consumer);
482 	pp = cp->provider;
483 
484 	offset = entry->gpe_start * pp->sectorsize;
485 	if (entry->gpe_offset < offset)
486 		entry->gpe_offset = offset;
487 
488 	if (entry->gpe_pp == NULL) {
489 		entry->gpe_pp = G_PART_NEW_PROVIDER(table, gp, entry, gp->name);
490 		/*
491 		 * If our parent provider had any aliases, then copy them to our
492 		 * provider so when geom DEV tastes things later, they will be
493 		 * there for it to create the aliases with those name used in
494 		 * place of the geom's name we use to create the provider. The
495 		 * kobj interface that generates names makes this awkward.
496 		 */
497 		LIST_FOREACH(gap, &pp->aliases, ga_next)
498 			G_PART_ADD_ALIAS(table, entry->gpe_pp, entry, gap->ga_alias);
499 		entry->gpe_pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
500 		entry->gpe_pp->private = entry;		/* Close the circle. */
501 	}
502 	entry->gpe_pp->index = entry->gpe_index - 1;	/* index is 1-based. */
503 	entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) *
504 	    pp->sectorsize;
505 	entry->gpe_pp->mediasize -= entry->gpe_offset - offset;
506 	entry->gpe_pp->sectorsize = pp->sectorsize;
507 	entry->gpe_pp->stripesize = pp->stripesize;
508 	entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset;
509 	if (pp->stripesize > 0)
510 		entry->gpe_pp->stripeoffset %= pp->stripesize;
511 	entry->gpe_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
512 	g_error_provider(entry->gpe_pp, 0);
513 }
514 
515 static struct g_geom*
516 g_part_find_geom(const char *name)
517 {
518 	struct g_geom *gp;
519 	LIST_FOREACH(gp, &g_part_class.geom, geom) {
520 		if ((gp->flags & G_GEOM_WITHER) == 0 &&
521 		    strcmp(name, gp->name) == 0)
522 			break;
523 	}
524 	return (gp);
525 }
526 
527 static int
528 g_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v)
529 {
530 	struct g_geom *gp;
531 	const char *gname;
532 
533 	gname = gctl_get_asciiparam(req, name);
534 	if (gname == NULL)
535 		return (ENOATTR);
536 	if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
537 		gname += sizeof(_PATH_DEV) - 1;
538 	gp = g_part_find_geom(gname);
539 	if (gp == NULL) {
540 		gctl_error(req, "%d %s '%s'", EINVAL, name, gname);
541 		return (EINVAL);
542 	}
543 	*v = gp;
544 	return (0);
545 }
546 
547 static int
548 g_part_parm_provider(struct gctl_req *req, const char *name,
549     struct g_provider **v)
550 {
551 	struct g_provider *pp;
552 	const char *pname;
553 
554 	pname = gctl_get_asciiparam(req, name);
555 	if (pname == NULL)
556 		return (ENOATTR);
557 	if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
558 		pname += sizeof(_PATH_DEV) - 1;
559 	pp = g_provider_by_name(pname);
560 	if (pp == NULL) {
561 		gctl_error(req, "%d %s '%s'", EINVAL, name, pname);
562 		return (EINVAL);
563 	}
564 	*v = pp;
565 	return (0);
566 }
567 
568 static int
569 g_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v)
570 {
571 	const char *p;
572 	char *x;
573 	quad_t q;
574 
575 	p = gctl_get_asciiparam(req, name);
576 	if (p == NULL)
577 		return (ENOATTR);
578 	q = strtoq(p, &x, 0);
579 	if (*x != '\0' || q < 0) {
580 		gctl_error(req, "%d %s '%s'", EINVAL, name, p);
581 		return (EINVAL);
582 	}
583 	*v = q;
584 	return (0);
585 }
586 
587 static int
588 g_part_parm_scheme(struct gctl_req *req, const char *name,
589     struct g_part_scheme **v)
590 {
591 	struct g_part_scheme *s;
592 	const char *p;
593 
594 	p = gctl_get_asciiparam(req, name);
595 	if (p == NULL)
596 		return (ENOATTR);
597 	TAILQ_FOREACH(s, &g_part_schemes, scheme_list) {
598 		if (s == &g_part_null_scheme)
599 			continue;
600 		if (!strcasecmp(s->name, p))
601 			break;
602 	}
603 	if (s == NULL) {
604 		gctl_error(req, "%d %s '%s'", EINVAL, name, p);
605 		return (EINVAL);
606 	}
607 	*v = s;
608 	return (0);
609 }
610 
611 static int
612 g_part_parm_str(struct gctl_req *req, const char *name, const char **v)
613 {
614 	const char *p;
615 
616 	p = gctl_get_asciiparam(req, name);
617 	if (p == NULL)
618 		return (ENOATTR);
619 	/* An empty label is always valid. */
620 	if (strcmp(name, "label") != 0 && p[0] == '\0') {
621 		gctl_error(req, "%d %s '%s'", EINVAL, name, p);
622 		return (EINVAL);
623 	}
624 	*v = p;
625 	return (0);
626 }
627 
628 static int
629 g_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v)
630 {
631 	const intmax_t *p;
632 	int size;
633 
634 	p = gctl_get_param(req, name, &size);
635 	if (p == NULL)
636 		return (ENOATTR);
637 	if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) {
638 		gctl_error(req, "%d %s '%jd'", EINVAL, name, *p);
639 		return (EINVAL);
640 	}
641 	*v = (u_int)*p;
642 	return (0);
643 }
644 
645 static int
646 g_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v)
647 {
648 	const uint32_t *p;
649 	int size;
650 
651 	p = gctl_get_param(req, name, &size);
652 	if (p == NULL)
653 		return (ENOATTR);
654 	if (size != sizeof(*p) || *p > INT_MAX) {
655 		gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p);
656 		return (EINVAL);
657 	}
658 	*v = (u_int)*p;
659 	return (0);
660 }
661 
662 static int
663 g_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v,
664     unsigned int *s)
665 {
666 	const void *p;
667 	int size;
668 
669 	p = gctl_get_param(req, name, &size);
670 	if (p == NULL)
671 		return (ENOATTR);
672 	*v = p;
673 	*s = size;
674 	return (0);
675 }
676 
677 static int
678 g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth)
679 {
680 	struct g_part_scheme *iter, *scheme;
681 	struct g_part_table *table;
682 	int pri, probe;
683 
684 	table = gp->softc;
685 	scheme = (table != NULL) ? table->gpt_scheme : NULL;
686 	pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN;
687 	if (pri == 0)
688 		goto done;
689 	if (pri > 0) {	/* error */
690 		scheme = NULL;
691 		pri = INT_MIN;
692 	}
693 
694 	TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
695 		if (iter == &g_part_null_scheme)
696 			continue;
697 		table = (void *)kobj_create((kobj_class_t)iter, M_GEOM,
698 		    M_WAITOK);
699 		table->gpt_gp = gp;
700 		table->gpt_scheme = iter;
701 		table->gpt_depth = depth;
702 		probe = G_PART_PROBE(table, cp);
703 		if (probe <= 0 && probe > pri) {
704 			pri = probe;
705 			scheme = iter;
706 			if (gp->softc != NULL)
707 				kobj_delete((kobj_t)gp->softc, M_GEOM);
708 			gp->softc = table;
709 			if (pri == 0)
710 				goto done;
711 		} else
712 			kobj_delete((kobj_t)table, M_GEOM);
713 	}
714 
715 done:
716 	return ((scheme == NULL) ? ENXIO : 0);
717 }
718 
719 /*
720  * Control request functions.
721  */
722 
723 static int
724 g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp)
725 {
726 	struct g_geom *gp;
727 	struct g_provider *pp;
728 	struct g_part_entry *delent, *last, *entry;
729 	struct g_part_table *table;
730 	struct sbuf *sb;
731 	quad_t end;
732 	unsigned int index;
733 	int error;
734 
735 	gp = gpp->gpp_geom;
736 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
737 	g_topology_assert();
738 
739 	pp = LIST_FIRST(&gp->consumer)->provider;
740 	table = gp->softc;
741 	end = gpp->gpp_start + gpp->gpp_size - 1;
742 
743 	if (gpp->gpp_start < table->gpt_first ||
744 	    gpp->gpp_start > table->gpt_last) {
745 		gctl_error(req, "%d start '%jd'", EINVAL,
746 		    (intmax_t)gpp->gpp_start);
747 		return (EINVAL);
748 	}
749 	if (end < gpp->gpp_start || end > table->gpt_last) {
750 		gctl_error(req, "%d size '%jd'", EINVAL,
751 		    (intmax_t)gpp->gpp_size);
752 		return (EINVAL);
753 	}
754 	if (gpp->gpp_index > table->gpt_entries) {
755 		gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index);
756 		return (EINVAL);
757 	}
758 
759 	delent = last = NULL;
760 	index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1;
761 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
762 		if (entry->gpe_deleted) {
763 			if (entry->gpe_index == index)
764 				delent = entry;
765 			continue;
766 		}
767 		if (entry->gpe_index == index)
768 			index = entry->gpe_index + 1;
769 		if (entry->gpe_index < index)
770 			last = entry;
771 		if (entry->gpe_internal)
772 			continue;
773 		if (gpp->gpp_start >= entry->gpe_start &&
774 		    gpp->gpp_start <= entry->gpe_end) {
775 			gctl_error(req, "%d start '%jd'", ENOSPC,
776 			    (intmax_t)gpp->gpp_start);
777 			return (ENOSPC);
778 		}
779 		if (end >= entry->gpe_start && end <= entry->gpe_end) {
780 			gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end);
781 			return (ENOSPC);
782 		}
783 		if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) {
784 			gctl_error(req, "%d size '%jd'", ENOSPC,
785 			    (intmax_t)gpp->gpp_size);
786 			return (ENOSPC);
787 		}
788 	}
789 	if (gpp->gpp_index > 0 && index != gpp->gpp_index) {
790 		gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index);
791 		return (EEXIST);
792 	}
793 	if (index > table->gpt_entries) {
794 		gctl_error(req, "%d index '%d'", ENOSPC, index);
795 		return (ENOSPC);
796 	}
797 
798 	entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz,
799 	    M_WAITOK | M_ZERO) : delent;
800 	entry->gpe_index = index;
801 	entry->gpe_start = gpp->gpp_start;
802 	entry->gpe_end = end;
803 	error = G_PART_ADD(table, entry, gpp);
804 	if (error) {
805 		gctl_error(req, "%d", error);
806 		if (delent == NULL)
807 			g_free(entry);
808 		return (error);
809 	}
810 	if (delent == NULL) {
811 		if (last == NULL)
812 			LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
813 		else
814 			LIST_INSERT_AFTER(last, entry, gpe_entry);
815 		entry->gpe_created = 1;
816 	} else {
817 		entry->gpe_deleted = 0;
818 		entry->gpe_modified = 1;
819 	}
820 	g_part_new_provider(gp, table, entry);
821 
822 	/* Provide feedback if so requested. */
823 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
824 		sb = sbuf_new_auto();
825 		G_PART_FULLNAME(table, entry, sb, gp->name);
826 		if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0)
827 			sbuf_printf(sb, " added, but partition is not "
828 			    "aligned on %ju bytes\n", (uintmax_t)pp->stripesize);
829 		else
830 			sbuf_cat(sb, " added\n");
831 		sbuf_finish(sb);
832 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
833 		sbuf_delete(sb);
834 	}
835 	return (0);
836 }
837 
838 static int
839 g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp)
840 {
841 	struct g_geom *gp;
842 	struct g_part_table *table;
843 	struct sbuf *sb;
844 	int error, sz;
845 
846 	gp = gpp->gpp_geom;
847 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
848 	g_topology_assert();
849 
850 	table = gp->softc;
851 	sz = table->gpt_scheme->gps_bootcodesz;
852 	if (sz == 0) {
853 		error = ENODEV;
854 		goto fail;
855 	}
856 	if (gpp->gpp_codesize > sz) {
857 		error = EFBIG;
858 		goto fail;
859 	}
860 
861 	error = G_PART_BOOTCODE(table, gpp);
862 	if (error)
863 		goto fail;
864 
865 	/* Provide feedback if so requested. */
866 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
867 		sb = sbuf_new_auto();
868 		sbuf_printf(sb, "bootcode written to %s\n", gp->name);
869 		sbuf_finish(sb);
870 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
871 		sbuf_delete(sb);
872 	}
873 	return (0);
874 
875  fail:
876 	gctl_error(req, "%d", error);
877 	return (error);
878 }
879 
880 static int
881 g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp)
882 {
883 	struct g_consumer *cp;
884 	struct g_geom *gp;
885 	struct g_provider *pp;
886 	struct g_part_entry *entry, *tmp;
887 	struct g_part_table *table;
888 	char *buf;
889 	int error, i;
890 
891 	gp = gpp->gpp_geom;
892 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
893 	g_topology_assert();
894 
895 	table = gp->softc;
896 	if (!table->gpt_opened) {
897 		gctl_error(req, "%d", EPERM);
898 		return (EPERM);
899 	}
900 
901 	g_topology_unlock();
902 
903 	cp = LIST_FIRST(&gp->consumer);
904 	if ((table->gpt_smhead | table->gpt_smtail) != 0) {
905 		pp = cp->provider;
906 		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
907 		while (table->gpt_smhead != 0) {
908 			i = ffs(table->gpt_smhead) - 1;
909 			error = g_write_data(cp, i * pp->sectorsize, buf,
910 			    pp->sectorsize);
911 			if (error) {
912 				g_free(buf);
913 				goto fail;
914 			}
915 			table->gpt_smhead &= ~(1 << i);
916 		}
917 		while (table->gpt_smtail != 0) {
918 			i = ffs(table->gpt_smtail) - 1;
919 			error = g_write_data(cp, pp->mediasize - (i + 1) *
920 			    pp->sectorsize, buf, pp->sectorsize);
921 			if (error) {
922 				g_free(buf);
923 				goto fail;
924 			}
925 			table->gpt_smtail &= ~(1 << i);
926 		}
927 		g_free(buf);
928 	}
929 
930 	if (table->gpt_scheme == &g_part_null_scheme) {
931 		g_topology_lock();
932 		g_access(cp, -1, -1, -1);
933 		g_part_wither(gp, ENXIO);
934 		return (0);
935 	}
936 
937 	error = G_PART_WRITE(table, cp);
938 	if (error)
939 		goto fail;
940 
941 	LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
942 		if (!entry->gpe_deleted) {
943 			/* Notify consumers that provider might be changed. */
944 			if (entry->gpe_modified && (
945 			    entry->gpe_pp->acw + entry->gpe_pp->ace +
946 			    entry->gpe_pp->acr) == 0)
947 				g_media_changed(entry->gpe_pp, M_NOWAIT);
948 			entry->gpe_created = 0;
949 			entry->gpe_modified = 0;
950 			continue;
951 		}
952 		LIST_REMOVE(entry, gpe_entry);
953 		g_free(entry);
954 	}
955 	table->gpt_created = 0;
956 	table->gpt_opened = 0;
957 
958 	g_topology_lock();
959 	g_access(cp, -1, -1, -1);
960 	return (0);
961 
962 fail:
963 	g_topology_lock();
964 	gctl_error(req, "%d", error);
965 	return (error);
966 }
967 
968 static int
969 g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp)
970 {
971 	struct g_consumer *cp;
972 	struct g_geom *gp;
973 	struct g_provider *pp;
974 	struct g_part_scheme *scheme;
975 	struct g_part_table *null, *table;
976 	struct sbuf *sb;
977 	int attr, error;
978 
979 	pp = gpp->gpp_provider;
980 	scheme = gpp->gpp_scheme;
981 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
982 	g_topology_assert();
983 
984 	/* Check that there isn't already a g_part geom on the provider. */
985 	gp = g_part_find_geom(pp->name);
986 	if (gp != NULL) {
987 		null = gp->softc;
988 		if (null->gpt_scheme != &g_part_null_scheme) {
989 			gctl_error(req, "%d geom '%s'", EEXIST, pp->name);
990 			return (EEXIST);
991 		}
992 	} else
993 		null = NULL;
994 
995 	if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) &&
996 	    (gpp->gpp_entries < scheme->gps_minent ||
997 	     gpp->gpp_entries > scheme->gps_maxent)) {
998 		gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries);
999 		return (EINVAL);
1000 	}
1001 
1002 	if (null == NULL)
1003 		gp = g_new_geomf(&g_part_class, "%s", pp->name);
1004 	gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM,
1005 	    M_WAITOK);
1006 	table = gp->softc;
1007 	table->gpt_gp = gp;
1008 	table->gpt_scheme = gpp->gpp_scheme;
1009 	table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ?
1010 	    gpp->gpp_entries : scheme->gps_minent;
1011 	LIST_INIT(&table->gpt_entry);
1012 	if (null == NULL) {
1013 		cp = g_new_consumer(gp);
1014 		cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
1015 		error = g_attach(cp, pp);
1016 		if (error == 0)
1017 			error = g_access(cp, 1, 1, 1);
1018 		if (error != 0) {
1019 			g_part_wither(gp, error);
1020 			gctl_error(req, "%d geom '%s'", error, pp->name);
1021 			return (error);
1022 		}
1023 		table->gpt_opened = 1;
1024 	} else {
1025 		cp = LIST_FIRST(&gp->consumer);
1026 		table->gpt_opened = null->gpt_opened;
1027 		table->gpt_smhead = null->gpt_smhead;
1028 		table->gpt_smtail = null->gpt_smtail;
1029 	}
1030 
1031 	g_topology_unlock();
1032 
1033 	/* Make sure the provider has media. */
1034 	if (pp->mediasize == 0 || pp->sectorsize == 0) {
1035 		error = ENODEV;
1036 		goto fail;
1037 	}
1038 
1039 	/* Make sure we can nest and if so, determine our depth. */
1040 	error = g_getattr("PART::isleaf", cp, &attr);
1041 	if (!error && attr) {
1042 		error = ENODEV;
1043 		goto fail;
1044 	}
1045 	error = g_getattr("PART::depth", cp, &attr);
1046 	table->gpt_depth = (!error) ? attr + 1 : 0;
1047 
1048 	/*
1049 	 * Synthesize a disk geometry. Some partitioning schemes
1050 	 * depend on it and since some file systems need it even
1051 	 * when the partitition scheme doesn't, we do it here in
1052 	 * scheme-independent code.
1053 	 */
1054 	g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1055 
1056 	error = G_PART_CREATE(table, gpp);
1057 	if (error)
1058 		goto fail;
1059 
1060 	g_topology_lock();
1061 
1062 	table->gpt_created = 1;
1063 	if (null != NULL)
1064 		kobj_delete((kobj_t)null, M_GEOM);
1065 
1066 	/*
1067 	 * Support automatic commit by filling in the gpp_geom
1068 	 * parameter.
1069 	 */
1070 	gpp->gpp_parms |= G_PART_PARM_GEOM;
1071 	gpp->gpp_geom = gp;
1072 
1073 	/* Provide feedback if so requested. */
1074 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1075 		sb = sbuf_new_auto();
1076 		sbuf_printf(sb, "%s created\n", gp->name);
1077 		sbuf_finish(sb);
1078 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1079 		sbuf_delete(sb);
1080 	}
1081 	return (0);
1082 
1083 fail:
1084 	g_topology_lock();
1085 	if (null == NULL) {
1086 		g_access(cp, -1, -1, -1);
1087 		g_part_wither(gp, error);
1088 	} else {
1089 		kobj_delete((kobj_t)gp->softc, M_GEOM);
1090 		gp->softc = null;
1091 	}
1092 	gctl_error(req, "%d provider", error);
1093 	return (error);
1094 }
1095 
1096 static int
1097 g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp)
1098 {
1099 	struct g_geom *gp;
1100 	struct g_provider *pp;
1101 	struct g_part_entry *entry;
1102 	struct g_part_table *table;
1103 	struct sbuf *sb;
1104 
1105 	gp = gpp->gpp_geom;
1106 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1107 	g_topology_assert();
1108 
1109 	table = gp->softc;
1110 
1111 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1112 		if (entry->gpe_deleted || entry->gpe_internal)
1113 			continue;
1114 		if (entry->gpe_index == gpp->gpp_index)
1115 			break;
1116 	}
1117 	if (entry == NULL) {
1118 		gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1119 		return (ENOENT);
1120 	}
1121 
1122 	pp = entry->gpe_pp;
1123 	if (pp != NULL) {
1124 		if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
1125 			gctl_error(req, "%d", EBUSY);
1126 			return (EBUSY);
1127 		}
1128 
1129 		pp->private = NULL;
1130 		entry->gpe_pp = NULL;
1131 	}
1132 
1133 	if (pp != NULL)
1134 		g_wither_provider(pp, ENXIO);
1135 
1136 	/* Provide feedback if so requested. */
1137 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1138 		sb = sbuf_new_auto();
1139 		G_PART_FULLNAME(table, entry, sb, gp->name);
1140 		sbuf_cat(sb, " deleted\n");
1141 		sbuf_finish(sb);
1142 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1143 		sbuf_delete(sb);
1144 	}
1145 
1146 	if (entry->gpe_created) {
1147 		LIST_REMOVE(entry, gpe_entry);
1148 		g_free(entry);
1149 	} else {
1150 		entry->gpe_modified = 0;
1151 		entry->gpe_deleted = 1;
1152 	}
1153 	return (0);
1154 }
1155 
1156 static int
1157 g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp)
1158 {
1159 	struct g_consumer *cp;
1160 	struct g_geom *gp;
1161 	struct g_provider *pp;
1162 	struct g_part_entry *entry, *tmp;
1163 	struct g_part_table *null, *table;
1164 	struct sbuf *sb;
1165 	int error;
1166 
1167 	gp = gpp->gpp_geom;
1168 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1169 	g_topology_assert();
1170 
1171 	table = gp->softc;
1172 	/* Check for busy providers. */
1173 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1174 		if (entry->gpe_deleted || entry->gpe_internal)
1175 			continue;
1176 		if (gpp->gpp_force) {
1177 			pp = entry->gpe_pp;
1178 			if (pp == NULL)
1179 				continue;
1180 			if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
1181 				continue;
1182 		}
1183 		gctl_error(req, "%d", EBUSY);
1184 		return (EBUSY);
1185 	}
1186 
1187 	if (gpp->gpp_force) {
1188 		/* Destroy all providers. */
1189 		LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1190 			pp = entry->gpe_pp;
1191 			if (pp != NULL) {
1192 				pp->private = NULL;
1193 				g_wither_provider(pp, ENXIO);
1194 			}
1195 			LIST_REMOVE(entry, gpe_entry);
1196 			g_free(entry);
1197 		}
1198 	}
1199 
1200 	error = G_PART_DESTROY(table, gpp);
1201 	if (error) {
1202 		gctl_error(req, "%d", error);
1203 		return (error);
1204 	}
1205 
1206 	gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM,
1207 	    M_WAITOK);
1208 	null = gp->softc;
1209 	null->gpt_gp = gp;
1210 	null->gpt_scheme = &g_part_null_scheme;
1211 	LIST_INIT(&null->gpt_entry);
1212 
1213 	cp = LIST_FIRST(&gp->consumer);
1214 	pp = cp->provider;
1215 	null->gpt_last = pp->mediasize / pp->sectorsize - 1;
1216 
1217 	null->gpt_depth = table->gpt_depth;
1218 	null->gpt_opened = table->gpt_opened;
1219 	null->gpt_smhead = table->gpt_smhead;
1220 	null->gpt_smtail = table->gpt_smtail;
1221 
1222 	while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1223 		LIST_REMOVE(entry, gpe_entry);
1224 		g_free(entry);
1225 	}
1226 	kobj_delete((kobj_t)table, M_GEOM);
1227 
1228 	/* Provide feedback if so requested. */
1229 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1230 		sb = sbuf_new_auto();
1231 		sbuf_printf(sb, "%s destroyed\n", gp->name);
1232 		sbuf_finish(sb);
1233 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1234 		sbuf_delete(sb);
1235 	}
1236 	return (0);
1237 }
1238 
1239 static int
1240 g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp)
1241 {
1242 	struct g_geom *gp;
1243 	struct g_part_entry *entry;
1244 	struct g_part_table *table;
1245 	struct sbuf *sb;
1246 	int error;
1247 
1248 	gp = gpp->gpp_geom;
1249 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1250 	g_topology_assert();
1251 
1252 	table = gp->softc;
1253 
1254 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1255 		if (entry->gpe_deleted || entry->gpe_internal)
1256 			continue;
1257 		if (entry->gpe_index == gpp->gpp_index)
1258 			break;
1259 	}
1260 	if (entry == NULL) {
1261 		gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1262 		return (ENOENT);
1263 	}
1264 
1265 	error = G_PART_MODIFY(table, entry, gpp);
1266 	if (error) {
1267 		gctl_error(req, "%d", error);
1268 		return (error);
1269 	}
1270 
1271 	if (!entry->gpe_created)
1272 		entry->gpe_modified = 1;
1273 
1274 	/* Provide feedback if so requested. */
1275 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1276 		sb = sbuf_new_auto();
1277 		G_PART_FULLNAME(table, entry, sb, gp->name);
1278 		sbuf_cat(sb, " modified\n");
1279 		sbuf_finish(sb);
1280 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1281 		sbuf_delete(sb);
1282 	}
1283 	return (0);
1284 }
1285 
1286 static int
1287 g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp)
1288 {
1289 	gctl_error(req, "%d verb 'move'", ENOSYS);
1290 	return (ENOSYS);
1291 }
1292 
1293 static int
1294 g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp)
1295 {
1296 	struct g_part_table *table;
1297 	struct g_geom *gp;
1298 	struct sbuf *sb;
1299 	int error, recovered;
1300 
1301 	gp = gpp->gpp_geom;
1302 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1303 	g_topology_assert();
1304 	table = gp->softc;
1305 	error = recovered = 0;
1306 
1307 	if (table->gpt_corrupt) {
1308 		error = G_PART_RECOVER(table);
1309 		if (error == 0)
1310 			error = g_part_check_integrity(table,
1311 			    LIST_FIRST(&gp->consumer));
1312 		if (error) {
1313 			gctl_error(req, "%d recovering '%s' failed",
1314 			    error, gp->name);
1315 			return (error);
1316 		}
1317 		recovered = 1;
1318 	}
1319 	/* Provide feedback if so requested. */
1320 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1321 		sb = sbuf_new_auto();
1322 		if (recovered)
1323 			sbuf_printf(sb, "%s recovered\n", gp->name);
1324 		else
1325 			sbuf_printf(sb, "%s recovering is not needed\n",
1326 			    gp->name);
1327 		sbuf_finish(sb);
1328 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1329 		sbuf_delete(sb);
1330 	}
1331 	return (0);
1332 }
1333 
1334 static int
1335 g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp)
1336 {
1337 	struct g_geom *gp;
1338 	struct g_provider *pp;
1339 	struct g_part_entry *pe, *entry;
1340 	struct g_part_table *table;
1341 	struct sbuf *sb;
1342 	quad_t end;
1343 	int error;
1344 	off_t mediasize;
1345 
1346 	gp = gpp->gpp_geom;
1347 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1348 	g_topology_assert();
1349 	table = gp->softc;
1350 
1351 	/* check gpp_index */
1352 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1353 		if (entry->gpe_deleted || entry->gpe_internal)
1354 			continue;
1355 		if (entry->gpe_index == gpp->gpp_index)
1356 			break;
1357 	}
1358 	if (entry == NULL) {
1359 		gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1360 		return (ENOENT);
1361 	}
1362 
1363 	/* check gpp_size */
1364 	end = entry->gpe_start + gpp->gpp_size - 1;
1365 	if (gpp->gpp_size < 1 || end > table->gpt_last) {
1366 		gctl_error(req, "%d size '%jd'", EINVAL,
1367 		    (intmax_t)gpp->gpp_size);
1368 		return (EINVAL);
1369 	}
1370 
1371 	LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) {
1372 		if (pe->gpe_deleted || pe->gpe_internal || pe == entry)
1373 			continue;
1374 		if (end >= pe->gpe_start && end <= pe->gpe_end) {
1375 			gctl_error(req, "%d end '%jd'", ENOSPC,
1376 			    (intmax_t)end);
1377 			return (ENOSPC);
1378 		}
1379 		if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) {
1380 			gctl_error(req, "%d size '%jd'", ENOSPC,
1381 			    (intmax_t)gpp->gpp_size);
1382 			return (ENOSPC);
1383 		}
1384 	}
1385 
1386 	pp = entry->gpe_pp;
1387 	if ((g_debugflags & G_F_FOOTSHOOTING) == 0 &&
1388 	    (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) {
1389 		if (entry->gpe_end - entry->gpe_start + 1 > gpp->gpp_size) {
1390 			/* Deny shrinking of an opened partition. */
1391 			gctl_error(req, "%d", EBUSY);
1392 			return (EBUSY);
1393 		}
1394 	}
1395 
1396 	error = G_PART_RESIZE(table, entry, gpp);
1397 	if (error) {
1398 		gctl_error(req, "%d%s", error, error != EBUSY ? "":
1399 		    " resizing will lead to unexpected shrinking"
1400 		    " due to alignment");
1401 		return (error);
1402 	}
1403 
1404 	if (!entry->gpe_created)
1405 		entry->gpe_modified = 1;
1406 
1407 	/* update mediasize of changed provider */
1408 	mediasize = (entry->gpe_end - entry->gpe_start + 1) *
1409 		pp->sectorsize;
1410 	g_resize_provider(pp, mediasize);
1411 
1412 	/* Provide feedback if so requested. */
1413 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1414 		sb = sbuf_new_auto();
1415 		G_PART_FULLNAME(table, entry, sb, gp->name);
1416 		sbuf_cat(sb, " resized\n");
1417 		sbuf_finish(sb);
1418 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1419 		sbuf_delete(sb);
1420 	}
1421 	return (0);
1422 }
1423 
1424 static int
1425 g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp,
1426     unsigned int set)
1427 {
1428 	struct g_geom *gp;
1429 	struct g_part_entry *entry;
1430 	struct g_part_table *table;
1431 	struct sbuf *sb;
1432 	int error;
1433 
1434 	gp = gpp->gpp_geom;
1435 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1436 	g_topology_assert();
1437 
1438 	table = gp->softc;
1439 
1440 	if (gpp->gpp_parms & G_PART_PARM_INDEX) {
1441 		LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1442 			if (entry->gpe_deleted || entry->gpe_internal)
1443 				continue;
1444 			if (entry->gpe_index == gpp->gpp_index)
1445 				break;
1446 		}
1447 		if (entry == NULL) {
1448 			gctl_error(req, "%d index '%d'", ENOENT,
1449 			    gpp->gpp_index);
1450 			return (ENOENT);
1451 		}
1452 	} else
1453 		entry = NULL;
1454 
1455 	error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set);
1456 	if (error) {
1457 		gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib);
1458 		return (error);
1459 	}
1460 
1461 	/* Provide feedback if so requested. */
1462 	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1463 		sb = sbuf_new_auto();
1464 		sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib,
1465 		    (set) ? "" : "un");
1466 		if (entry)
1467 			G_PART_FULLNAME(table, entry, sb, gp->name);
1468 		else
1469 			sbuf_cat(sb, gp->name);
1470 		sbuf_cat(sb, "\n");
1471 		sbuf_finish(sb);
1472 		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1473 		sbuf_delete(sb);
1474 	}
1475 	return (0);
1476 }
1477 
1478 static int
1479 g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp)
1480 {
1481 	struct g_consumer *cp;
1482 	struct g_provider *pp;
1483 	struct g_geom *gp;
1484 	struct g_part_entry *entry, *tmp;
1485 	struct g_part_table *table;
1486 	int error, reprobe;
1487 
1488 	gp = gpp->gpp_geom;
1489 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1490 	g_topology_assert();
1491 
1492 	table = gp->softc;
1493 	if (!table->gpt_opened) {
1494 		gctl_error(req, "%d", EPERM);
1495 		return (EPERM);
1496 	}
1497 
1498 	cp = LIST_FIRST(&gp->consumer);
1499 	LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1500 		entry->gpe_modified = 0;
1501 		if (entry->gpe_created) {
1502 			pp = entry->gpe_pp;
1503 			if (pp != NULL) {
1504 				pp->private = NULL;
1505 				entry->gpe_pp = NULL;
1506 				g_wither_provider(pp, ENXIO);
1507 			}
1508 			entry->gpe_deleted = 1;
1509 		}
1510 		if (entry->gpe_deleted) {
1511 			LIST_REMOVE(entry, gpe_entry);
1512 			g_free(entry);
1513 		}
1514 	}
1515 
1516 	g_topology_unlock();
1517 
1518 	reprobe = (table->gpt_scheme == &g_part_null_scheme ||
1519 	    table->gpt_created) ? 1 : 0;
1520 
1521 	if (reprobe) {
1522 		LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1523 			if (entry->gpe_internal)
1524 				continue;
1525 			error = EBUSY;
1526 			goto fail;
1527 		}
1528 		while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1529 			LIST_REMOVE(entry, gpe_entry);
1530 			g_free(entry);
1531 		}
1532 		error = g_part_probe(gp, cp, table->gpt_depth);
1533 		if (error) {
1534 			g_topology_lock();
1535 			g_access(cp, -1, -1, -1);
1536 			g_part_wither(gp, error);
1537 			return (0);
1538 		}
1539 		table = gp->softc;
1540 
1541 		/*
1542 		 * Synthesize a disk geometry. Some partitioning schemes
1543 		 * depend on it and since some file systems need it even
1544 		 * when the partitition scheme doesn't, we do it here in
1545 		 * scheme-independent code.
1546 		 */
1547 		pp = cp->provider;
1548 		g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1549 	}
1550 
1551 	error = G_PART_READ(table, cp);
1552 	if (error)
1553 		goto fail;
1554 	error = g_part_check_integrity(table, cp);
1555 	if (error)
1556 		goto fail;
1557 
1558 	g_topology_lock();
1559 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1560 		if (!entry->gpe_internal)
1561 			g_part_new_provider(gp, table, entry);
1562 	}
1563 
1564 	table->gpt_opened = 0;
1565 	g_access(cp, -1, -1, -1);
1566 	return (0);
1567 
1568 fail:
1569 	g_topology_lock();
1570 	gctl_error(req, "%d", error);
1571 	return (error);
1572 }
1573 
1574 static void
1575 g_part_wither(struct g_geom *gp, int error)
1576 {
1577 	struct g_part_entry *entry;
1578 	struct g_part_table *table;
1579 	struct g_provider *pp;
1580 
1581 	table = gp->softc;
1582 	if (table != NULL) {
1583 		gp->softc = NULL;
1584 		while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1585 			LIST_REMOVE(entry, gpe_entry);
1586 			pp = entry->gpe_pp;
1587 			entry->gpe_pp = NULL;
1588 			if (pp != NULL) {
1589 				pp->private = NULL;
1590 				g_wither_provider(pp, error);
1591 			}
1592 			g_free(entry);
1593 		}
1594 		G_PART_DESTROY(table, NULL);
1595 		kobj_delete((kobj_t)table, M_GEOM);
1596 	}
1597 	g_wither_geom(gp, error);
1598 }
1599 
1600 /*
1601  * Class methods.
1602  */
1603 
1604 static void
1605 g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
1606 {
1607 	struct g_part_parms gpp;
1608 	struct g_part_table *table;
1609 	struct gctl_req_arg *ap;
1610 	enum g_part_ctl ctlreq;
1611 	unsigned int i, mparms, oparms, parm;
1612 	int auto_commit, close_on_error;
1613 	int error, modifies;
1614 
1615 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
1616 	g_topology_assert();
1617 
1618 	ctlreq = G_PART_CTL_NONE;
1619 	modifies = 1;
1620 	mparms = 0;
1621 	oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION;
1622 	switch (*verb) {
1623 	case 'a':
1624 		if (!strcmp(verb, "add")) {
1625 			ctlreq = G_PART_CTL_ADD;
1626 			mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE |
1627 			    G_PART_PARM_START | G_PART_PARM_TYPE;
1628 			oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL;
1629 		}
1630 		break;
1631 	case 'b':
1632 		if (!strcmp(verb, "bootcode")) {
1633 			ctlreq = G_PART_CTL_BOOTCODE;
1634 			mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE;
1635 			oparms |= G_PART_PARM_SKIP_DSN;
1636 		}
1637 		break;
1638 	case 'c':
1639 		if (!strcmp(verb, "commit")) {
1640 			ctlreq = G_PART_CTL_COMMIT;
1641 			mparms |= G_PART_PARM_GEOM;
1642 			modifies = 0;
1643 		} else if (!strcmp(verb, "create")) {
1644 			ctlreq = G_PART_CTL_CREATE;
1645 			mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME;
1646 			oparms |= G_PART_PARM_ENTRIES;
1647 		}
1648 		break;
1649 	case 'd':
1650 		if (!strcmp(verb, "delete")) {
1651 			ctlreq = G_PART_CTL_DELETE;
1652 			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1653 		} else if (!strcmp(verb, "destroy")) {
1654 			ctlreq = G_PART_CTL_DESTROY;
1655 			mparms |= G_PART_PARM_GEOM;
1656 			oparms |= G_PART_PARM_FORCE;
1657 		}
1658 		break;
1659 	case 'm':
1660 		if (!strcmp(verb, "modify")) {
1661 			ctlreq = G_PART_CTL_MODIFY;
1662 			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1663 			oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE;
1664 		} else if (!strcmp(verb, "move")) {
1665 			ctlreq = G_PART_CTL_MOVE;
1666 			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1667 		}
1668 		break;
1669 	case 'r':
1670 		if (!strcmp(verb, "recover")) {
1671 			ctlreq = G_PART_CTL_RECOVER;
1672 			mparms |= G_PART_PARM_GEOM;
1673 		} else if (!strcmp(verb, "resize")) {
1674 			ctlreq = G_PART_CTL_RESIZE;
1675 			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX |
1676 			    G_PART_PARM_SIZE;
1677 		}
1678 		break;
1679 	case 's':
1680 		if (!strcmp(verb, "set")) {
1681 			ctlreq = G_PART_CTL_SET;
1682 			mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM;
1683 			oparms |= G_PART_PARM_INDEX;
1684 		}
1685 		break;
1686 	case 'u':
1687 		if (!strcmp(verb, "undo")) {
1688 			ctlreq = G_PART_CTL_UNDO;
1689 			mparms |= G_PART_PARM_GEOM;
1690 			modifies = 0;
1691 		} else if (!strcmp(verb, "unset")) {
1692 			ctlreq = G_PART_CTL_UNSET;
1693 			mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM;
1694 			oparms |= G_PART_PARM_INDEX;
1695 		}
1696 		break;
1697 	}
1698 	if (ctlreq == G_PART_CTL_NONE) {
1699 		gctl_error(req, "%d verb '%s'", EINVAL, verb);
1700 		return;
1701 	}
1702 
1703 	bzero(&gpp, sizeof(gpp));
1704 	for (i = 0; i < req->narg; i++) {
1705 		ap = &req->arg[i];
1706 		parm = 0;
1707 		switch (ap->name[0]) {
1708 		case 'a':
1709 			if (!strcmp(ap->name, "arg0")) {
1710 				parm = mparms &
1711 				    (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER);
1712 			}
1713 			if (!strcmp(ap->name, "attrib"))
1714 				parm = G_PART_PARM_ATTRIB;
1715 			break;
1716 		case 'b':
1717 			if (!strcmp(ap->name, "bootcode"))
1718 				parm = G_PART_PARM_BOOTCODE;
1719 			break;
1720 		case 'c':
1721 			if (!strcmp(ap->name, "class"))
1722 				continue;
1723 			break;
1724 		case 'e':
1725 			if (!strcmp(ap->name, "entries"))
1726 				parm = G_PART_PARM_ENTRIES;
1727 			break;
1728 		case 'f':
1729 			if (!strcmp(ap->name, "flags"))
1730 				parm = G_PART_PARM_FLAGS;
1731 			else if (!strcmp(ap->name, "force"))
1732 				parm = G_PART_PARM_FORCE;
1733 			break;
1734 		case 'i':
1735 			if (!strcmp(ap->name, "index"))
1736 				parm = G_PART_PARM_INDEX;
1737 			break;
1738 		case 'l':
1739 			if (!strcmp(ap->name, "label"))
1740 				parm = G_PART_PARM_LABEL;
1741 			break;
1742 		case 'o':
1743 			if (!strcmp(ap->name, "output"))
1744 				parm = G_PART_PARM_OUTPUT;
1745 			break;
1746 		case 's':
1747 			if (!strcmp(ap->name, "scheme"))
1748 				parm = G_PART_PARM_SCHEME;
1749 			else if (!strcmp(ap->name, "size"))
1750 				parm = G_PART_PARM_SIZE;
1751 			else if (!strcmp(ap->name, "start"))
1752 				parm = G_PART_PARM_START;
1753 			else if (!strcmp(ap->name, "skip_dsn"))
1754 				parm = G_PART_PARM_SKIP_DSN;
1755 			break;
1756 		case 't':
1757 			if (!strcmp(ap->name, "type"))
1758 				parm = G_PART_PARM_TYPE;
1759 			break;
1760 		case 'v':
1761 			if (!strcmp(ap->name, "verb"))
1762 				continue;
1763 			else if (!strcmp(ap->name, "version"))
1764 				parm = G_PART_PARM_VERSION;
1765 			break;
1766 		}
1767 		if ((parm & (mparms | oparms)) == 0) {
1768 			gctl_error(req, "%d param '%s'", EINVAL, ap->name);
1769 			return;
1770 		}
1771 		switch (parm) {
1772 		case G_PART_PARM_ATTRIB:
1773 			error = g_part_parm_str(req, ap->name,
1774 			    &gpp.gpp_attrib);
1775 			break;
1776 		case G_PART_PARM_BOOTCODE:
1777 			error = g_part_parm_bootcode(req, ap->name,
1778 			    &gpp.gpp_codeptr, &gpp.gpp_codesize);
1779 			break;
1780 		case G_PART_PARM_ENTRIES:
1781 			error = g_part_parm_intmax(req, ap->name,
1782 			    &gpp.gpp_entries);
1783 			break;
1784 		case G_PART_PARM_FLAGS:
1785 			error = g_part_parm_str(req, ap->name, &gpp.gpp_flags);
1786 			break;
1787 		case G_PART_PARM_FORCE:
1788 			error = g_part_parm_uint32(req, ap->name,
1789 			    &gpp.gpp_force);
1790 			break;
1791 		case G_PART_PARM_GEOM:
1792 			error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom);
1793 			break;
1794 		case G_PART_PARM_INDEX:
1795 			error = g_part_parm_intmax(req, ap->name,
1796 			    &gpp.gpp_index);
1797 			break;
1798 		case G_PART_PARM_LABEL:
1799 			error = g_part_parm_str(req, ap->name, &gpp.gpp_label);
1800 			break;
1801 		case G_PART_PARM_OUTPUT:
1802 			error = 0;	/* Write-only parameter */
1803 			break;
1804 		case G_PART_PARM_PROVIDER:
1805 			error = g_part_parm_provider(req, ap->name,
1806 			    &gpp.gpp_provider);
1807 			break;
1808 		case G_PART_PARM_SCHEME:
1809 			error = g_part_parm_scheme(req, ap->name,
1810 			    &gpp.gpp_scheme);
1811 			break;
1812 		case G_PART_PARM_SIZE:
1813 			error = g_part_parm_quad(req, ap->name, &gpp.gpp_size);
1814 			break;
1815 		case G_PART_PARM_SKIP_DSN:
1816 			error = g_part_parm_uint32(req, ap->name,
1817 			    &gpp.gpp_skip_dsn);
1818 			break;
1819 		case G_PART_PARM_START:
1820 			error = g_part_parm_quad(req, ap->name,
1821 			    &gpp.gpp_start);
1822 			break;
1823 		case G_PART_PARM_TYPE:
1824 			error = g_part_parm_str(req, ap->name, &gpp.gpp_type);
1825 			break;
1826 		case G_PART_PARM_VERSION:
1827 			error = g_part_parm_uint32(req, ap->name,
1828 			    &gpp.gpp_version);
1829 			break;
1830 		default:
1831 			error = EDOOFUS;
1832 			gctl_error(req, "%d %s", error, ap->name);
1833 			break;
1834 		}
1835 		if (error != 0) {
1836 			if (error == ENOATTR) {
1837 				gctl_error(req, "%d param '%s'", error,
1838 				    ap->name);
1839 			}
1840 			return;
1841 		}
1842 		gpp.gpp_parms |= parm;
1843 	}
1844 	if ((gpp.gpp_parms & mparms) != mparms) {
1845 		parm = mparms - (gpp.gpp_parms & mparms);
1846 		gctl_error(req, "%d param '%x'", ENOATTR, parm);
1847 		return;
1848 	}
1849 
1850 	/* Obtain permissions if possible/necessary. */
1851 	close_on_error = 0;
1852 	table = NULL;
1853 	if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) {
1854 		table = gpp.gpp_geom->softc;
1855 		if (table != NULL && table->gpt_corrupt &&
1856 		    ctlreq != G_PART_CTL_DESTROY &&
1857 		    ctlreq != G_PART_CTL_RECOVER &&
1858 		    geom_part_check_integrity) {
1859 			gctl_error(req, "%d table '%s' is corrupt",
1860 			    EPERM, gpp.gpp_geom->name);
1861 			return;
1862 		}
1863 		if (table != NULL && !table->gpt_opened) {
1864 			error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer),
1865 			    1, 1, 1);
1866 			if (error) {
1867 				gctl_error(req, "%d geom '%s'", error,
1868 				    gpp.gpp_geom->name);
1869 				return;
1870 			}
1871 			table->gpt_opened = 1;
1872 			close_on_error = 1;
1873 		}
1874 	}
1875 
1876 	/* Allow the scheme to check or modify the parameters. */
1877 	if (table != NULL) {
1878 		error = G_PART_PRECHECK(table, ctlreq, &gpp);
1879 		if (error) {
1880 			gctl_error(req, "%d pre-check failed", error);
1881 			goto out;
1882 		}
1883 	} else
1884 		error = EDOOFUS;	/* Prevent bogus uninit. warning. */
1885 
1886 	switch (ctlreq) {
1887 	case G_PART_CTL_NONE:
1888 		panic("%s", __func__);
1889 	case G_PART_CTL_ADD:
1890 		error = g_part_ctl_add(req, &gpp);
1891 		break;
1892 	case G_PART_CTL_BOOTCODE:
1893 		error = g_part_ctl_bootcode(req, &gpp);
1894 		break;
1895 	case G_PART_CTL_COMMIT:
1896 		error = g_part_ctl_commit(req, &gpp);
1897 		break;
1898 	case G_PART_CTL_CREATE:
1899 		error = g_part_ctl_create(req, &gpp);
1900 		break;
1901 	case G_PART_CTL_DELETE:
1902 		error = g_part_ctl_delete(req, &gpp);
1903 		break;
1904 	case G_PART_CTL_DESTROY:
1905 		error = g_part_ctl_destroy(req, &gpp);
1906 		break;
1907 	case G_PART_CTL_MODIFY:
1908 		error = g_part_ctl_modify(req, &gpp);
1909 		break;
1910 	case G_PART_CTL_MOVE:
1911 		error = g_part_ctl_move(req, &gpp);
1912 		break;
1913 	case G_PART_CTL_RECOVER:
1914 		error = g_part_ctl_recover(req, &gpp);
1915 		break;
1916 	case G_PART_CTL_RESIZE:
1917 		error = g_part_ctl_resize(req, &gpp);
1918 		break;
1919 	case G_PART_CTL_SET:
1920 		error = g_part_ctl_setunset(req, &gpp, 1);
1921 		break;
1922 	case G_PART_CTL_UNDO:
1923 		error = g_part_ctl_undo(req, &gpp);
1924 		break;
1925 	case G_PART_CTL_UNSET:
1926 		error = g_part_ctl_setunset(req, &gpp, 0);
1927 		break;
1928 	}
1929 
1930 	/* Implement automatic commit. */
1931 	if (!error) {
1932 		auto_commit = (modifies &&
1933 		    (gpp.gpp_parms & G_PART_PARM_FLAGS) &&
1934 		    strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0;
1935 		if (auto_commit) {
1936 			KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s",
1937 			    __func__));
1938 			error = g_part_ctl_commit(req, &gpp);
1939 		}
1940 	}
1941 
1942  out:
1943 	if (error && close_on_error) {
1944 		g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1);
1945 		table->gpt_opened = 0;
1946 	}
1947 }
1948 
1949 static int
1950 g_part_destroy_geom(struct gctl_req *req, struct g_class *mp,
1951     struct g_geom *gp)
1952 {
1953 
1954 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
1955 	g_topology_assert();
1956 
1957 	g_part_wither(gp, EINVAL);
1958 	return (0);
1959 }
1960 
1961 static struct g_geom *
1962 g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
1963 {
1964 	struct g_consumer *cp;
1965 	struct g_geom *gp;
1966 	struct g_part_entry *entry;
1967 	struct g_part_table *table;
1968 	struct root_hold_token *rht;
1969 	int attr, depth;
1970 	int error;
1971 
1972 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
1973 	g_topology_assert();
1974 
1975 	/* Skip providers that are already open for writing. */
1976 	if (pp->acw > 0)
1977 		return (NULL);
1978 
1979 	/*
1980 	 * Create a GEOM with consumer and hook it up to the provider.
1981 	 * With that we become part of the topology. Obtain read access
1982 	 * to the provider.
1983 	 */
1984 	gp = g_new_geomf(mp, "%s", pp->name);
1985 	cp = g_new_consumer(gp);
1986 	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
1987 	error = g_attach(cp, pp);
1988 	if (error == 0)
1989 		error = g_access(cp, 1, 0, 0);
1990 	if (error != 0) {
1991 		if (cp->provider)
1992 			g_detach(cp);
1993 		g_destroy_consumer(cp);
1994 		g_destroy_geom(gp);
1995 		return (NULL);
1996 	}
1997 
1998 	rht = root_mount_hold(mp->name);
1999 	g_topology_unlock();
2000 
2001 	/*
2002 	 * Short-circuit the whole probing galore when there's no
2003 	 * media present.
2004 	 */
2005 	if (pp->mediasize == 0 || pp->sectorsize == 0) {
2006 		error = ENODEV;
2007 		goto fail;
2008 	}
2009 
2010 	/* Make sure we can nest and if so, determine our depth. */
2011 	error = g_getattr("PART::isleaf", cp, &attr);
2012 	if (!error && attr) {
2013 		error = ENODEV;
2014 		goto fail;
2015 	}
2016 	error = g_getattr("PART::depth", cp, &attr);
2017 	depth = (!error) ? attr + 1 : 0;
2018 
2019 	error = g_part_probe(gp, cp, depth);
2020 	if (error)
2021 		goto fail;
2022 
2023 	table = gp->softc;
2024 
2025 	/*
2026 	 * Synthesize a disk geometry. Some partitioning schemes
2027 	 * depend on it and since some file systems need it even
2028 	 * when the partitition scheme doesn't, we do it here in
2029 	 * scheme-independent code.
2030 	 */
2031 	g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
2032 
2033 	error = G_PART_READ(table, cp);
2034 	if (error)
2035 		goto fail;
2036 	error = g_part_check_integrity(table, cp);
2037 	if (error)
2038 		goto fail;
2039 
2040 	g_topology_lock();
2041 	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
2042 		if (!entry->gpe_internal)
2043 			g_part_new_provider(gp, table, entry);
2044 	}
2045 
2046 	root_mount_rel(rht);
2047 	g_access(cp, -1, 0, 0);
2048 	return (gp);
2049 
2050  fail:
2051 	g_topology_lock();
2052 	root_mount_rel(rht);
2053 	g_access(cp, -1, 0, 0);
2054 	g_detach(cp);
2055 	g_destroy_consumer(cp);
2056 	g_destroy_geom(gp);
2057 	return (NULL);
2058 }
2059 
2060 /*
2061  * Geom methods.
2062  */
2063 
2064 static int
2065 g_part_access(struct g_provider *pp, int dr, int dw, int de)
2066 {
2067 	struct g_consumer *cp;
2068 
2069 	G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr,
2070 	    dw, de));
2071 
2072 	cp = LIST_FIRST(&pp->geom->consumer);
2073 
2074 	/* We always gain write-exclusive access. */
2075 	return (g_access(cp, dr, dw, dw + de));
2076 }
2077 
2078 static void
2079 g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
2080     struct g_consumer *cp, struct g_provider *pp)
2081 {
2082 	char buf[64];
2083 	struct g_part_entry *entry;
2084 	struct g_part_table *table;
2085 
2086 	KASSERT(sb != NULL && gp != NULL, ("%s", __func__));
2087 	table = gp->softc;
2088 
2089 	if (indent == NULL) {
2090 		KASSERT(cp == NULL && pp != NULL, ("%s", __func__));
2091 		entry = pp->private;
2092 		if (entry == NULL)
2093 			return;
2094 		sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index,
2095 		    (uintmax_t)entry->gpe_offset,
2096 		    G_PART_TYPE(table, entry, buf, sizeof(buf)));
2097 		/*
2098 		 * libdisk compatibility quirk - the scheme dumps the
2099 		 * slicer name and partition type in a way that is
2100 		 * compatible with libdisk. When libdisk is not used
2101 		 * anymore, this should go away.
2102 		 */
2103 		G_PART_DUMPCONF(table, entry, sb, indent);
2104 	} else if (cp != NULL) {	/* Consumer configuration. */
2105 		KASSERT(pp == NULL, ("%s", __func__));
2106 		/* none */
2107 	} else if (pp != NULL) {	/* Provider configuration. */
2108 		entry = pp->private;
2109 		if (entry == NULL)
2110 			return;
2111 		sbuf_printf(sb, "%s<start>%ju</start>\n", indent,
2112 		    (uintmax_t)entry->gpe_start);
2113 		sbuf_printf(sb, "%s<end>%ju</end>\n", indent,
2114 		    (uintmax_t)entry->gpe_end);
2115 		sbuf_printf(sb, "%s<index>%u</index>\n", indent,
2116 		    entry->gpe_index);
2117 		sbuf_printf(sb, "%s<type>%s</type>\n", indent,
2118 		    G_PART_TYPE(table, entry, buf, sizeof(buf)));
2119 		sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
2120 		    (uintmax_t)entry->gpe_offset);
2121 		sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
2122 		    (uintmax_t)pp->mediasize);
2123 		G_PART_DUMPCONF(table, entry, sb, indent);
2124 	} else {			/* Geom configuration. */
2125 		sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent,
2126 		    table->gpt_scheme->name);
2127 		sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
2128 		    table->gpt_entries);
2129 		sbuf_printf(sb, "%s<first>%ju</first>\n", indent,
2130 		    (uintmax_t)table->gpt_first);
2131 		sbuf_printf(sb, "%s<last>%ju</last>\n", indent,
2132 		    (uintmax_t)table->gpt_last);
2133 		sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent,
2134 		    table->gpt_sectors);
2135 		sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent,
2136 		    table->gpt_heads);
2137 		sbuf_printf(sb, "%s<state>%s</state>\n", indent,
2138 		    table->gpt_corrupt ? "CORRUPT": "OK");
2139 		sbuf_printf(sb, "%s<modified>%s</modified>\n", indent,
2140 		    table->gpt_opened ? "true": "false");
2141 		G_PART_DUMPCONF(table, NULL, sb, indent);
2142 	}
2143 }
2144 
2145 /*-
2146  * This start routine is only called for non-trivial requests, all the
2147  * trivial ones are handled autonomously by the slice code.
2148  * For requests we handle here, we must call the g_io_deliver() on the
2149  * bio, and return non-zero to indicate to the slice code that we did so.
2150  * This code executes in the "DOWN" I/O path, this means:
2151  *    * No sleeping.
2152  *    * Don't grab the topology lock.
2153  *    * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
2154  */
2155 static int
2156 g_part_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
2157 {
2158 	struct g_part_table *table;
2159 
2160 	table = pp->geom->softc;
2161 	return G_PART_IOCTL(table, pp, cmd, data, fflag, td);
2162 }
2163 
2164 static void
2165 g_part_resize(struct g_consumer *cp)
2166 {
2167 	struct g_part_table *table;
2168 
2169 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
2170 	g_topology_assert();
2171 
2172 	if (auto_resize == 0)
2173 		return;
2174 
2175 	table = cp->geom->softc;
2176 	if (table->gpt_opened == 0) {
2177 		if (g_access(cp, 1, 1, 1) != 0)
2178 			return;
2179 		table->gpt_opened = 1;
2180 	}
2181 	if (G_PART_RESIZE(table, NULL, NULL) == 0)
2182 		printf("GEOM_PART: %s was automatically resized.\n"
2183 		    "  Use `gpart commit %s` to save changes or "
2184 		    "`gpart undo %s` to revert them.\n", cp->geom->name,
2185 		    cp->geom->name, cp->geom->name);
2186 	if (g_part_check_integrity(table, cp) != 0) {
2187 		g_access(cp, -1, -1, -1);
2188 		table->gpt_opened = 0;
2189 		g_part_wither(table->gpt_gp, ENXIO);
2190 	}
2191 }
2192 
2193 static void
2194 g_part_orphan(struct g_consumer *cp)
2195 {
2196 	struct g_provider *pp;
2197 	struct g_part_table *table;
2198 
2199 	pp = cp->provider;
2200 	KASSERT(pp != NULL, ("%s", __func__));
2201 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
2202 	g_topology_assert();
2203 
2204 	KASSERT(pp->error != 0, ("%s", __func__));
2205 	table = cp->geom->softc;
2206 	if (table != NULL && table->gpt_opened)
2207 		g_access(cp, -1, -1, -1);
2208 	g_part_wither(cp->geom, pp->error);
2209 }
2210 
2211 static void
2212 g_part_spoiled(struct g_consumer *cp)
2213 {
2214 
2215 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
2216 	g_topology_assert();
2217 
2218 	cp->flags |= G_CF_ORPHAN;
2219 	g_part_wither(cp->geom, ENXIO);
2220 }
2221 
2222 static void
2223 g_part_start(struct bio *bp)
2224 {
2225 	struct bio *bp2;
2226 	struct g_consumer *cp;
2227 	struct g_geom *gp;
2228 	struct g_part_entry *entry;
2229 	struct g_part_table *table;
2230 	struct g_kerneldump *gkd;
2231 	struct g_provider *pp;
2232 	void (*done_func)(struct bio *) = g_std_done;
2233 	char buf[64];
2234 
2235 	biotrack(bp, __func__);
2236 
2237 	pp = bp->bio_to;
2238 	gp = pp->geom;
2239 	table = gp->softc;
2240 	cp = LIST_FIRST(&gp->consumer);
2241 
2242 	G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
2243 	    pp->name));
2244 
2245 	entry = pp->private;
2246 	if (entry == NULL) {
2247 		g_io_deliver(bp, ENXIO);
2248 		return;
2249 	}
2250 
2251 	switch(bp->bio_cmd) {
2252 	case BIO_DELETE:
2253 	case BIO_READ:
2254 	case BIO_WRITE:
2255 		if (bp->bio_offset >= pp->mediasize) {
2256 			g_io_deliver(bp, EIO);
2257 			return;
2258 		}
2259 		bp2 = g_clone_bio(bp);
2260 		if (bp2 == NULL) {
2261 			g_io_deliver(bp, ENOMEM);
2262 			return;
2263 		}
2264 		if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
2265 			bp2->bio_length = pp->mediasize - bp2->bio_offset;
2266 		bp2->bio_done = g_std_done;
2267 		bp2->bio_offset += entry->gpe_offset;
2268 		g_io_request(bp2, cp);
2269 		return;
2270 	case BIO_SPEEDUP:
2271 	case BIO_FLUSH:
2272 		break;
2273 	case BIO_GETATTR:
2274 		if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads))
2275 			return;
2276 		if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors))
2277 			return;
2278 		/*
2279 		 * allow_nesting overrides "isleaf" to false _unless_ the
2280 		 * provider offset is zero, since otherwise we would recurse.
2281 		 */
2282 		if (g_handleattr_int(bp, "PART::isleaf",
2283 			table->gpt_isleaf &&
2284 			(allow_nesting == 0 || entry->gpe_offset == 0)))
2285 			return;
2286 		if (g_handleattr_int(bp, "PART::depth", table->gpt_depth))
2287 			return;
2288 		if (g_handleattr_str(bp, "PART::scheme",
2289 		    table->gpt_scheme->name))
2290 			return;
2291 		if (g_handleattr_str(bp, "PART::type",
2292 		    G_PART_TYPE(table, entry, buf, sizeof(buf))))
2293 			return;
2294 		if (!strcmp("GEOM::physpath", bp->bio_attribute)) {
2295 			done_func = g_part_get_physpath_done;
2296 			break;
2297 		}
2298 		if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
2299 			/*
2300 			 * Check that the partition is suitable for kernel
2301 			 * dumps. Typically only swap partitions should be
2302 			 * used. If the request comes from the nested scheme
2303 			 * we allow dumping there as well.
2304 			 */
2305 			if ((bp->bio_from == NULL ||
2306 			    bp->bio_from->geom->class != &g_part_class) &&
2307 			    G_PART_DUMPTO(table, entry) == 0) {
2308 				g_io_deliver(bp, ENODEV);
2309 				printf("GEOM_PART: Partition '%s' not suitable"
2310 				    " for kernel dumps (wrong type?)\n",
2311 				    pp->name);
2312 				return;
2313 			}
2314 			gkd = (struct g_kerneldump *)bp->bio_data;
2315 			if (gkd->offset >= pp->mediasize) {
2316 				g_io_deliver(bp, EIO);
2317 				return;
2318 			}
2319 			if (gkd->offset + gkd->length > pp->mediasize)
2320 				gkd->length = pp->mediasize - gkd->offset;
2321 			gkd->offset += entry->gpe_offset;
2322 		}
2323 		break;
2324 	default:
2325 		g_io_deliver(bp, EOPNOTSUPP);
2326 		return;
2327 	}
2328 
2329 	bp2 = g_clone_bio(bp);
2330 	if (bp2 == NULL) {
2331 		g_io_deliver(bp, ENOMEM);
2332 		return;
2333 	}
2334 	bp2->bio_done = done_func;
2335 	g_io_request(bp2, cp);
2336 }
2337 
2338 static void
2339 g_part_init(struct g_class *mp)
2340 {
2341 
2342 	TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
2343 }
2344 
2345 static void
2346 g_part_fini(struct g_class *mp)
2347 {
2348 
2349 	TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
2350 }
2351 
2352 static void
2353 g_part_unload_event(void *arg, int flag)
2354 {
2355 	struct g_consumer *cp;
2356 	struct g_geom *gp;
2357 	struct g_provider *pp;
2358 	struct g_part_scheme *scheme;
2359 	struct g_part_table *table;
2360 	uintptr_t *xchg;
2361 	int acc, error;
2362 
2363 	if (flag == EV_CANCEL)
2364 		return;
2365 
2366 	xchg = arg;
2367 	error = 0;
2368 	scheme = (void *)(*xchg);
2369 
2370 	g_topology_assert();
2371 
2372 	LIST_FOREACH(gp, &g_part_class.geom, geom) {
2373 		table = gp->softc;
2374 		if (table->gpt_scheme != scheme)
2375 			continue;
2376 
2377 		acc = 0;
2378 		LIST_FOREACH(pp, &gp->provider, provider)
2379 			acc += pp->acr + pp->acw + pp->ace;
2380 		LIST_FOREACH(cp, &gp->consumer, consumer)
2381 			acc += cp->acr + cp->acw + cp->ace;
2382 
2383 		if (!acc)
2384 			g_part_wither(gp, ENOSYS);
2385 		else
2386 			error = EBUSY;
2387 	}
2388 
2389 	if (!error)
2390 		TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
2391 
2392 	*xchg = error;
2393 }
2394 
2395 int
2396 g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme)
2397 {
2398 	struct g_part_scheme *iter;
2399 	uintptr_t arg;
2400 	int error;
2401 
2402 	error = 0;
2403 	switch (type) {
2404 	case MOD_LOAD:
2405 		TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
2406 			if (scheme == iter) {
2407 				printf("GEOM_PART: scheme %s is already "
2408 				    "registered!\n", scheme->name);
2409 				break;
2410 			}
2411 		}
2412 		if (iter == NULL) {
2413 			TAILQ_INSERT_TAIL(&g_part_schemes, scheme,
2414 			    scheme_list);
2415 			g_retaste(&g_part_class);
2416 		}
2417 		break;
2418 	case MOD_UNLOAD:
2419 		arg = (uintptr_t)scheme;
2420 		error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK,
2421 		    NULL);
2422 		if (error == 0)
2423 			error = arg;
2424 		break;
2425 	default:
2426 		error = EOPNOTSUPP;
2427 		break;
2428 	}
2429 
2430 	return (error);
2431 }
2432