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