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