The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/part/g_part.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: 56eb0383af000f00ce59ef0b5c0962b5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.