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, §ors) != 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