g_part.c revision 188352
1/*-
2 * Copyright (c) 2002, 2005-2008 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 188352 2009-02-08 23:39:30Z marcel $");
29
30#include <sys/param.h>
31#include <sys/bio.h>
32#include <sys/diskmbr.h>
33#include <sys/endian.h>
34#include <sys/kernel.h>
35#include <sys/kobj.h>
36#include <sys/limits.h>
37#include <sys/lock.h>
38#include <sys/malloc.h>
39#include <sys/mutex.h>
40#include <sys/queue.h>
41#include <sys/sbuf.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
51static kobj_method_t g_part_null_methods[] = {
52	{ 0, 0 }
53};
54
55static struct g_part_scheme g_part_null_scheme = {
56	"(none)",
57	g_part_null_methods,
58	sizeof(struct g_part_table),
59};
60
61TAILQ_HEAD(, g_part_scheme) g_part_schemes =
62    TAILQ_HEAD_INITIALIZER(g_part_schemes);
63
64struct g_part_alias_list {
65	const char *lexeme;
66	enum g_part_alias alias;
67} g_part_alias_list[G_PART_ALIAS_COUNT] = {
68	{ "apple-hfs", G_PART_ALIAS_APPLE_HFS },
69	{ "efi", G_PART_ALIAS_EFI },
70	{ "freebsd", G_PART_ALIAS_FREEBSD },
71	{ "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT },
72	{ "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP },
73	{ "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS },
74	{ "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM },
75	{ "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS },
76	{ "mbr", G_PART_ALIAS_MBR }
77};
78
79/*
80 * The GEOM partitioning class.
81 */
82static g_ctl_req_t g_part_ctlreq;
83static g_ctl_destroy_geom_t g_part_destroy_geom;
84static g_fini_t g_part_fini;
85static g_init_t g_part_init;
86static g_taste_t g_part_taste;
87
88static g_access_t g_part_access;
89static g_dumpconf_t g_part_dumpconf;
90static g_orphan_t g_part_orphan;
91static g_spoiled_t g_part_spoiled;
92static g_start_t g_part_start;
93
94static struct g_class g_part_class = {
95	.name = "PART",
96	.version = G_VERSION,
97	/* Class methods. */
98	.ctlreq = g_part_ctlreq,
99	.destroy_geom = g_part_destroy_geom,
100	.fini = g_part_fini,
101	.init = g_part_init,
102	.taste = g_part_taste,
103	/* Geom methods. */
104	.access = g_part_access,
105	.dumpconf = g_part_dumpconf,
106	.orphan = g_part_orphan,
107	.spoiled = g_part_spoiled,
108	.start = g_part_start,
109};
110
111DECLARE_GEOM_CLASS(g_part_class, g_part);
112
113enum g_part_ctl {
114	G_PART_CTL_NONE,
115	G_PART_CTL_ADD,
116	G_PART_CTL_BOOTCODE,
117	G_PART_CTL_COMMIT,
118	G_PART_CTL_CREATE,
119	G_PART_CTL_DELETE,
120	G_PART_CTL_DESTROY,
121	G_PART_CTL_MODIFY,
122	G_PART_CTL_MOVE,
123	G_PART_CTL_RECOVER,
124	G_PART_CTL_RESIZE,
125	G_PART_CTL_SET,
126	G_PART_CTL_UNDO,
127	G_PART_CTL_UNSET
128};
129
130/*
131 * Support functions.
132 */
133
134static void g_part_wither(struct g_geom *, int);
135
136const char *
137g_part_alias_name(enum g_part_alias alias)
138{
139	int i;
140
141	for (i = 0; i < G_PART_ALIAS_COUNT; i++) {
142		if (g_part_alias_list[i].alias != alias)
143			continue;
144		return (g_part_alias_list[i].lexeme);
145	}
146
147	return (NULL);
148}
149
150void
151g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs,
152    u_int *bestheads)
153{
154	static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 };
155	off_t chs, cylinders;
156	u_int heads;
157	int idx;
158
159	*bestchs = 0;
160	*bestheads = 0;
161	for (idx = 0; candidate_heads[idx] != 0; idx++) {
162		heads = candidate_heads[idx];
163		cylinders = blocks / heads / sectors;
164		if (cylinders < heads || cylinders < sectors)
165			break;
166		if (cylinders > 1023)
167			continue;
168		chs = cylinders * heads * sectors;
169		if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) {
170			*bestchs = chs;
171			*bestheads = heads;
172		}
173	}
174}
175
176static void
177g_part_geometry(struct g_part_table *table, struct g_consumer *cp,
178    off_t blocks)
179{
180	static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 };
181	off_t chs, bestchs;
182	u_int heads, sectors;
183	int idx;
184
185	if (g_getattr("GEOM::fwsectors", cp, &sectors) != 0 || sectors == 0 ||
186	    g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) {
187		table->gpt_fixgeom = 0;
188		table->gpt_heads = 0;
189		table->gpt_sectors = 0;
190		bestchs = 0;
191		for (idx = 0; candidate_sectors[idx] != 0; idx++) {
192			sectors = candidate_sectors[idx];
193			g_part_geometry_heads(blocks, sectors, &chs, &heads);
194			if (chs == 0)
195				continue;
196			/*
197			 * Prefer a geometry with sectors > 1, but only if
198			 * it doesn't bump down the numbver of heads to 1.
199			 */
200			if (chs > bestchs || (chs == bestchs && heads > 1 &&
201			    table->gpt_sectors == 1)) {
202				bestchs = chs;
203				table->gpt_heads = heads;
204				table->gpt_sectors = sectors;
205			}
206		}
207		/*
208		 * If we didn't find a geometry at all, then the disk is
209		 * too big. This means we can use the maximum number of
210		 * heads and sectors.
211		 */
212		if (bestchs == 0) {
213			table->gpt_heads = 255;
214			table->gpt_sectors = 63;
215		}
216	} else {
217		table->gpt_fixgeom = 1;
218		table->gpt_heads = heads;
219		table->gpt_sectors = sectors;
220	}
221}
222
223struct g_part_entry *
224g_part_new_entry(struct g_part_table *table, int index, quad_t start,
225    quad_t end)
226{
227	struct g_part_entry *entry, *last;
228
229	last = NULL;
230	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
231		if (entry->gpe_index == index)
232			break;
233		if (entry->gpe_index > index) {
234			entry = NULL;
235			break;
236		}
237		last = entry;
238	}
239	if (entry == NULL) {
240		entry = g_malloc(table->gpt_scheme->gps_entrysz,
241		    M_WAITOK | M_ZERO);
242		entry->gpe_index = index;
243		if (last == NULL)
244			LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
245		else
246			LIST_INSERT_AFTER(last, entry, gpe_entry);
247	} else
248		entry->gpe_offset = 0;
249	entry->gpe_start = start;
250	entry->gpe_end = end;
251	return (entry);
252}
253
254static void
255g_part_new_provider(struct g_geom *gp, struct g_part_table *table,
256    struct g_part_entry *entry)
257{
258	char buf[32];
259	struct g_consumer *cp;
260	struct g_provider *pp;
261	off_t offset;
262
263	cp = LIST_FIRST(&gp->consumer);
264	pp = cp->provider;
265
266	offset = entry->gpe_start * pp->sectorsize;
267	if (entry->gpe_offset < offset)
268		entry->gpe_offset = offset;
269
270	if (entry->gpe_pp == NULL) {
271		entry->gpe_pp = g_new_providerf(gp, "%s%s", gp->name,
272		    G_PART_NAME(table, entry, buf, sizeof(buf)));
273		entry->gpe_pp->private = entry;		/* Close the circle. */
274	}
275	entry->gpe_pp->index = entry->gpe_index - 1;	/* index is 1-based. */
276	entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) *
277	    pp->sectorsize;
278	entry->gpe_pp->mediasize -= entry->gpe_offset - offset;
279	entry->gpe_pp->sectorsize = pp->sectorsize;
280	entry->gpe_pp->flags = pp->flags & G_PF_CANDELETE;
281	if (pp->stripesize > 0) {
282		entry->gpe_pp->stripesize = pp->stripesize;
283		entry->gpe_pp->stripeoffset = (pp->stripeoffset +
284		    entry->gpe_offset) % pp->stripesize;
285	}
286	g_error_provider(entry->gpe_pp, 0);
287}
288
289static int
290g_part_parm_geom(const char *p, struct g_geom **v)
291{
292	struct g_geom *gp;
293
294	LIST_FOREACH(gp, &g_part_class.geom, geom) {
295		if (!strcmp(p, gp->name))
296			break;
297	}
298	if (gp == NULL)
299		return (EINVAL);
300	*v = gp;
301	return (0);
302}
303
304static int
305g_part_parm_provider(const char *p, struct g_provider **v)
306{
307	struct g_provider *pp;
308
309	pp = g_provider_by_name(p);
310	if (pp == NULL)
311		return (EINVAL);
312	*v = pp;
313	return (0);
314}
315
316static int
317g_part_parm_quad(const char *p, quad_t *v)
318{
319	char *x;
320	quad_t q;
321
322	q = strtoq(p, &x, 0);
323	if (*x != '\0' || q < 0)
324		return (EINVAL);
325	*v = q;
326	return (0);
327}
328
329static int
330g_part_parm_scheme(const char *p, struct g_part_scheme **v)
331{
332	struct g_part_scheme *s;
333
334	TAILQ_FOREACH(s, &g_part_schemes, scheme_list) {
335		if (s == &g_part_null_scheme)
336			continue;
337		if (!strcasecmp(s->name, p))
338			break;
339	}
340	if (s == NULL)
341		return (EINVAL);
342	*v = s;
343	return (0);
344}
345
346static int
347g_part_parm_str(const char *p, const char **v)
348{
349
350	if (p[0] == '\0')
351		return (EINVAL);
352	*v = p;
353	return (0);
354}
355
356static int
357g_part_parm_uint(const char *p, u_int *v)
358{
359	char *x;
360	long l;
361
362	l = strtol(p, &x, 0);
363	if (*x != '\0' || l < 0 || l > INT_MAX)
364		return (EINVAL);
365	*v = (unsigned int)l;
366	return (0);
367}
368
369static int
370g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth)
371{
372	struct g_part_scheme *iter, *scheme;
373	struct g_part_table *table;
374	int pri, probe;
375
376	table = gp->softc;
377	scheme = (table != NULL) ? table->gpt_scheme : NULL;
378	pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN;
379	if (pri == 0)
380		goto done;
381	if (pri > 0) {	/* error */
382		scheme = NULL;
383		pri = INT_MIN;
384	}
385
386	TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
387		if (iter == &g_part_null_scheme)
388			continue;
389		table = (void *)kobj_create((kobj_class_t)iter, M_GEOM,
390		    M_WAITOK);
391		table->gpt_gp = gp;
392		table->gpt_scheme = iter;
393		table->gpt_depth = depth;
394		probe = G_PART_PROBE(table, cp);
395		if (probe <= 0 && probe > pri) {
396			pri = probe;
397			scheme = iter;
398			if (gp->softc != NULL)
399				kobj_delete((kobj_t)gp->softc, M_GEOM);
400			gp->softc = table;
401			if (pri == 0)
402				goto done;
403		} else
404			kobj_delete((kobj_t)table, M_GEOM);
405	}
406
407done:
408	return ((scheme == NULL) ? ENXIO : 0);
409}
410
411/*
412 * Control request functions.
413 */
414
415static int
416g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp)
417{
418	char buf[32];
419	struct g_geom *gp;
420	struct g_provider *pp;
421	struct g_part_entry *delent, *last, *entry;
422	struct g_part_table *table;
423	struct sbuf *sb;
424	quad_t end;
425	unsigned int index;
426	int error;
427
428	gp = gpp->gpp_geom;
429	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
430	g_topology_assert();
431
432	pp = LIST_FIRST(&gp->consumer)->provider;
433	table = gp->softc;
434	end = gpp->gpp_start + gpp->gpp_size - 1;
435
436	if (gpp->gpp_start < table->gpt_first ||
437	    gpp->gpp_start > table->gpt_last) {
438		gctl_error(req, "%d start '%jd'", EINVAL,
439		    (intmax_t)gpp->gpp_start);
440		return (EINVAL);
441	}
442	if (end < gpp->gpp_start || end > table->gpt_last) {
443		gctl_error(req, "%d size '%jd'", EINVAL,
444		    (intmax_t)gpp->gpp_size);
445		return (EINVAL);
446	}
447	if (gpp->gpp_index > table->gpt_entries) {
448		gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index);
449		return (EINVAL);
450	}
451
452	delent = last = NULL;
453	index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1;
454	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
455		if (entry->gpe_deleted) {
456			if (entry->gpe_index == index)
457				delent = entry;
458			continue;
459		}
460		if (entry->gpe_index == index)
461			index = entry->gpe_index + 1;
462		if (entry->gpe_index < index)
463			last = entry;
464		if (entry->gpe_internal)
465			continue;
466		if (gpp->gpp_start >= entry->gpe_start &&
467		    gpp->gpp_start <= entry->gpe_end) {
468			gctl_error(req, "%d start '%jd'", ENOSPC,
469			    (intmax_t)gpp->gpp_start);
470			return (ENOSPC);
471		}
472		if (end >= entry->gpe_start && end <= entry->gpe_end) {
473			gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end);
474			return (ENOSPC);
475		}
476		if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) {
477			gctl_error(req, "%d size '%jd'", ENOSPC,
478			    (intmax_t)gpp->gpp_size);
479			return (ENOSPC);
480		}
481	}
482	if (gpp->gpp_index > 0 && index != gpp->gpp_index) {
483		gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index);
484		return (EEXIST);
485	}
486
487	entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz,
488	    M_WAITOK | M_ZERO) : delent;
489	entry->gpe_index = index;
490	entry->gpe_start = gpp->gpp_start;
491	entry->gpe_end = end;
492	error = G_PART_ADD(table, entry, gpp);
493	if (error) {
494		gctl_error(req, "%d", error);
495		if (delent == NULL)
496			g_free(entry);
497		return (error);
498	}
499	if (delent == NULL) {
500		if (last == NULL)
501			LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
502		else
503			LIST_INSERT_AFTER(last, entry, gpe_entry);
504		entry->gpe_created = 1;
505	} else {
506		entry->gpe_deleted = 0;
507		entry->gpe_modified = 1;
508	}
509	g_part_new_provider(gp, table, entry);
510
511	/* Provide feedback if so requested. */
512	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
513		sb = sbuf_new_auto();
514		sbuf_printf(sb, "%s%s added\n", gp->name,
515		    G_PART_NAME(table, entry, buf, sizeof(buf)));
516		sbuf_finish(sb);
517		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
518		sbuf_delete(sb);
519	}
520	return (0);
521}
522
523static int
524g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp)
525{
526	struct g_geom *gp;
527	struct g_part_table *table;
528	struct sbuf *sb;
529	int error, sz;
530
531	gp = gpp->gpp_geom;
532	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
533	g_topology_assert();
534
535	table = gp->softc;
536	sz = table->gpt_scheme->gps_bootcodesz;
537	if (sz == 0) {
538		error = ENODEV;
539		goto fail;
540	}
541	if (gpp->gpp_codesize > sz) {
542		error = EFBIG;
543		goto fail;
544	}
545
546	error = G_PART_BOOTCODE(table, gpp);
547	if (error)
548		goto fail;
549
550	/* Provide feedback if so requested. */
551	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
552		sb = sbuf_new_auto();
553		sbuf_printf(sb, "%s has bootcode\n", gp->name);
554		sbuf_finish(sb);
555		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
556		sbuf_delete(sb);
557	}
558	return (0);
559
560 fail:
561	gctl_error(req, "%d", error);
562	return (error);
563}
564
565static int
566g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp)
567{
568	struct g_consumer *cp;
569	struct g_geom *gp;
570	struct g_provider *pp;
571	struct g_part_entry *entry, *tmp;
572	struct g_part_table *table;
573	char *buf;
574	int error, i;
575
576	gp = gpp->gpp_geom;
577	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
578	g_topology_assert();
579
580	table = gp->softc;
581	if (!table->gpt_opened) {
582		gctl_error(req, "%d", EPERM);
583		return (EPERM);
584	}
585
586	cp = LIST_FIRST(&gp->consumer);
587	if ((table->gpt_smhead | table->gpt_smtail) != 0) {
588		pp = cp->provider;
589		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
590		while (table->gpt_smhead != 0) {
591			i = ffs(table->gpt_smhead) - 1;
592			error = g_write_data(cp, i * pp->sectorsize, buf,
593			    pp->sectorsize);
594			if (error) {
595				g_free(buf);
596				goto fail;
597			}
598			table->gpt_smhead &= ~(1 << i);
599		}
600		while (table->gpt_smtail != 0) {
601			i = ffs(table->gpt_smtail) - 1;
602			error = g_write_data(cp, pp->mediasize - (i + 1) *
603			    pp->sectorsize, buf, pp->sectorsize);
604			if (error) {
605				g_free(buf);
606				goto fail;
607			}
608			table->gpt_smtail &= ~(1 << i);
609		}
610		g_free(buf);
611	}
612
613	if (table->gpt_scheme == &g_part_null_scheme) {
614		g_access(cp, -1, -1, -1);
615		g_part_wither(gp, ENXIO);
616		return (0);
617	}
618
619	error = G_PART_WRITE(table, cp);
620	if (error)
621		goto fail;
622
623	LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
624		if (!entry->gpe_deleted) {
625			entry->gpe_created = 0;
626			entry->gpe_modified = 0;
627			continue;
628		}
629		LIST_REMOVE(entry, gpe_entry);
630		g_free(entry);
631	}
632	table->gpt_created = 0;
633	table->gpt_opened = 0;
634	g_access(cp, -1, -1, -1);
635	return (0);
636
637fail:
638	gctl_error(req, "%d", error);
639	return (error);
640}
641
642static int
643g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp)
644{
645	struct g_consumer *cp;
646	struct g_geom *gp;
647	struct g_provider *pp;
648	struct g_part_scheme *scheme;
649	struct g_part_table *null, *table;
650	struct sbuf *sb;
651	int attr, error;
652
653	pp = gpp->gpp_provider;
654	scheme = gpp->gpp_scheme;
655	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
656	g_topology_assert();
657
658	/* Check that there isn't already a g_part geom on the provider. */
659	error = g_part_parm_geom(pp->name, &gp);
660	if (!error) {
661		null = gp->softc;
662		if (null->gpt_scheme != &g_part_null_scheme) {
663			gctl_error(req, "%d geom '%s'", EEXIST, pp->name);
664			return (EEXIST);
665		}
666	} else
667		null = NULL;
668
669	if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) &&
670	    (gpp->gpp_entries < scheme->gps_minent ||
671	     gpp->gpp_entries > scheme->gps_maxent)) {
672		gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries);
673		return (EINVAL);
674	}
675
676	if (null == NULL)
677		gp = g_new_geomf(&g_part_class, "%s", pp->name);
678	gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM,
679	    M_WAITOK);
680	table = gp->softc;
681	table->gpt_gp = gp;
682	table->gpt_scheme = gpp->gpp_scheme;
683	table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ?
684	    gpp->gpp_entries : scheme->gps_minent;
685	LIST_INIT(&table->gpt_entry);
686	if (null == NULL) {
687		cp = g_new_consumer(gp);
688		error = g_attach(cp, pp);
689		if (error == 0)
690			error = g_access(cp, 1, 1, 1);
691		if (error != 0) {
692			g_part_wither(gp, error);
693			gctl_error(req, "%d geom '%s'", error, pp->name);
694			return (error);
695		}
696		table->gpt_opened = 1;
697	} else {
698		cp = LIST_FIRST(&gp->consumer);
699		table->gpt_opened = null->gpt_opened;
700		table->gpt_smhead = null->gpt_smhead;
701		table->gpt_smtail = null->gpt_smtail;
702	}
703
704	g_topology_unlock();
705
706	/* Make sure the provider has media. */
707	if (pp->mediasize == 0 || pp->sectorsize == 0) {
708		error = ENODEV;
709		goto fail;
710	}
711
712	/* Make sure we can nest and if so, determine our depth. */
713	error = g_getattr("PART::isleaf", cp, &attr);
714	if (!error && attr) {
715		error = ENODEV;
716		goto fail;
717	}
718	error = g_getattr("PART::depth", cp, &attr);
719	table->gpt_depth = (!error) ? attr + 1 : 0;
720
721	/* If we're nested, get the absolute sector offset on disk. */
722	if (table->gpt_depth) {
723		error = g_getattr("PART::offset", cp, &attr);
724		if (error)
725			goto fail;
726		table->gpt_offset = attr;
727	}
728
729	/*
730	 * Synthesize a disk geometry. Some partitioning schemes
731	 * depend on it and since some file systems need it even
732	 * when the partitition scheme doesn't, we do it here in
733	 * scheme-independent code.
734	 */
735	g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
736
737	error = G_PART_CREATE(table, gpp);
738	if (error)
739		goto fail;
740
741	g_topology_lock();
742
743	table->gpt_created = 1;
744	if (null != NULL)
745		kobj_delete((kobj_t)null, M_GEOM);
746
747	/*
748	 * Support automatic commit by filling in the gpp_geom
749	 * parameter.
750	 */
751	gpp->gpp_parms |= G_PART_PARM_GEOM;
752	gpp->gpp_geom = gp;
753
754	/* Provide feedback if so requested. */
755	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
756		sb = sbuf_new_auto();
757		sbuf_printf(sb, "%s created\n", gp->name);
758		sbuf_finish(sb);
759		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
760		sbuf_delete(sb);
761	}
762	return (0);
763
764fail:
765	g_topology_lock();
766	if (null == NULL) {
767		g_access(cp, -1, -1, -1);
768		g_part_wither(gp, error);
769	} else {
770		kobj_delete((kobj_t)gp->softc, M_GEOM);
771		gp->softc = null;
772	}
773	gctl_error(req, "%d provider", error);
774	return (error);
775}
776
777static int
778g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp)
779{
780	char buf[32];
781	struct g_geom *gp;
782	struct g_provider *pp;
783	struct g_part_entry *entry;
784	struct g_part_table *table;
785	struct sbuf *sb;
786
787	gp = gpp->gpp_geom;
788	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
789	g_topology_assert();
790
791	table = gp->softc;
792
793	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
794		if (entry->gpe_deleted || entry->gpe_internal)
795			continue;
796		if (entry->gpe_index == gpp->gpp_index)
797			break;
798	}
799	if (entry == NULL) {
800		gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
801		return (ENOENT);
802	}
803
804	pp = entry->gpe_pp;
805	if (pp != NULL) {
806		if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
807			gctl_error(req, "%d", EBUSY);
808			return (EBUSY);
809		}
810
811		pp->private = NULL;
812		entry->gpe_pp = NULL;
813	}
814
815	if (entry->gpe_created) {
816		LIST_REMOVE(entry, gpe_entry);
817		g_free(entry);
818	} else {
819		entry->gpe_modified = 0;
820		entry->gpe_deleted = 1;
821	}
822
823	if (pp != NULL)
824		g_wither_provider(pp, ENXIO);
825
826	/* Provide feedback if so requested. */
827	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
828		sb = sbuf_new_auto();
829		sbuf_printf(sb, "%s%s deleted\n", gp->name,
830		    G_PART_NAME(table, entry, buf, sizeof(buf)));
831		sbuf_finish(sb);
832		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
833		sbuf_delete(sb);
834	}
835	return (0);
836}
837
838static int
839g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp)
840{
841	struct g_geom *gp;
842	struct g_part_entry *entry;
843	struct g_part_table *null, *table;
844	struct sbuf *sb;
845	int error;
846
847	gp = gpp->gpp_geom;
848	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
849	g_topology_assert();
850
851	table = gp->softc;
852	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
853		if (entry->gpe_deleted || entry->gpe_internal)
854			continue;
855		gctl_error(req, "%d", EBUSY);
856		return (EBUSY);
857	}
858
859	error = G_PART_DESTROY(table, gpp);
860	if (error) {
861		gctl_error(req, "%d", error);
862		return (error);
863	}
864
865	gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM,
866	    M_WAITOK);
867	null = gp->softc;
868	null->gpt_gp = gp;
869	null->gpt_scheme = &g_part_null_scheme;
870	LIST_INIT(&null->gpt_entry);
871	null->gpt_depth = table->gpt_depth;
872	null->gpt_opened = table->gpt_opened;
873	null->gpt_smhead = table->gpt_smhead;
874	null->gpt_smtail = table->gpt_smtail;
875
876	while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
877		LIST_REMOVE(entry, gpe_entry);
878		g_free(entry);
879	}
880	kobj_delete((kobj_t)table, M_GEOM);
881
882	/* Provide feedback if so requested. */
883	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
884		sb = sbuf_new_auto();
885		sbuf_printf(sb, "%s destroyed\n", gp->name);
886		sbuf_finish(sb);
887		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
888		sbuf_delete(sb);
889	}
890	return (0);
891}
892
893static int
894g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp)
895{
896	char buf[32];
897	struct g_geom *gp;
898	struct g_part_entry *entry;
899	struct g_part_table *table;
900	struct sbuf *sb;
901	int error;
902
903	gp = gpp->gpp_geom;
904	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
905	g_topology_assert();
906
907	table = gp->softc;
908
909	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
910		if (entry->gpe_deleted || entry->gpe_internal)
911			continue;
912		if (entry->gpe_index == gpp->gpp_index)
913			break;
914	}
915	if (entry == NULL) {
916		gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
917		return (ENOENT);
918	}
919
920	error = G_PART_MODIFY(table, entry, gpp);
921	if (error) {
922		gctl_error(req, "%d", error);
923		return (error);
924	}
925
926	if (!entry->gpe_created)
927		entry->gpe_modified = 1;
928
929	/* Provide feedback if so requested. */
930	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
931		sb = sbuf_new_auto();
932		sbuf_printf(sb, "%s%s modified\n", gp->name,
933		    G_PART_NAME(table, entry, buf, sizeof(buf)));
934		sbuf_finish(sb);
935		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
936		sbuf_delete(sb);
937	}
938	return (0);
939}
940
941static int
942g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp)
943{
944	gctl_error(req, "%d verb 'move'", ENOSYS);
945	return (ENOSYS);
946}
947
948static int
949g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp)
950{
951	gctl_error(req, "%d verb 'recover'", ENOSYS);
952	return (ENOSYS);
953}
954
955static int
956g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp)
957{
958	gctl_error(req, "%d verb 'resize'", ENOSYS);
959	return (ENOSYS);
960}
961
962static int
963g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp,
964    unsigned int set)
965{
966	char buf[32];
967	struct g_geom *gp;
968	struct g_part_entry *entry;
969	struct g_part_table *table;
970	struct sbuf *sb;
971	int error;
972
973	gp = gpp->gpp_geom;
974	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
975	g_topology_assert();
976
977	table = gp->softc;
978
979	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
980		if (entry->gpe_deleted || entry->gpe_internal)
981			continue;
982		if (entry->gpe_index == gpp->gpp_index)
983			break;
984	}
985	if (entry == NULL) {
986		gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
987		return (ENOENT);
988	}
989
990	error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set);
991	if (error) {
992		gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib);
993		return (error);
994	}
995
996	/* Provide feedback if so requested. */
997	if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
998		sb = sbuf_new_auto();
999		sbuf_printf(sb, "%s%s has %s %sset\n", gp->name,
1000		    G_PART_NAME(table, entry, buf, sizeof(buf)),
1001		    gpp->gpp_attrib, (set) ? "" : "un");
1002		sbuf_finish(sb);
1003		gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1004		sbuf_delete(sb);
1005	}
1006	return (0);
1007}
1008
1009static int
1010g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp)
1011{
1012	struct g_consumer *cp;
1013	struct g_provider *pp;
1014	struct g_geom *gp;
1015	struct g_part_entry *entry, *tmp;
1016	struct g_part_table *table;
1017	int error, reprobe;
1018
1019	gp = gpp->gpp_geom;
1020	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1021	g_topology_assert();
1022
1023	table = gp->softc;
1024	if (!table->gpt_opened) {
1025		gctl_error(req, "%d", EPERM);
1026		return (EPERM);
1027	}
1028
1029	cp = LIST_FIRST(&gp->consumer);
1030	LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1031		entry->gpe_modified = 0;
1032		if (entry->gpe_created) {
1033			pp = entry->gpe_pp;
1034			if (pp != NULL) {
1035				pp->private = NULL;
1036				entry->gpe_pp = NULL;
1037				g_wither_provider(pp, ENXIO);
1038			}
1039			entry->gpe_deleted = 1;
1040		}
1041		if (entry->gpe_deleted) {
1042			LIST_REMOVE(entry, gpe_entry);
1043			g_free(entry);
1044		}
1045	}
1046
1047	g_topology_unlock();
1048
1049	reprobe = (table->gpt_scheme == &g_part_null_scheme ||
1050	    table->gpt_created) ? 1 : 0;
1051
1052	if (reprobe) {
1053		if (!LIST_EMPTY(&table->gpt_entry)) {
1054			error = EBUSY;
1055			goto fail;
1056		}
1057		error = g_part_probe(gp, cp, table->gpt_depth);
1058		if (error) {
1059			g_topology_lock();
1060			g_access(cp, -1, -1, -1);
1061			g_part_wither(gp, error);
1062			return (0);
1063		}
1064		table = gp->softc;
1065	}
1066
1067	error = G_PART_READ(table, cp);
1068	if (error)
1069		goto fail;
1070
1071	g_topology_lock();
1072
1073	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1074		if (!entry->gpe_internal)
1075			g_part_new_provider(gp, table, entry);
1076	}
1077
1078	table->gpt_opened = 0;
1079	g_access(cp, -1, -1, -1);
1080	return (0);
1081
1082fail:
1083	g_topology_lock();
1084	gctl_error(req, "%d", error);
1085	return (error);
1086}
1087
1088static void
1089g_part_wither(struct g_geom *gp, int error)
1090{
1091	struct g_part_entry *entry;
1092	struct g_part_table *table;
1093
1094	table = gp->softc;
1095	if (table != NULL) {
1096		while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1097			LIST_REMOVE(entry, gpe_entry);
1098			g_free(entry);
1099		}
1100		if (gp->softc != NULL) {
1101			kobj_delete((kobj_t)gp->softc, M_GEOM);
1102			gp->softc = NULL;
1103		}
1104	}
1105	g_wither_geom(gp, error);
1106}
1107
1108/*
1109 * Class methods.
1110 */
1111
1112static void
1113g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
1114{
1115	struct g_part_parms gpp;
1116	struct g_part_table *table;
1117	struct gctl_req_arg *ap;
1118	const char *p;
1119	enum g_part_ctl ctlreq;
1120	unsigned int i, mparms, oparms, parm;
1121	int auto_commit, close_on_error;
1122	int error, len, modifies;
1123
1124	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
1125	g_topology_assert();
1126
1127	ctlreq = G_PART_CTL_NONE;
1128	modifies = 1;
1129	mparms = 0;
1130	oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION;
1131	switch (*verb) {
1132	case 'a':
1133		if (!strcmp(verb, "add")) {
1134			ctlreq = G_PART_CTL_ADD;
1135			mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE |
1136			    G_PART_PARM_START | G_PART_PARM_TYPE;
1137			oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL;
1138		}
1139		break;
1140	case 'b':
1141		if (!strcmp(verb, "bootcode")) {
1142			ctlreq = G_PART_CTL_BOOTCODE;
1143			mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE;
1144		}
1145		break;
1146	case 'c':
1147		if (!strcmp(verb, "commit")) {
1148			ctlreq = G_PART_CTL_COMMIT;
1149			mparms |= G_PART_PARM_GEOM;
1150			modifies = 0;
1151		} else if (!strcmp(verb, "create")) {
1152			ctlreq = G_PART_CTL_CREATE;
1153			mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME;
1154			oparms |= G_PART_PARM_ENTRIES;
1155		}
1156		break;
1157	case 'd':
1158		if (!strcmp(verb, "delete")) {
1159			ctlreq = G_PART_CTL_DELETE;
1160			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1161		} else if (!strcmp(verb, "destroy")) {
1162			ctlreq = G_PART_CTL_DESTROY;
1163			mparms |= G_PART_PARM_GEOM;
1164		}
1165		break;
1166	case 'm':
1167		if (!strcmp(verb, "modify")) {
1168			ctlreq = G_PART_CTL_MODIFY;
1169			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1170			oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE;
1171		} else if (!strcmp(verb, "move")) {
1172			ctlreq = G_PART_CTL_MOVE;
1173			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1174		}
1175		break;
1176	case 'r':
1177		if (!strcmp(verb, "recover")) {
1178			ctlreq = G_PART_CTL_RECOVER;
1179			mparms |= G_PART_PARM_GEOM;
1180		} else if (!strcmp(verb, "resize")) {
1181			ctlreq = G_PART_CTL_RESIZE;
1182			mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1183		}
1184		break;
1185	case 's':
1186		if (!strcmp(verb, "set")) {
1187			ctlreq = G_PART_CTL_SET;
1188			mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM |
1189			    G_PART_PARM_INDEX;
1190		}
1191		break;
1192	case 'u':
1193		if (!strcmp(verb, "undo")) {
1194			ctlreq = G_PART_CTL_UNDO;
1195			mparms |= G_PART_PARM_GEOM;
1196			modifies = 0;
1197		} else if (!strcmp(verb, "unset")) {
1198			ctlreq = G_PART_CTL_UNSET;
1199			mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM |
1200			    G_PART_PARM_INDEX;
1201		}
1202		break;
1203	}
1204	if (ctlreq == G_PART_CTL_NONE) {
1205		gctl_error(req, "%d verb '%s'", EINVAL, verb);
1206		return;
1207	}
1208
1209	bzero(&gpp, sizeof(gpp));
1210	for (i = 0; i < req->narg; i++) {
1211		ap = &req->arg[i];
1212		parm = 0;
1213		switch (ap->name[0]) {
1214		case 'a':
1215			if (!strcmp(ap->name, "attrib"))
1216				parm = G_PART_PARM_ATTRIB;
1217			break;
1218		case 'b':
1219			if (!strcmp(ap->name, "bootcode"))
1220				parm = G_PART_PARM_BOOTCODE;
1221			break;
1222		case 'c':
1223			if (!strcmp(ap->name, "class"))
1224				continue;
1225			break;
1226		case 'e':
1227			if (!strcmp(ap->name, "entries"))
1228				parm = G_PART_PARM_ENTRIES;
1229			break;
1230		case 'f':
1231			if (!strcmp(ap->name, "flags"))
1232				parm = G_PART_PARM_FLAGS;
1233			break;
1234		case 'g':
1235			if (!strcmp(ap->name, "geom"))
1236				parm = G_PART_PARM_GEOM;
1237			break;
1238		case 'i':
1239			if (!strcmp(ap->name, "index"))
1240				parm = G_PART_PARM_INDEX;
1241			break;
1242		case 'l':
1243			if (!strcmp(ap->name, "label"))
1244				parm = G_PART_PARM_LABEL;
1245			break;
1246		case 'o':
1247			if (!strcmp(ap->name, "output"))
1248				parm = G_PART_PARM_OUTPUT;
1249			break;
1250		case 'p':
1251			if (!strcmp(ap->name, "provider"))
1252				parm = G_PART_PARM_PROVIDER;
1253			break;
1254		case 's':
1255			if (!strcmp(ap->name, "scheme"))
1256				parm = G_PART_PARM_SCHEME;
1257			else if (!strcmp(ap->name, "size"))
1258				parm = G_PART_PARM_SIZE;
1259			else if (!strcmp(ap->name, "start"))
1260				parm = G_PART_PARM_START;
1261			break;
1262		case 't':
1263			if (!strcmp(ap->name, "type"))
1264				parm = G_PART_PARM_TYPE;
1265			break;
1266		case 'v':
1267			if (!strcmp(ap->name, "verb"))
1268				continue;
1269			else if (!strcmp(ap->name, "version"))
1270				parm = G_PART_PARM_VERSION;
1271			break;
1272		}
1273		if ((parm & (mparms | oparms)) == 0) {
1274			gctl_error(req, "%d param '%s'", EINVAL, ap->name);
1275			return;
1276		}
1277		if (parm == G_PART_PARM_BOOTCODE)
1278			p = gctl_get_param(req, ap->name, &len);
1279		else
1280			p = gctl_get_asciiparam(req, ap->name);
1281		if (p == NULL) {
1282			gctl_error(req, "%d param '%s'", ENOATTR, ap->name);
1283			return;
1284		}
1285		switch (parm) {
1286		case G_PART_PARM_ATTRIB:
1287			error = g_part_parm_str(p, &gpp.gpp_attrib);
1288			break;
1289		case G_PART_PARM_BOOTCODE:
1290			gpp.gpp_codeptr = p;
1291			gpp.gpp_codesize = len;
1292			error = 0;
1293			break;
1294		case G_PART_PARM_ENTRIES:
1295			error = g_part_parm_uint(p, &gpp.gpp_entries);
1296			break;
1297		case G_PART_PARM_FLAGS:
1298			if (p[0] == '\0')
1299				continue;
1300			error = g_part_parm_str(p, &gpp.gpp_flags);
1301			break;
1302		case G_PART_PARM_GEOM:
1303			error = g_part_parm_geom(p, &gpp.gpp_geom);
1304			break;
1305		case G_PART_PARM_INDEX:
1306			error = g_part_parm_uint(p, &gpp.gpp_index);
1307			break;
1308		case G_PART_PARM_LABEL:
1309			/* An empty label is always valid. */
1310			gpp.gpp_label = p;
1311			error = 0;
1312			break;
1313		case G_PART_PARM_OUTPUT:
1314			error = 0;	/* Write-only parameter */
1315			break;
1316		case G_PART_PARM_PROVIDER:
1317			error = g_part_parm_provider(p, &gpp.gpp_provider);
1318			break;
1319		case G_PART_PARM_SCHEME:
1320			error = g_part_parm_scheme(p, &gpp.gpp_scheme);
1321			break;
1322		case G_PART_PARM_SIZE:
1323			error = g_part_parm_quad(p, &gpp.gpp_size);
1324			break;
1325		case G_PART_PARM_START:
1326			error = g_part_parm_quad(p, &gpp.gpp_start);
1327			break;
1328		case G_PART_PARM_TYPE:
1329			error = g_part_parm_str(p, &gpp.gpp_type);
1330			break;
1331		case G_PART_PARM_VERSION:
1332			error = g_part_parm_uint(p, &gpp.gpp_version);
1333			break;
1334		default:
1335			error = EDOOFUS;
1336			break;
1337		}
1338		if (error) {
1339			gctl_error(req, "%d %s '%s'", error, ap->name, p);
1340			return;
1341		}
1342		gpp.gpp_parms |= parm;
1343	}
1344	if ((gpp.gpp_parms & mparms) != mparms) {
1345		parm = mparms - (gpp.gpp_parms & mparms);
1346		gctl_error(req, "%d param '%x'", ENOATTR, parm);
1347		return;
1348	}
1349
1350	/* Obtain permissions if possible/necessary. */
1351	close_on_error = 0;
1352	table = NULL;	/* Suppress uninit. warning. */
1353	if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) {
1354		table = gpp.gpp_geom->softc;
1355		if (table != NULL && !table->gpt_opened) {
1356			error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer),
1357			    1, 1, 1);
1358			if (error) {
1359				gctl_error(req, "%d geom '%s'", error,
1360				    gpp.gpp_geom->name);
1361				return;
1362			}
1363			table->gpt_opened = 1;
1364			close_on_error = 1;
1365		}
1366	}
1367
1368	error = EDOOFUS;	/* Prevent bogus  uninit. warning. */
1369	switch (ctlreq) {
1370	case G_PART_CTL_NONE:
1371		panic("%s", __func__);
1372	case G_PART_CTL_ADD:
1373		error = g_part_ctl_add(req, &gpp);
1374		break;
1375	case G_PART_CTL_BOOTCODE:
1376		error = g_part_ctl_bootcode(req, &gpp);
1377		break;
1378	case G_PART_CTL_COMMIT:
1379		error = g_part_ctl_commit(req, &gpp);
1380		break;
1381	case G_PART_CTL_CREATE:
1382		error = g_part_ctl_create(req, &gpp);
1383		break;
1384	case G_PART_CTL_DELETE:
1385		error = g_part_ctl_delete(req, &gpp);
1386		break;
1387	case G_PART_CTL_DESTROY:
1388		error = g_part_ctl_destroy(req, &gpp);
1389		break;
1390	case G_PART_CTL_MODIFY:
1391		error = g_part_ctl_modify(req, &gpp);
1392		break;
1393	case G_PART_CTL_MOVE:
1394		error = g_part_ctl_move(req, &gpp);
1395		break;
1396	case G_PART_CTL_RECOVER:
1397		error = g_part_ctl_recover(req, &gpp);
1398		break;
1399	case G_PART_CTL_RESIZE:
1400		error = g_part_ctl_resize(req, &gpp);
1401		break;
1402	case G_PART_CTL_SET:
1403		error = g_part_ctl_setunset(req, &gpp, 1);
1404		break;
1405	case G_PART_CTL_UNDO:
1406		error = g_part_ctl_undo(req, &gpp);
1407		break;
1408	case G_PART_CTL_UNSET:
1409		error = g_part_ctl_setunset(req, &gpp, 0);
1410		break;
1411	}
1412
1413	/* Implement automatic commit. */
1414	if (!error) {
1415		auto_commit = (modifies &&
1416		    (gpp.gpp_parms & G_PART_PARM_FLAGS) &&
1417		    strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0;
1418		if (auto_commit) {
1419			KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__));
1420			error = g_part_ctl_commit(req, &gpp);
1421		}
1422	}
1423
1424	if (error && close_on_error) {
1425		g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1);
1426		table->gpt_opened = 0;
1427	}
1428}
1429
1430static int
1431g_part_destroy_geom(struct gctl_req *req, struct g_class *mp,
1432    struct g_geom *gp)
1433{
1434
1435	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
1436	g_topology_assert();
1437
1438	g_part_wither(gp, EINVAL);
1439	return (0);
1440}
1441
1442static struct g_geom *
1443g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
1444{
1445	struct g_consumer *cp;
1446	struct g_geom *gp;
1447	struct g_part_entry *entry;
1448	struct g_part_table *table;
1449	struct root_hold_token *rht;
1450	int attr, depth;
1451	int error;
1452
1453	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
1454	g_topology_assert();
1455
1456	/*
1457	 * Create a GEOM with consumer and hook it up to the provider.
1458	 * With that we become part of the topology. Optain read access
1459	 * to the provider.
1460	 */
1461	gp = g_new_geomf(mp, "%s", pp->name);
1462	cp = g_new_consumer(gp);
1463	error = g_attach(cp, pp);
1464	if (error == 0)
1465		error = g_access(cp, 1, 0, 0);
1466	if (error != 0) {
1467		g_part_wither(gp, error);
1468		return (NULL);
1469	}
1470
1471	rht = root_mount_hold(mp->name);
1472	g_topology_unlock();
1473
1474	/*
1475	 * Short-circuit the whole probing galore when there's no
1476	 * media present.
1477	 */
1478	if (pp->mediasize == 0 || pp->sectorsize == 0) {
1479		error = ENODEV;
1480		goto fail;
1481	}
1482
1483	/* Make sure we can nest and if so, determine our depth. */
1484	error = g_getattr("PART::isleaf", cp, &attr);
1485	if (!error && attr) {
1486		error = ENODEV;
1487		goto fail;
1488	}
1489	error = g_getattr("PART::depth", cp, &attr);
1490	depth = (!error) ? attr + 1 : 0;
1491
1492	error = g_part_probe(gp, cp, depth);
1493	if (error)
1494		goto fail;
1495
1496	table = gp->softc;
1497
1498	/* If we're nested, get the absolute sector offset on disk. */
1499	if (table->gpt_depth) {
1500		error = g_getattr("PART::offset", cp, &attr);
1501		if (error)
1502			goto fail;
1503		table->gpt_offset = attr;
1504	}
1505
1506	/*
1507	 * Synthesize a disk geometry. Some partitioning schemes
1508	 * depend on it and since some file systems need it even
1509	 * when the partitition scheme doesn't, we do it here in
1510	 * scheme-independent code.
1511	 */
1512	g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1513
1514	error = G_PART_READ(table, cp);
1515	if (error)
1516		goto fail;
1517
1518	g_topology_lock();
1519	LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1520		if (!entry->gpe_internal)
1521			g_part_new_provider(gp, table, entry);
1522	}
1523
1524	root_mount_rel(rht);
1525	g_access(cp, -1, 0, 0);
1526	return (gp);
1527
1528 fail:
1529	g_topology_lock();
1530	root_mount_rel(rht);
1531	g_access(cp, -1, 0, 0);
1532	g_part_wither(gp, error);
1533	return (NULL);
1534}
1535
1536/*
1537 * Geom methods.
1538 */
1539
1540static int
1541g_part_access(struct g_provider *pp, int dr, int dw, int de)
1542{
1543	struct g_consumer *cp;
1544
1545	G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr,
1546	    dw, de));
1547
1548	cp = LIST_FIRST(&pp->geom->consumer);
1549
1550	/* We always gain write-exclusive access. */
1551	return (g_access(cp, dr, dw, dw + de));
1552}
1553
1554static void
1555g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1556    struct g_consumer *cp, struct g_provider *pp)
1557{
1558	char buf[64];
1559	struct g_part_entry *entry;
1560	struct g_part_table *table;
1561
1562	KASSERT(sb != NULL && gp != NULL, (__func__));
1563	table = gp->softc;
1564
1565	if (indent == NULL) {
1566		KASSERT(cp == NULL && pp != NULL, (__func__));
1567		entry = pp->private;
1568		if (entry == NULL)
1569			return;
1570		sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index,
1571		    (uintmax_t)entry->gpe_offset,
1572		    G_PART_TYPE(table, entry, buf, sizeof(buf)));
1573		/*
1574		 * libdisk compatibility quirk - the scheme dumps the
1575		 * slicer name and partition type in a way that is
1576		 * compatible with libdisk. When libdisk is not used
1577		 * anymore, this should go away.
1578		 */
1579		G_PART_DUMPCONF(table, entry, sb, indent);
1580	} else if (cp != NULL) {	/* Consumer configuration. */
1581		KASSERT(pp == NULL, (__func__));
1582		/* none */
1583	} else if (pp != NULL) {	/* Provider configuration. */
1584		entry = pp->private;
1585		if (entry == NULL)
1586			return;
1587		sbuf_printf(sb, "%s<start>%ju</start>\n", indent,
1588		    (uintmax_t)entry->gpe_start);
1589		sbuf_printf(sb, "%s<end>%ju</end>\n", indent,
1590		    (uintmax_t)entry->gpe_end);
1591		sbuf_printf(sb, "%s<index>%u</index>\n", indent,
1592		    entry->gpe_index);
1593		sbuf_printf(sb, "%s<type>%s</type>\n", indent,
1594		    G_PART_TYPE(table, entry, buf, sizeof(buf)));
1595		sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
1596		    (uintmax_t)entry->gpe_offset);
1597		sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
1598		    (uintmax_t)pp->mediasize);
1599		G_PART_DUMPCONF(table, entry, sb, indent);
1600	} else {			/* Geom configuration. */
1601		sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent,
1602		    table->gpt_scheme->name);
1603		sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
1604		    table->gpt_entries);
1605		sbuf_printf(sb, "%s<first>%ju</first>\n", indent,
1606		    (uintmax_t)table->gpt_first);
1607		sbuf_printf(sb, "%s<last>%ju</last>\n", indent,
1608		    (uintmax_t)table->gpt_last);
1609		sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent,
1610		    table->gpt_sectors);
1611		sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent,
1612		    table->gpt_heads);
1613		G_PART_DUMPCONF(table, NULL, sb, indent);
1614	}
1615}
1616
1617static void
1618g_part_orphan(struct g_consumer *cp)
1619{
1620	struct g_provider *pp;
1621
1622	pp = cp->provider;
1623	KASSERT(pp != NULL, (__func__));
1624	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
1625	g_topology_assert();
1626
1627	KASSERT(pp->error != 0, (__func__));
1628	g_part_wither(cp->geom, pp->error);
1629}
1630
1631static void
1632g_part_spoiled(struct g_consumer *cp)
1633{
1634
1635	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
1636	g_topology_assert();
1637
1638	g_part_wither(cp->geom, ENXIO);
1639}
1640
1641static void
1642g_part_start(struct bio *bp)
1643{
1644	struct bio *bp2;
1645	struct g_consumer *cp;
1646	struct g_geom *gp;
1647	struct g_part_entry *entry;
1648	struct g_part_table *table;
1649	struct g_kerneldump *gkd;
1650	struct g_provider *pp;
1651
1652	pp = bp->bio_to;
1653	gp = pp->geom;
1654	table = gp->softc;
1655	cp = LIST_FIRST(&gp->consumer);
1656
1657	G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
1658	    pp->name));
1659
1660	entry = pp->private;
1661	if (entry == NULL) {
1662		g_io_deliver(bp, ENXIO);
1663		return;
1664	}
1665
1666	switch(bp->bio_cmd) {
1667	case BIO_DELETE:
1668	case BIO_READ:
1669	case BIO_WRITE:
1670		if (bp->bio_offset >= pp->mediasize) {
1671			g_io_deliver(bp, EIO);
1672			return;
1673		}
1674		bp2 = g_clone_bio(bp);
1675		if (bp2 == NULL) {
1676			g_io_deliver(bp, ENOMEM);
1677			return;
1678		}
1679		if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
1680			bp2->bio_length = pp->mediasize - bp2->bio_offset;
1681		bp2->bio_done = g_std_done;
1682		bp2->bio_offset += entry->gpe_offset;
1683		g_io_request(bp2, cp);
1684		return;
1685	case BIO_FLUSH:
1686		break;
1687	case BIO_GETATTR:
1688		if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads))
1689			return;
1690		if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors))
1691			return;
1692		if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf))
1693			return;
1694		if (g_handleattr_int(bp, "PART::depth", table->gpt_depth))
1695			return;
1696		if (g_handleattr_int(bp, "PART::offset",
1697		    table->gpt_offset + entry->gpe_start))
1698			return;
1699		if (g_handleattr_str(bp, "PART::scheme",
1700		    table->gpt_scheme->name))
1701			return;
1702		if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
1703			/*
1704			 * Check that the partition is suitable for kernel
1705			 * dumps. Typically only swap partitions should be
1706			 * used.
1707			 */
1708			if (!G_PART_DUMPTO(table, entry)) {
1709				g_io_deliver(bp, ENXIO);
1710				return;
1711			}
1712			gkd = (struct g_kerneldump *)bp->bio_data;
1713			if (gkd->offset >= pp->mediasize) {
1714				g_io_deliver(bp, EIO);
1715				return;
1716			}
1717			if (gkd->offset + gkd->length > pp->mediasize)
1718				gkd->length = pp->mediasize - gkd->offset;
1719			gkd->offset += entry->gpe_offset;
1720		}
1721		break;
1722	default:
1723		g_io_deliver(bp, EOPNOTSUPP);
1724		return;
1725	}
1726
1727	bp2 = g_clone_bio(bp);
1728	if (bp2 == NULL) {
1729		g_io_deliver(bp, ENOMEM);
1730		return;
1731	}
1732	bp2->bio_done = g_std_done;
1733	g_io_request(bp2, cp);
1734}
1735
1736static void
1737g_part_init(struct g_class *mp)
1738{
1739
1740	TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
1741}
1742
1743static void
1744g_part_fini(struct g_class *mp)
1745{
1746
1747	TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
1748}
1749
1750static void
1751g_part_unload_event(void *arg, int flag)
1752{
1753	struct g_consumer *cp;
1754	struct g_geom *gp;
1755	struct g_provider *pp;
1756	struct g_part_scheme *scheme;
1757	struct g_part_table *table;
1758	uintptr_t *xchg;
1759	int acc, error;
1760
1761	if (flag == EV_CANCEL)
1762		return;
1763
1764	xchg = arg;
1765	error = 0;
1766	scheme = (void *)(*xchg);
1767
1768	g_topology_assert();
1769
1770	LIST_FOREACH(gp, &g_part_class.geom, geom) {
1771		table = gp->softc;
1772		if (table->gpt_scheme != scheme)
1773			continue;
1774
1775		acc = 0;
1776		LIST_FOREACH(pp, &gp->provider, provider)
1777			acc += pp->acr + pp->acw + pp->ace;
1778		LIST_FOREACH(cp, &gp->consumer, consumer)
1779			acc += cp->acr + cp->acw + cp->ace;
1780
1781		if (!acc)
1782			g_part_wither(gp, ENOSYS);
1783		else
1784			error = EBUSY;
1785	}
1786
1787	if (!error)
1788		TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
1789
1790	*xchg = error;
1791}
1792
1793int
1794g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme)
1795{
1796	uintptr_t arg;
1797	int error;
1798
1799	switch (type) {
1800	case MOD_LOAD:
1801		TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list);
1802
1803		error = g_retaste(&g_part_class);
1804		if (error)
1805			TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
1806		break;
1807	case MOD_UNLOAD:
1808		arg = (uintptr_t)scheme;
1809		error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK,
1810		    NULL);
1811		if (!error)
1812			error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg;
1813		break;
1814	default:
1815		error = EOPNOTSUPP;
1816		break;
1817	}
1818
1819	return (error);
1820}
1821