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