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