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