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