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
53static kobj_method_t g_part_null_methods[] = {
54	{ 0, 0 }
55};
56
57static struct g_part_scheme g_part_null_scheme = {
58	"(none)",
59	g_part_null_methods,
60	sizeof(struct g_part_table),
61};
62
63TAILQ_HEAD(, g_part_scheme) g_part_schemes =
64    TAILQ_HEAD_INITIALIZER(g_part_schemes);
65
66struct 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
131SYSCTL_DECL(_kern_geom);
132SYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
133    "GEOM_PART stuff");
134static u_int check_integrity = 1;
135SYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity,
136    CTLFLAG_RWTUN, &check_integrity, 1,
137    "Enable integrity checking");
138static u_int auto_resize = 1;
139SYSCTL_UINT(_kern_geom_part, OID_AUTO, auto_resize,
140    CTLFLAG_RWTUN, &auto_resize, 1,
141    "Enable auto resize");
142static u_int allow_nesting = 0;
143SYSCTL_UINT(_kern_geom_part, OID_AUTO, allow_nesting,
144    CTLFLAG_RWTUN, &allow_nesting, 0,
145    "Allow additional levels of nesting");
146char g_part_separator[MAXPATHLEN] = "";
147SYSCTL_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 */
154static g_ctl_req_t g_part_ctlreq;
155static g_ctl_destroy_geom_t g_part_destroy_geom;
156static g_fini_t g_part_fini;
157static g_init_t g_part_init;
158static g_taste_t g_part_taste;
159
160static g_access_t g_part_access;
161static g_dumpconf_t g_part_dumpconf;
162static g_orphan_t g_part_orphan;
163static g_spoiled_t g_part_spoiled;
164static g_start_t g_part_start;
165static g_resize_t g_part_resize;
166static g_ioctl_t g_part_ioctl;
167
168static 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
187DECLARE_GEOM_CLASS(g_part_class, g_part);
188MODULE_VERSION(g_part, 0);
189
190/*
191 * Support functions.
192 */
193
194static void g_part_wither(struct g_geom *, int);
195
196const char *
197g_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
210void
211g_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
236static void
237g_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
283static void
284g_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
316static int
317g_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
431struct g_part_entry *
432g_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
462static void
463g_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
505static struct g_geom*
506g_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
517static int
518g_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
537static int
538g_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
558static int
559g_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
577static int
578g_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
601static int
602g_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
618static int
619g_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
635static int
636g_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
652static int
653g_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
667static int
668g_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
705done:
706	return ((scheme == NULL) ? ENXIO : 0);
707}
708
709/*
710 * Control request functions.
711 */
712
713static int
714g_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
828static int
829g_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
870static int
871g_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
952fail:
953	g_topology_lock();
954	gctl_error(req, "%d", error);
955	return (error);
956}
957
958static int
959g_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
1073fail:
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
1086static int
1087g_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
1146static int
1147g_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
1229static int
1230g_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
1276static int
1277g_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
1283static int
1284g_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
1324static int
1325g_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
1414static int
1415g_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
1468static int
1469g_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
1558fail:
1559	g_topology_lock();
1560	gctl_error(req, "%d", error);
1561	return (error);
1562}
1563
1564static void
1565g_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
1594static void
1595g_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
1938static int
1939g_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
1950static struct g_geom *
1951g_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
2053static int
2054g_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
2067static void
2068g_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 */
2144static int
2145g_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
2153static void
2154g_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
2182static void
2183g_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
2200static void
2201g_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
2211static void
2212g_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
2327static void
2328g_part_init(struct g_class *mp)
2329{
2330
2331	TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
2332}
2333
2334static void
2335g_part_fini(struct g_class *mp)
2336{
2337
2338	TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
2339}
2340
2341static void
2342g_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
2384int
2385g_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