g_part.c revision 267357
1118611Snjl/*- 2118611Snjl * Copyright (c) 2002, 2005-2009 Marcel Moolenaar 3118611Snjl * All rights reserved. 4118611Snjl * 5118611Snjl * Redistribution and use in source and binary forms, with or without 6118611Snjl * modification, are permitted provided that the following conditions 7118611Snjl * are met: 8217365Sjkim * 9229989Sjkim * 1. Redistributions of source code must retain the above copyright 10118611Snjl * notice, this list of conditions and the following disclaimer. 11118611Snjl * 2. Redistributions in binary form must reproduce the above copyright 12217365Sjkim * notice, this list of conditions and the following disclaimer in the 13217365Sjkim * documentation and/or other materials provided with the distribution. 14217365Sjkim * 15217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16217365Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17217365Sjkim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18217365Sjkim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19217365Sjkim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20217365Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21217365Sjkim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22217365Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23217365Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24217365Sjkim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25217365Sjkim */ 26118611Snjl 27217365Sjkim#include <sys/cdefs.h> 28217365Sjkim__FBSDID("$FreeBSD: head/sys/geom/part/g_part.c 267357 2014-06-11 10:19:11Z ae $"); 29217365Sjkim 30118611Snjl#include <sys/param.h> 31217365Sjkim#include <sys/bio.h> 32217365Sjkim#include <sys/endian.h> 33217365Sjkim#include <sys/kernel.h> 34217365Sjkim#include <sys/kobj.h> 35217365Sjkim#include <sys/limits.h> 36217365Sjkim#include <sys/lock.h> 37217365Sjkim#include <sys/malloc.h> 38217365Sjkim#include <sys/mutex.h> 39217365Sjkim#include <sys/queue.h> 40217365Sjkim#include <sys/sbuf.h> 41217365Sjkim#include <sys/sysctl.h> 42217365Sjkim#include <sys/systm.h> 43217365Sjkim#include <sys/uuid.h> 44118611Snjl#include <geom/geom.h> 45118611Snjl#include <geom/geom_ctl.h> 46151937Sjkim#include <geom/geom_int.h> 47118611Snjl#include <geom/part/g_part.h> 48228110Sjkim 49218590Sjkim#include "g_part_if.h" 50118611Snjl 51118611Snjl#ifndef _PATH_DEV 52118611Snjl#define _PATH_DEV "/dev/" 53118611Snjl#endif 54151937Sjkim 55118611Snjlstatic kobj_method_t g_part_null_methods[] = { 56151937Sjkim { 0, 0 } 57151937Sjkim}; 58151937Sjkim 59151937Sjkimstatic struct g_part_scheme g_part_null_scheme = { 60151937Sjkim "(none)", 61151937Sjkim g_part_null_methods, 62151937Sjkim sizeof(struct g_part_table), 63151937Sjkim}; 64151937Sjkim 65118611SnjlTAILQ_HEAD(, g_part_scheme) g_part_schemes = 66118611Snjl TAILQ_HEAD_INITIALIZER(g_part_schemes); 67118611Snjl 68118611Snjlstruct g_part_alias_list { 69118611Snjl const char *lexeme; 70118611Snjl enum g_part_alias alias; 71239340Sjkim} g_part_alias_list[G_PART_ALIAS_COUNT] = { 72118611Snjl { "apple-boot", G_PART_ALIAS_APPLE_BOOT }, 73239340Sjkim { "apple-hfs", G_PART_ALIAS_APPLE_HFS }, 74118611Snjl { "apple-label", G_PART_ALIAS_APPLE_LABEL }, 75118611Snjl { "apple-raid", G_PART_ALIAS_APPLE_RAID }, 76118611Snjl { "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE }, 77118611Snjl { "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY }, 78118611Snjl { "apple-ufs", G_PART_ALIAS_APPLE_UFS }, 79151937Sjkim { "bios-boot", G_PART_ALIAS_BIOS_BOOT }, 80151937Sjkim { "ebr", G_PART_ALIAS_EBR }, 81151937Sjkim { "efi", G_PART_ALIAS_EFI }, 82118611Snjl { "fat16", G_PART_ALIAS_MS_FAT16 }, 83118611Snjl { "fat32", G_PART_ALIAS_MS_FAT32 }, 84118611Snjl { "freebsd", G_PART_ALIAS_FREEBSD }, 85118611Snjl { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT }, 86151937Sjkim { "freebsd-nandfs", G_PART_ALIAS_FREEBSD_NANDFS }, 87151937Sjkim { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP }, 88118611Snjl { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS }, 89118611Snjl { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM }, 90118611Snjl { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS }, 91118611Snjl { "linux-data", G_PART_ALIAS_LINUX_DATA }, 92118611Snjl { "linux-lvm", G_PART_ALIAS_LINUX_LVM }, 93118611Snjl { "linux-raid", G_PART_ALIAS_LINUX_RAID }, 94118611Snjl { "linux-swap", G_PART_ALIAS_LINUX_SWAP }, 95118611Snjl { "mbr", G_PART_ALIAS_MBR }, 96118611Snjl { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA }, 97118611Snjl { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA }, 98118611Snjl { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA }, 99118611Snjl { "ms-reserved", G_PART_ALIAS_MS_RESERVED }, 100118611Snjl { "ntfs", G_PART_ALIAS_MS_NTFS }, 101239340Sjkim { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD }, 102118611Snjl { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD }, 103118611Snjl { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS }, 104118611Snjl { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS }, 105118611Snjl { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID }, 106118611Snjl { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP }, 107118611Snjl { "vmware-vmfs", G_PART_ALIAS_VMFS }, 108118611Snjl { "vmware-vmkdiag", G_PART_ALIAS_VMKDIAG }, 109118611Snjl { "vmware-reserved", G_PART_ALIAS_VMRESERVED }, 110118611Snjl { "vmware-vsanhdr", G_PART_ALIAS_VMVSANHDR }, 111118611Snjl { "dragonfly-label32", G_PART_ALIAS_DFBSD }, 112118611Snjl { "dragonfly-label64", G_PART_ALIAS_DFBSD64 }, 113118611Snjl { "dragonfly-swap", G_PART_ALIAS_DFBSD_SWAP }, 114118611Snjl { "dragonfly-ufs", G_PART_ALIAS_DFBSD_UFS }, 115118611Snjl { "dragonfly-vinum", G_PART_ALIAS_DFBSD_VINUM }, 116118611Snjl { "dragonfly-ccd", G_PART_ALIAS_DFBSD_CCD }, 117118611Snjl { "dragonfly-legacy", G_PART_ALIAS_DFBSD_LEGACY }, 118118611Snjl { "dragonfly-hammer", G_PART_ALIAS_DFBSD_HAMMER }, 119118611Snjl { "dragonfly-hammer2", G_PART_ALIAS_DFBSD_HAMMER2 }, 120118611Snjl}; 121118611Snjl 122118611SnjlSYSCTL_DECL(_kern_geom); 123118611SnjlSYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW, 0, 124118611Snjl "GEOM_PART stuff"); 125118611Snjlstatic u_int check_integrity = 1; 126118611SnjlTUNABLE_INT("kern.geom.part.check_integrity", &check_integrity); 127118611SnjlSYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity, 128118611Snjl CTLFLAG_RW | CTLFLAG_TUN, &check_integrity, 1, 129118611Snjl "Enable integrity checking"); 130118611Snjl 131118611Snjl/* 132118611Snjl * The GEOM partitioning class. 133118611Snjl */ 134118611Snjlstatic g_ctl_req_t g_part_ctlreq; 135118611Snjlstatic g_ctl_destroy_geom_t g_part_destroy_geom; 136239340Sjkimstatic g_fini_t g_part_fini; 137118611Snjlstatic g_init_t g_part_init; 138118611Snjlstatic g_taste_t g_part_taste; 139118611Snjl 140118611Snjlstatic g_access_t g_part_access; 141118611Snjlstatic g_dumpconf_t g_part_dumpconf; 142118611Snjlstatic g_orphan_t g_part_orphan; 143118611Snjlstatic g_spoiled_t g_part_spoiled; 144118611Snjlstatic g_start_t g_part_start; 145118611Snjlstatic g_resize_t g_part_resize; 146118611Snjl 147118611Snjlstatic struct g_class g_part_class = { 148118611Snjl .name = "PART", 149118611Snjl .version = G_VERSION, 150118611Snjl /* Class methods. */ 151118611Snjl .ctlreq = g_part_ctlreq, 152118611Snjl .destroy_geom = g_part_destroy_geom, 153118611Snjl .fini = g_part_fini, 154118611Snjl .init = g_part_init, 155118611Snjl .taste = g_part_taste, 156118611Snjl /* Geom methods. */ 157118611Snjl .access = g_part_access, 158118611Snjl .dumpconf = g_part_dumpconf, 159239340Sjkim .orphan = g_part_orphan, 160118611Snjl .spoiled = g_part_spoiled, 161239340Sjkim .start = g_part_start, 162118611Snjl .resize = g_part_resize 163118611Snjl}; 164118611Snjl 165118611SnjlDECLARE_GEOM_CLASS(g_part_class, g_part); 166118611SnjlMODULE_VERSION(g_part, 0); 167118611Snjl 168118611Snjl/* 169118611Snjl * Support functions. 170118611Snjl */ 171118611Snjl 172118611Snjlstatic void g_part_wither(struct g_geom *, int); 173118611Snjl 174118611Snjlconst char * 175118611Snjlg_part_alias_name(enum g_part_alias alias) 176118611Snjl{ 177118611Snjl int i; 178118611Snjl 179118611Snjl for (i = 0; i < G_PART_ALIAS_COUNT; i++) { 180118611Snjl if (g_part_alias_list[i].alias != alias) 181118611Snjl continue; 182118611Snjl return (g_part_alias_list[i].lexeme); 183118611Snjl } 184118611Snjl 185118611Snjl return (NULL); 186118611Snjl} 187118611Snjl 188118611Snjlvoid 189239340Sjkimg_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs, 190118611Snjl u_int *bestheads) 191118611Snjl{ 192118611Snjl static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 }; 193239340Sjkim off_t chs, cylinders; 194118611Snjl u_int heads; 195118611Snjl int idx; 196118611Snjl 197239340Sjkim *bestchs = 0; 198118611Snjl *bestheads = 0; 199118611Snjl for (idx = 0; candidate_heads[idx] != 0; idx++) { 200239340Sjkim heads = candidate_heads[idx]; 201239340Sjkim cylinders = blocks / heads / sectors; 202118611Snjl if (cylinders < heads || cylinders < sectors) 203239340Sjkim break; 204118611Snjl if (cylinders > 1023) 205118611Snjl continue; 206118611Snjl chs = cylinders * heads * sectors; 207118611Snjl if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) { 208118611Snjl *bestchs = chs; 209118611Snjl *bestheads = heads; 210118611Snjl } 211118611Snjl } 212118611Snjl} 213118611Snjl 214118611Snjlstatic void 215118611Snjlg_part_geometry(struct g_part_table *table, struct g_consumer *cp, 216118611Snjl off_t blocks) 217118611Snjl{ 218239340Sjkim static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 }; 219239340Sjkim off_t chs, bestchs; 220118611Snjl u_int heads, sectors; 221118611Snjl int idx; 222118611Snjl 223239340Sjkim if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || sectors == 0 || 224239340Sjkim g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) { 225118611Snjl table->gpt_fixgeom = 0; 226118611Snjl table->gpt_heads = 0; 227118611Snjl table->gpt_sectors = 0; 228239340Sjkim bestchs = 0; 229239340Sjkim for (idx = 0; candidate_sectors[idx] != 0; idx++) { 230118611Snjl sectors = candidate_sectors[idx]; 231118611Snjl g_part_geometry_heads(blocks, sectors, &chs, &heads); 232118611Snjl if (chs == 0) 233118611Snjl continue; 234118611Snjl /* 235118611Snjl * Prefer a geometry with sectors > 1, but only if 236118611Snjl * it doesn't bump down the number of heads to 1. 237118611Snjl */ 238118611Snjl if (chs > bestchs || (chs == bestchs && heads > 1 && 239118611Snjl table->gpt_sectors == 1)) { 240118611Snjl bestchs = chs; 241118611Snjl table->gpt_heads = heads; 242118611Snjl table->gpt_sectors = sectors; 243118611Snjl } 244118611Snjl } 245118611Snjl /* 246118611Snjl * If we didn't find a geometry at all, then the disk is 247151937Sjkim * too big. This means we can use the maximum number of 248118611Snjl * heads and sectors. 249118611Snjl */ 250118611Snjl if (bestchs == 0) { 251118611Snjl table->gpt_heads = 255; 252118611Snjl table->gpt_sectors = 63; 253151937Sjkim } 254118611Snjl } else { 255118611Snjl table->gpt_fixgeom = 1; 256118611Snjl table->gpt_heads = heads; 257118611Snjl table->gpt_sectors = sectors; 258118611Snjl } 259118611Snjl} 260118611Snjl 261118611Snjl#define DPRINTF(...) if (bootverbose) { \ 262118611Snjl printf("GEOM_PART: " __VA_ARGS__); \ 263118611Snjl} 264118611Snjl 265118611Snjlstatic int 266118611Snjlg_part_check_integrity(struct g_part_table *table, struct g_consumer *cp) 267118611Snjl{ 268118611Snjl struct g_part_entry *e1, *e2; 269118611Snjl struct g_provider *pp; 270118611Snjl off_t offset; 271118611Snjl int failed; 272118611Snjl 273118611Snjl failed = 0; 274118611Snjl pp = cp->provider; 275118611Snjl if (table->gpt_last < table->gpt_first) { 276118611Snjl DPRINTF("last LBA is below first LBA: %jd < %jd\n", 277118611Snjl (intmax_t)table->gpt_last, (intmax_t)table->gpt_first); 278118611Snjl failed++; 279118611Snjl } 280118611Snjl if (table->gpt_last > pp->mediasize / pp->sectorsize - 1) { 281118611Snjl DPRINTF("last LBA extends beyond mediasize: " 282118611Snjl "%jd > %jd\n", (intmax_t)table->gpt_last, 283118611Snjl (intmax_t)pp->mediasize / pp->sectorsize - 1); 284118611Snjl failed++; 285118611Snjl } 286118611Snjl LIST_FOREACH(e1, &table->gpt_entry, gpe_entry) { 287118611Snjl if (e1->gpe_deleted || e1->gpe_internal) 288118611Snjl continue; 289118611Snjl if (e1->gpe_start < table->gpt_first) { 290118611Snjl DPRINTF("partition %d has start offset below first " 291118611Snjl "LBA: %jd < %jd\n", e1->gpe_index, 292118611Snjl (intmax_t)e1->gpe_start, 293118611Snjl (intmax_t)table->gpt_first); 294118611Snjl failed++; 295118611Snjl } 296118611Snjl if (e1->gpe_start > table->gpt_last) { 297118611Snjl DPRINTF("partition %d has start offset beyond last " 298118611Snjl "LBA: %jd > %jd\n", e1->gpe_index, 299118611Snjl (intmax_t)e1->gpe_start, 300118611Snjl (intmax_t)table->gpt_last); 301118611Snjl failed++; 302118611Snjl } 303118611Snjl if (e1->gpe_end < e1->gpe_start) { 304118611Snjl DPRINTF("partition %d has end offset below start " 305118611Snjl "offset: %jd < %jd\n", e1->gpe_index, 306118611Snjl (intmax_t)e1->gpe_end, 307118611Snjl (intmax_t)e1->gpe_start); 308118611Snjl failed++; 309118611Snjl } 310118611Snjl if (e1->gpe_end > table->gpt_last) { 311118611Snjl DPRINTF("partition %d has end offset beyond last " 312118611Snjl "LBA: %jd > %jd\n", e1->gpe_index, 313118611Snjl (intmax_t)e1->gpe_end, 314118611Snjl (intmax_t)table->gpt_last); 315118611Snjl failed++; 316118611Snjl } 317118611Snjl if (pp->stripesize > 0) { 318151937Sjkim offset = e1->gpe_start * pp->sectorsize; 319118611Snjl if (e1->gpe_offset > offset) 320118611Snjl offset = e1->gpe_offset; 321151937Sjkim if ((offset + pp->stripeoffset) % pp->stripesize) { 322118611Snjl DPRINTF("partition %d is not aligned on %u " 323239340Sjkim "bytes\n", e1->gpe_index, pp->stripesize); 324118611Snjl /* Don't treat this as a critical failure */ 325118611Snjl } 326118611Snjl } 327118611Snjl e2 = e1; 328118611Snjl while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) { 329118611Snjl if (e2->gpe_deleted || e2->gpe_internal) 330118611Snjl continue; 331118611Snjl if (e1->gpe_start >= e2->gpe_start && 332118611Snjl e1->gpe_start <= e2->gpe_end) { 333118611Snjl DPRINTF("partition %d has start offset inside " 334151937Sjkim "partition %d: start[%d] %jd >= start[%d] " 335151937Sjkim "%jd <= end[%d] %jd\n", 336118611Snjl e1->gpe_index, e2->gpe_index, 337118611Snjl e2->gpe_index, (intmax_t)e2->gpe_start, 338118611Snjl e1->gpe_index, (intmax_t)e1->gpe_start, 339118611Snjl e2->gpe_index, (intmax_t)e2->gpe_end); 340118611Snjl failed++; 341118611Snjl } 342118611Snjl if (e1->gpe_end >= e2->gpe_start && 343239340Sjkim e1->gpe_end <= e2->gpe_end) { 344239340Sjkim DPRINTF("partition %d has end offset inside " 345118611Snjl "partition %d: start[%d] %jd >= end[%d] " 346239340Sjkim "%jd <= end[%d] %jd\n", 347239340Sjkim e1->gpe_index, e2->gpe_index, 348239340Sjkim e2->gpe_index, (intmax_t)e2->gpe_start, 349239340Sjkim e1->gpe_index, (intmax_t)e1->gpe_end, 350239340Sjkim e2->gpe_index, (intmax_t)e2->gpe_end); 351239340Sjkim failed++; 352239340Sjkim } 353239340Sjkim if (e1->gpe_start < e2->gpe_start && 354239340Sjkim e1->gpe_end > e2->gpe_end) { 355239340Sjkim DPRINTF("partition %d contains partition %d: " 356239340Sjkim "start[%d] %jd > start[%d] %jd, end[%d] " 357239340Sjkim "%jd < end[%d] %jd\n", 358239340Sjkim e1->gpe_index, e2->gpe_index, 359239340Sjkim e1->gpe_index, (intmax_t)e1->gpe_start, 360239340Sjkim e2->gpe_index, (intmax_t)e2->gpe_start, 361239340Sjkim e2->gpe_index, (intmax_t)e2->gpe_end, 362239340Sjkim e1->gpe_index, (intmax_t)e1->gpe_end); 363239340Sjkim failed++; 364239340Sjkim } 365239340Sjkim } 366239340Sjkim } 367239340Sjkim if (failed != 0) { 368239340Sjkim printf("GEOM_PART: integrity check failed (%s, %s)\n", 369239340Sjkim pp->name, table->gpt_scheme->name); 370239340Sjkim if (check_integrity != 0) 371239340Sjkim return (EINVAL); 372239340Sjkim table->gpt_corrupt = 1; 373239340Sjkim } 374239340Sjkim return (0); 375239340Sjkim} 376239340Sjkim#undef DPRINTF 377239340Sjkim 378118611Snjlstruct g_part_entry * 379118611Snjlg_part_new_entry(struct g_part_table *table, int index, quad_t start, 380118611Snjl quad_t end) 381118611Snjl{ 382118611Snjl struct g_part_entry *entry, *last; 383118611Snjl 384118611Snjl last = NULL; 385118611Snjl LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 386118611Snjl if (entry->gpe_index == index) 387118611Snjl break; 388118611Snjl if (entry->gpe_index > index) { 389118611Snjl entry = NULL; 390118611Snjl break; 391118611Snjl } 392118611Snjl last = entry; 393118611Snjl } 394118611Snjl if (entry == NULL) { 395118611Snjl entry = g_malloc(table->gpt_scheme->gps_entrysz, 396118611Snjl M_WAITOK | M_ZERO); 397118611Snjl entry->gpe_index = index; 398118611Snjl if (last == NULL) 399118611Snjl LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 400118611Snjl else 401118611Snjl LIST_INSERT_AFTER(last, entry, gpe_entry); 402118611Snjl } else 403118611Snjl entry->gpe_offset = 0; 404118611Snjl entry->gpe_start = start; 405118611Snjl entry->gpe_end = end; 406118611Snjl return (entry); 407118611Snjl} 408118611Snjl 409118611Snjlstatic void 410118611Snjlg_part_new_provider(struct g_geom *gp, struct g_part_table *table, 411118611Snjl struct g_part_entry *entry) 412118611Snjl{ 413118611Snjl struct g_consumer *cp; 414118611Snjl struct g_provider *pp; 415118611Snjl struct sbuf *sb; 416118611Snjl off_t offset; 417239340Sjkim 418118611Snjl cp = LIST_FIRST(&gp->consumer); 419118611Snjl pp = cp->provider; 420118611Snjl 421118611Snjl offset = entry->gpe_start * pp->sectorsize; 422118611Snjl if (entry->gpe_offset < offset) 423118611Snjl entry->gpe_offset = offset; 424118611Snjl 425118611Snjl if (entry->gpe_pp == NULL) { 426118611Snjl sb = sbuf_new_auto(); 427118611Snjl G_PART_FULLNAME(table, entry, sb, gp->name); 428118611Snjl sbuf_finish(sb); 429118611Snjl entry->gpe_pp = g_new_providerf(gp, "%s", sbuf_data(sb)); 430118611Snjl sbuf_delete(sb); 431118611Snjl entry->gpe_pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 432118611Snjl entry->gpe_pp->private = entry; /* Close the circle. */ 433118611Snjl } 434209746Sjkim entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */ 435167802Sjkim entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 436118611Snjl pp->sectorsize; 437118611Snjl entry->gpe_pp->mediasize -= entry->gpe_offset - offset; 438118611Snjl entry->gpe_pp->sectorsize = pp->sectorsize; 439118611Snjl entry->gpe_pp->stripesize = pp->stripesize; 440118611Snjl entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset; 441118611Snjl if (pp->stripesize > 0) 442118611Snjl entry->gpe_pp->stripeoffset %= pp->stripesize; 443218590Sjkim entry->gpe_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 444218590Sjkim g_error_provider(entry->gpe_pp, 0); 445218590Sjkim} 446218590Sjkim 447239340Sjkimstatic struct g_geom* 448218590Sjkimg_part_find_geom(const char *name) 449218590Sjkim{ 450218590Sjkim struct g_geom *gp; 451218590Sjkim LIST_FOREACH(gp, &g_part_class.geom, geom) { 452218590Sjkim if (!strcmp(name, gp->name)) 453218590Sjkim break; 454218590Sjkim } 455218590Sjkim return (gp); 456218590Sjkim} 457218590Sjkim 458218590Sjkimstatic int 459218590Sjkimg_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v) 460218590Sjkim{ 461218590Sjkim struct g_geom *gp; 462218590Sjkim const char *gname; 463218590Sjkim 464218590Sjkim gname = gctl_get_asciiparam(req, name); 465218590Sjkim if (gname == NULL) 466218590Sjkim return (ENOATTR); 467228110Sjkim if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 468228110Sjkim gname += sizeof(_PATH_DEV) - 1; 469218590Sjkim gp = g_part_find_geom(gname); 470218590Sjkim if (gp == NULL) { 471218590Sjkim gctl_error(req, "%d %s '%s'", EINVAL, name, gname); 472218590Sjkim return (EINVAL); 473218590Sjkim } 474218590Sjkim if ((gp->flags & G_GEOM_WITHER) != 0) { 475218590Sjkim gctl_error(req, "%d %s", ENXIO, gname); 476218590Sjkim return (ENXIO); 477218590Sjkim } 478228110Sjkim *v = gp; 479218590Sjkim return (0); 480218590Sjkim} 481218590Sjkim 482218590Sjkimstatic int 483218590Sjkimg_part_parm_provider(struct gctl_req *req, const char *name, 484218590Sjkim struct g_provider **v) 485218590Sjkim{ 486228110Sjkim struct g_provider *pp; 487218590Sjkim const char *pname; 488218590Sjkim 489228110Sjkim pname = gctl_get_asciiparam(req, name); 490228110Sjkim if (pname == NULL) 491228110Sjkim return (ENOATTR); 492228110Sjkim if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 493228110Sjkim pname += sizeof(_PATH_DEV) - 1; 494228110Sjkim pp = g_provider_by_name(pname); 495228110Sjkim if (pp == NULL) { 496228110Sjkim gctl_error(req, "%d %s '%s'", EINVAL, name, pname); 497228110Sjkim return (EINVAL); 498228110Sjkim } 499218590Sjkim *v = pp; 500218590Sjkim return (0); 501218590Sjkim} 502218590Sjkim 503218590Sjkimstatic int 504218590Sjkimg_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v) 505218590Sjkim{ 506218590Sjkim const char *p; 507218590Sjkim char *x; 508218590Sjkim quad_t q; 509218590Sjkim 510218590Sjkim p = gctl_get_asciiparam(req, name); 511218590Sjkim if (p == NULL) 512218590Sjkim return (ENOATTR); 513218590Sjkim q = strtoq(p, &x, 0); 514218590Sjkim if (*x != '\0' || q < 0) { 515218590Sjkim gctl_error(req, "%d %s '%s'", EINVAL, name, p); 516218590Sjkim return (EINVAL); 517218590Sjkim } 518218590Sjkim *v = q; 519218590Sjkim return (0); 520218590Sjkim} 521218590Sjkim 522218590Sjkimstatic int 523218590Sjkimg_part_parm_scheme(struct gctl_req *req, const char *name, 524118611Snjl struct g_part_scheme **v) 525118611Snjl{ 526118611Snjl struct g_part_scheme *s; 527118611Snjl const char *p; 528118611Snjl 529239340Sjkim p = gctl_get_asciiparam(req, name); 530118611Snjl if (p == NULL) 531118611Snjl return (ENOATTR); 532118611Snjl TAILQ_FOREACH(s, &g_part_schemes, scheme_list) { 533118611Snjl if (s == &g_part_null_scheme) 534118611Snjl continue; 535118611Snjl if (!strcasecmp(s->name, p)) 536118611Snjl break; 537118611Snjl } 538118611Snjl if (s == NULL) { 539202771Sjkim gctl_error(req, "%d %s '%s'", EINVAL, name, p); 540118611Snjl return (EINVAL); 541118611Snjl } 542118611Snjl *v = s; 543118611Snjl return (0); 544118611Snjl} 545118611Snjl 546118611Snjlstatic int 547209746Sjkimg_part_parm_str(struct gctl_req *req, const char *name, const char **v) 548167802Sjkim{ 549123315Snjl const char *p; 550118611Snjl 551118611Snjl p = gctl_get_asciiparam(req, name); 552118611Snjl if (p == NULL) 553118611Snjl return (ENOATTR); 554118611Snjl /* An empty label is always valid. */ 555118611Snjl if (strcmp(name, "label") != 0 && p[0] == '\0') { 556118611Snjl gctl_error(req, "%d %s '%s'", EINVAL, name, p); 557118611Snjl return (EINVAL); 558118611Snjl } 559118611Snjl *v = p; 560118611Snjl return (0); 561118611Snjl} 562118611Snjl 563118611Snjlstatic int 564118611Snjlg_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v) 565118611Snjl{ 566118611Snjl const intmax_t *p; 567118611Snjl int size; 568118611Snjl 569118611Snjl p = gctl_get_param(req, name, &size); 570118611Snjl if (p == NULL) 571118611Snjl return (ENOATTR); 572118611Snjl if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) { 573118611Snjl gctl_error(req, "%d %s '%jd'", EINVAL, name, *p); 574118611Snjl return (EINVAL); 575118611Snjl } 576118611Snjl *v = (u_int)*p; 577118611Snjl return (0); 578118611Snjl} 579118611Snjl 580118611Snjlstatic int 581118611Snjlg_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v) 582118611Snjl{ 583118611Snjl const uint32_t *p; 584118611Snjl int size; 585118611Snjl 586118611Snjl p = gctl_get_param(req, name, &size); 587118611Snjl if (p == NULL) 588118611Snjl return (ENOATTR); 589118611Snjl if (size != sizeof(*p) || *p > INT_MAX) { 590118611Snjl gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p); 591118611Snjl return (EINVAL); 592118611Snjl } 593118611Snjl *v = (u_int)*p; 594239340Sjkim return (0); 595118611Snjl} 596239340Sjkim 597118611Snjlstatic int 598118611Snjlg_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v, 599118611Snjl unsigned int *s) 600118611Snjl{ 601118611Snjl const void *p; 602118611Snjl int size; 603118611Snjl 604118611Snjl p = gctl_get_param(req, name, &size); 605118611Snjl if (p == NULL) 606118611Snjl return (ENOATTR); 607118611Snjl *v = p; 608118611Snjl *s = size; 609118611Snjl return (0); 610118611Snjl} 611118611Snjl 612118611Snjlstatic int 613118611Snjlg_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth) 614118611Snjl{ 615118611Snjl struct g_part_scheme *iter, *scheme; 616118611Snjl struct g_part_table *table; 617118611Snjl int pri, probe; 618118611Snjl 619118611Snjl table = gp->softc; 620118611Snjl scheme = (table != NULL) ? table->gpt_scheme : NULL; 621118611Snjl pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN; 622118611Snjl if (pri == 0) 623118611Snjl goto done; 624209746Sjkim if (pri > 0) { /* error */ 625167802Sjkim scheme = NULL; 626118611Snjl pri = INT_MIN; 627118611Snjl } 628118611Snjl 629118611Snjl TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { 630118611Snjl if (iter == &g_part_null_scheme) 631118611Snjl continue; 632118611Snjl table = (void *)kobj_create((kobj_class_t)iter, M_GEOM, 633118611Snjl M_WAITOK); 634118611Snjl table->gpt_gp = gp; 635118611Snjl table->gpt_scheme = iter; 636118611Snjl table->gpt_depth = depth; 637118611Snjl probe = G_PART_PROBE(table, cp); 638118611Snjl if (probe <= 0 && probe > pri) { 639118611Snjl pri = probe; 640118611Snjl scheme = iter; 641118611Snjl if (gp->softc != NULL) 642118611Snjl kobj_delete((kobj_t)gp->softc, M_GEOM); 643118611Snjl gp->softc = table; 644118611Snjl if (pri == 0) 645118611Snjl goto done; 646118611Snjl } else 647118611Snjl kobj_delete((kobj_t)table, M_GEOM); 648118611Snjl } 649118611Snjl 650118611Snjldone: 651118611Snjl return ((scheme == NULL) ? ENXIO : 0); 652118611Snjl} 653118611Snjl 654118611Snjl/* 655118611Snjl * Control request functions. 656118611Snjl */ 657118611Snjl 658118611Snjlstatic int 659118611Snjlg_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) 660118611Snjl{ 661118611Snjl struct g_geom *gp; 662239340Sjkim struct g_provider *pp; 663118611Snjl struct g_part_entry *delent, *last, *entry; 664118611Snjl struct g_part_table *table; 665118611Snjl struct sbuf *sb; 666118611Snjl quad_t end; 667118611Snjl unsigned int index; 668118611Snjl int error; 669118611Snjl 670118611Snjl gp = gpp->gpp_geom; 671118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 672118611Snjl g_topology_assert(); 673118611Snjl 674118611Snjl pp = LIST_FIRST(&gp->consumer)->provider; 675118611Snjl table = gp->softc; 676118611Snjl end = gpp->gpp_start + gpp->gpp_size - 1; 677118611Snjl 678118611Snjl if (gpp->gpp_start < table->gpt_first || 679118611Snjl gpp->gpp_start > table->gpt_last) { 680118611Snjl gctl_error(req, "%d start '%jd'", EINVAL, 681118611Snjl (intmax_t)gpp->gpp_start); 682118611Snjl return (EINVAL); 683118611Snjl } 684118611Snjl if (end < gpp->gpp_start || end > table->gpt_last) { 685118611Snjl gctl_error(req, "%d size '%jd'", EINVAL, 686118611Snjl (intmax_t)gpp->gpp_size); 687118611Snjl return (EINVAL); 688118611Snjl } 689118611Snjl if (gpp->gpp_index > table->gpt_entries) { 690118611Snjl gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index); 691118611Snjl return (EINVAL); 692118611Snjl } 693118611Snjl 694118611Snjl delent = last = NULL; 695118611Snjl index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1; 696118611Snjl LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 697118611Snjl if (entry->gpe_deleted) { 698118611Snjl if (entry->gpe_index == index) 699118611Snjl delent = entry; 700118611Snjl continue; 701118611Snjl } 702118611Snjl if (entry->gpe_index == index) 703118611Snjl index = entry->gpe_index + 1; 704118611Snjl if (entry->gpe_index < index) 705118611Snjl last = entry; 706118611Snjl if (entry->gpe_internal) 707118611Snjl continue; 708118611Snjl if (gpp->gpp_start >= entry->gpe_start && 709118611Snjl gpp->gpp_start <= entry->gpe_end) { 710118611Snjl gctl_error(req, "%d start '%jd'", ENOSPC, 711118611Snjl (intmax_t)gpp->gpp_start); 712118611Snjl return (ENOSPC); 713118611Snjl } 714118611Snjl if (end >= entry->gpe_start && end <= entry->gpe_end) { 715118611Snjl gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end); 716239340Sjkim return (ENOSPC); 717118611Snjl } 718118611Snjl if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) { 719118611Snjl gctl_error(req, "%d size '%jd'", ENOSPC, 720118611Snjl (intmax_t)gpp->gpp_size); 721118611Snjl return (ENOSPC); 722118611Snjl } 723118611Snjl } 724118611Snjl if (gpp->gpp_index > 0 && index != gpp->gpp_index) { 725118611Snjl gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index); 726118611Snjl return (EEXIST); 727118611Snjl } 728118611Snjl if (index > table->gpt_entries) { 729118611Snjl gctl_error(req, "%d index '%d'", ENOSPC, index); 730118611Snjl return (ENOSPC); 731118611Snjl } 732118611Snjl 733118611Snjl entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz, 734118611Snjl M_WAITOK | M_ZERO) : delent; 735118611Snjl entry->gpe_index = index; 736118611Snjl entry->gpe_start = gpp->gpp_start; 737118611Snjl entry->gpe_end = end; 738118611Snjl error = G_PART_ADD(table, entry, gpp); 739118611Snjl if (error) { 740118611Snjl gctl_error(req, "%d", error); 741118611Snjl if (delent == NULL) 742118611Snjl g_free(entry); 743209746Sjkim return (error); 744118611Snjl } 745118611Snjl if (delent == NULL) { 746118611Snjl if (last == NULL) 747118611Snjl LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 748118611Snjl else 749118611Snjl LIST_INSERT_AFTER(last, entry, gpe_entry); 750118611Snjl entry->gpe_created = 1; 751118611Snjl } else { 752118611Snjl entry->gpe_deleted = 0; 753118611Snjl entry->gpe_modified = 1; 754118611Snjl } 755118611Snjl g_part_new_provider(gp, table, entry); 756118611Snjl 757118611Snjl /* Provide feedback if so requested. */ 758118611Snjl if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 759118611Snjl sb = sbuf_new_auto(); 760118611Snjl G_PART_FULLNAME(table, entry, sb, gp->name); 761118611Snjl if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0) 762118611Snjl sbuf_printf(sb, " added, but partition is not " 763118611Snjl "aligned on %u bytes\n", pp->stripesize); 764118611Snjl else 765118611Snjl sbuf_cat(sb, " added\n"); 766118611Snjl sbuf_finish(sb); 767118611Snjl gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 768118611Snjl sbuf_delete(sb); 769118611Snjl } 770118611Snjl return (0); 771118611Snjl} 772118611Snjl 773118611Snjlstatic int 774118611Snjlg_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp) 775118611Snjl{ 776118611Snjl struct g_geom *gp; 777151937Sjkim struct g_part_table *table; 778151937Sjkim struct sbuf *sb; 779118611Snjl int error, sz; 780118611Snjl 781118611Snjl gp = gpp->gpp_geom; 782118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 783118611Snjl g_topology_assert(); 784118611Snjl 785118611Snjl table = gp->softc; 786239340Sjkim sz = table->gpt_scheme->gps_bootcodesz; 787118611Snjl if (sz == 0) { 788118611Snjl error = ENODEV; 789118611Snjl goto fail; 790118611Snjl } 791118611Snjl if (gpp->gpp_codesize > sz) { 792118611Snjl error = EFBIG; 793118611Snjl goto fail; 794118611Snjl } 795118611Snjl 796118611Snjl error = G_PART_BOOTCODE(table, gpp); 797118611Snjl if (error) 798118611Snjl goto fail; 799118611Snjl 800118611Snjl /* Provide feedback if so requested. */ 801118611Snjl if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 802118611Snjl sb = sbuf_new_auto(); 803118611Snjl sbuf_printf(sb, "bootcode written to %s\n", gp->name); 804118611Snjl sbuf_finish(sb); 805118611Snjl gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 806118611Snjl sbuf_delete(sb); 807118611Snjl } 808118611Snjl return (0); 809118611Snjl 810118611Snjl fail: 811118611Snjl gctl_error(req, "%d", error); 812118611Snjl return (error); 813118611Snjl} 814118611Snjl 815118611Snjlstatic int 816118611Snjlg_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp) 817118611Snjl{ 818118611Snjl struct g_consumer *cp; 819118611Snjl struct g_geom *gp; 820118611Snjl struct g_provider *pp; 821118611Snjl struct g_part_entry *entry, *tmp; 822118611Snjl struct g_part_table *table; 823118611Snjl char *buf; 824118611Snjl int error, i; 825118611Snjl 826118611Snjl gp = gpp->gpp_geom; 827118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 828118611Snjl g_topology_assert(); 829118611Snjl 830118611Snjl table = gp->softc; 831118611Snjl if (!table->gpt_opened) { 832118611Snjl gctl_error(req, "%d", EPERM); 833118611Snjl return (EPERM); 834118611Snjl } 835118611Snjl 836118611Snjl g_topology_unlock(); 837118611Snjl 838118611Snjl cp = LIST_FIRST(&gp->consumer); 839118611Snjl if ((table->gpt_smhead | table->gpt_smtail) != 0) { 840118611Snjl pp = cp->provider; 841239340Sjkim buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 842118611Snjl while (table->gpt_smhead != 0) { 843118611Snjl i = ffs(table->gpt_smhead) - 1; 844118611Snjl error = g_write_data(cp, i * pp->sectorsize, buf, 845118611Snjl pp->sectorsize); 846118611Snjl if (error) { 847118611Snjl g_free(buf); 848118611Snjl goto fail; 849118611Snjl } 850118611Snjl table->gpt_smhead &= ~(1 << i); 851118611Snjl } 852118611Snjl while (table->gpt_smtail != 0) { 853118611Snjl i = ffs(table->gpt_smtail) - 1; 854118611Snjl error = g_write_data(cp, pp->mediasize - (i + 1) * 855118611Snjl pp->sectorsize, buf, pp->sectorsize); 856118611Snjl if (error) { 857118611Snjl g_free(buf); 858118611Snjl goto fail; 859118611Snjl } 860118611Snjl table->gpt_smtail &= ~(1 << i); 861118611Snjl } 862118611Snjl g_free(buf); 863118611Snjl } 864118611Snjl 865118611Snjl if (table->gpt_scheme == &g_part_null_scheme) { 866118611Snjl g_topology_lock(); 867118611Snjl g_access(cp, -1, -1, -1); 868118611Snjl g_part_wither(gp, ENXIO); 869118611Snjl return (0); 870118611Snjl } 871118611Snjl 872118611Snjl error = G_PART_WRITE(table, cp); 873118611Snjl if (error) 874118611Snjl goto fail; 875118611Snjl 876118611Snjl LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 877118611Snjl if (!entry->gpe_deleted) { 878118611Snjl entry->gpe_created = 0; 879118611Snjl entry->gpe_modified = 0; 880151937Sjkim continue; 881151937Sjkim } 882151937Sjkim LIST_REMOVE(entry, gpe_entry); 883151937Sjkim g_free(entry); 884118611Snjl } 885118611Snjl table->gpt_created = 0; 886118611Snjl table->gpt_opened = 0; 887118611Snjl 888118611Snjl g_topology_lock(); 889118611Snjl g_access(cp, -1, -1, -1); 890118611Snjl return (0); 891118611Snjl 892118611Snjlfail: 893118611Snjl g_topology_lock(); 894118611Snjl gctl_error(req, "%d", error); 895118611Snjl return (error); 896118611Snjl} 897118611Snjl 898118611Snjlstatic int 899118611Snjlg_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) 900118611Snjl{ 901118611Snjl struct g_consumer *cp; 902118611Snjl struct g_geom *gp; 903118611Snjl struct g_provider *pp; 904118611Snjl struct g_part_scheme *scheme; 905118611Snjl struct g_part_table *null, *table; 906118611Snjl struct sbuf *sb; 907118611Snjl int attr, error; 908118611Snjl 909118611Snjl pp = gpp->gpp_provider; 910118611Snjl scheme = gpp->gpp_scheme; 911118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 912118611Snjl g_topology_assert(); 913118611Snjl 914118611Snjl /* Check that there isn't already a g_part geom on the provider. */ 915118611Snjl gp = g_part_find_geom(pp->name); 916118611Snjl if (gp != NULL) { 917118611Snjl null = gp->softc; 918118611Snjl if (null->gpt_scheme != &g_part_null_scheme) { 919118611Snjl gctl_error(req, "%d geom '%s'", EEXIST, pp->name); 920118611Snjl return (EEXIST); 921118611Snjl } 922118611Snjl } else 923118611Snjl null = NULL; 924118611Snjl 925118611Snjl if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) && 926118611Snjl (gpp->gpp_entries < scheme->gps_minent || 927118611Snjl gpp->gpp_entries > scheme->gps_maxent)) { 928118611Snjl gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries); 929118611Snjl return (EINVAL); 930118611Snjl } 931209746Sjkim 932118611Snjl if (null == NULL) 933118611Snjl gp = g_new_geomf(&g_part_class, "%s", pp->name); 934118611Snjl gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM, 935118611Snjl M_WAITOK); 936118611Snjl table = gp->softc; 937118611Snjl table->gpt_gp = gp; 938118611Snjl table->gpt_scheme = gpp->gpp_scheme; 939118611Snjl table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ? 940118611Snjl gpp->gpp_entries : scheme->gps_minent; 941118611Snjl LIST_INIT(&table->gpt_entry); 942209746Sjkim if (null == NULL) { 943118611Snjl cp = g_new_consumer(gp); 944118611Snjl cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 945118611Snjl error = g_attach(cp, pp); 946118611Snjl if (error == 0) 947118611Snjl error = g_access(cp, 1, 1, 1); 948118611Snjl if (error != 0) { 949118611Snjl g_part_wither(gp, error); 950118611Snjl gctl_error(req, "%d geom '%s'", error, pp->name); 951118611Snjl return (error); 952118611Snjl } 953118611Snjl table->gpt_opened = 1; 954118611Snjl } else { 955118611Snjl cp = LIST_FIRST(&gp->consumer); 956118611Snjl table->gpt_opened = null->gpt_opened; 957118611Snjl table->gpt_smhead = null->gpt_smhead; 958118611Snjl table->gpt_smtail = null->gpt_smtail; 959118611Snjl } 960118611Snjl 961118611Snjl g_topology_unlock(); 962193529Sjkim 963118611Snjl /* Make sure the provider has media. */ 964118611Snjl if (pp->mediasize == 0 || pp->sectorsize == 0) { 965118611Snjl error = ENODEV; 966118611Snjl goto fail; 967118611Snjl } 968118611Snjl 969118611Snjl /* Make sure we can nest and if so, determine our depth. */ 970118611Snjl error = g_getattr("PART::isleaf", cp, &attr); 971118611Snjl if (!error && attr) { 972118611Snjl error = ENODEV; 973118611Snjl goto fail; 974118611Snjl } 975118611Snjl error = g_getattr("PART::depth", cp, &attr); 976118611Snjl table->gpt_depth = (!error) ? attr + 1 : 0; 977118611Snjl 978118611Snjl /* 979118611Snjl * Synthesize a disk geometry. Some partitioning schemes 980118611Snjl * depend on it and since some file systems need it even 981118611Snjl * when the partitition scheme doesn't, we do it here in 982118611Snjl * scheme-independent code. 983118611Snjl */ 984118611Snjl g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 985118611Snjl 986118611Snjl error = G_PART_CREATE(table, gpp); 987118611Snjl if (error) 988118611Snjl goto fail; 989118611Snjl 990118611Snjl g_topology_lock(); 991118611Snjl 992118611Snjl table->gpt_created = 1; 993118611Snjl if (null != NULL) 994118611Snjl kobj_delete((kobj_t)null, M_GEOM); 995118611Snjl 996118611Snjl /* 997118611Snjl * Support automatic commit by filling in the gpp_geom 998118611Snjl * parameter. 999118611Snjl */ 1000118611Snjl gpp->gpp_parms |= G_PART_PARM_GEOM; 1001118611Snjl gpp->gpp_geom = gp; 1002118611Snjl 1003118611Snjl /* Provide feedback if so requested. */ 1004118611Snjl if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1005118611Snjl sb = sbuf_new_auto(); 1006118611Snjl sbuf_printf(sb, "%s created\n", gp->name); 1007118611Snjl sbuf_finish(sb); 1008118611Snjl gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1009118611Snjl sbuf_delete(sb); 1010118611Snjl } 1011118611Snjl return (0); 1012118611Snjl 1013118611Snjlfail: 1014118611Snjl g_topology_lock(); 1015118611Snjl if (null == NULL) { 1016118611Snjl g_access(cp, -1, -1, -1); 1017118611Snjl g_part_wither(gp, error); 1018118611Snjl } else { 1019118611Snjl kobj_delete((kobj_t)gp->softc, M_GEOM); 1020118611Snjl gp->softc = null; 1021118611Snjl } 1022118611Snjl gctl_error(req, "%d provider", error); 1023118611Snjl return (error); 1024118611Snjl} 1025118611Snjl 1026118611Snjlstatic int 1027118611Snjlg_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp) 1028118611Snjl{ 1029118611Snjl struct g_geom *gp; 1030118611Snjl struct g_provider *pp; 1031118611Snjl struct g_part_entry *entry; 1032118611Snjl struct g_part_table *table; 1033118611Snjl struct sbuf *sb; 1034118611Snjl 1035118611Snjl gp = gpp->gpp_geom; 1036118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1037118611Snjl g_topology_assert(); 1038118611Snjl 1039118611Snjl table = gp->softc; 1040118611Snjl 1041118611Snjl LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1042118611Snjl if (entry->gpe_deleted || entry->gpe_internal) 1043118611Snjl continue; 1044118611Snjl if (entry->gpe_index == gpp->gpp_index) 1045118611Snjl break; 1046118611Snjl } 1047118611Snjl if (entry == NULL) { 1048118611Snjl gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1049118611Snjl return (ENOENT); 1050118611Snjl } 1051118611Snjl 1052118611Snjl pp = entry->gpe_pp; 1053118611Snjl if (pp != NULL) { 1054118611Snjl if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) { 1055118611Snjl gctl_error(req, "%d", EBUSY); 1056118611Snjl return (EBUSY); 1057118611Snjl } 1058118611Snjl 1059118611Snjl pp->private = NULL; 1060151937Sjkim entry->gpe_pp = NULL; 1061151937Sjkim } 1062118611Snjl 1063118611Snjl if (pp != NULL) 1064118611Snjl g_wither_provider(pp, ENXIO); 1065118611Snjl 1066118611Snjl /* Provide feedback if so requested. */ 1067118611Snjl if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1068118611Snjl sb = sbuf_new_auto(); 1069118611Snjl G_PART_FULLNAME(table, entry, sb, gp->name); 1070118611Snjl sbuf_cat(sb, " deleted\n"); 1071118611Snjl sbuf_finish(sb); 1072118611Snjl gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1073118611Snjl sbuf_delete(sb); 1074118611Snjl } 1075118611Snjl 1076118611Snjl if (entry->gpe_created) { 1077118611Snjl LIST_REMOVE(entry, gpe_entry); 1078118611Snjl g_free(entry); 1079118611Snjl } else { 1080118611Snjl entry->gpe_modified = 0; 1081118611Snjl entry->gpe_deleted = 1; 1082118611Snjl } 1083118611Snjl return (0); 1084118611Snjl} 1085118611Snjl 1086118611Snjlstatic int 1087118611Snjlg_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp) 1088118611Snjl{ 1089118611Snjl struct g_consumer *cp; 1090118611Snjl struct g_geom *gp; 1091118611Snjl struct g_provider *pp; 1092118611Snjl struct g_part_entry *entry, *tmp; 1093118611Snjl struct g_part_table *null, *table; 1094118611Snjl struct sbuf *sb; 1095118611Snjl int error; 1096118611Snjl 1097118611Snjl gp = gpp->gpp_geom; 1098118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1099118611Snjl g_topology_assert(); 1100118611Snjl 1101118611Snjl table = gp->softc; 1102118611Snjl /* Check for busy providers. */ 1103118611Snjl LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1104118611Snjl if (entry->gpe_deleted || entry->gpe_internal) 1105118611Snjl continue; 1106118611Snjl if (gpp->gpp_force) { 1107118611Snjl pp = entry->gpe_pp; 1108118611Snjl if (pp == NULL) 1109118611Snjl continue; 1110118611Snjl if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 1111118611Snjl continue; 1112118611Snjl } 1113118611Snjl gctl_error(req, "%d", EBUSY); 1114118611Snjl return (EBUSY); 1115118611Snjl } 1116118611Snjl 1117118611Snjl if (gpp->gpp_force) { 1118118611Snjl /* Destroy all providers. */ 1119118611Snjl LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1120151937Sjkim pp = entry->gpe_pp; 1121151937Sjkim if (pp != NULL) { 1122118611Snjl pp->private = NULL; 1123118611Snjl g_wither_provider(pp, ENXIO); 1124118611Snjl } 1125118611Snjl LIST_REMOVE(entry, gpe_entry); 1126118611Snjl g_free(entry); 1127118611Snjl } 1128118611Snjl } 1129118611Snjl 1130118611Snjl error = G_PART_DESTROY(table, gpp); 1131118611Snjl if (error) { 1132118611Snjl gctl_error(req, "%d", error); 1133118611Snjl return (error); 1134118611Snjl } 1135118611Snjl 1136118611Snjl gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM, 1137118611Snjl M_WAITOK); 1138118611Snjl null = gp->softc; 1139118611Snjl null->gpt_gp = gp; 1140118611Snjl null->gpt_scheme = &g_part_null_scheme; 1141118611Snjl LIST_INIT(&null->gpt_entry); 1142118611Snjl 1143118611Snjl cp = LIST_FIRST(&gp->consumer); 1144118611Snjl pp = cp->provider; 1145118611Snjl null->gpt_last = pp->mediasize / pp->sectorsize - 1; 1146118611Snjl 1147118611Snjl null->gpt_depth = table->gpt_depth; 1148118611Snjl null->gpt_opened = table->gpt_opened; 1149118611Snjl null->gpt_smhead = table->gpt_smhead; 1150118611Snjl null->gpt_smtail = table->gpt_smtail; 1151118611Snjl 1152118611Snjl while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1153118611Snjl LIST_REMOVE(entry, gpe_entry); 1154118611Snjl g_free(entry); 1155118611Snjl } 1156118611Snjl kobj_delete((kobj_t)table, M_GEOM); 1157118611Snjl 1158118611Snjl /* Provide feedback if so requested. */ 1159118611Snjl if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1160118611Snjl sb = sbuf_new_auto(); 1161118611Snjl sbuf_printf(sb, "%s destroyed\n", gp->name); 1162118611Snjl sbuf_finish(sb); 1163118611Snjl gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1164118611Snjl sbuf_delete(sb); 1165118611Snjl } 1166118611Snjl return (0); 1167118611Snjl} 1168118611Snjl 1169118611Snjlstatic int 1170118611Snjlg_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp) 1171118611Snjl{ 1172118611Snjl struct g_geom *gp; 1173118611Snjl struct g_part_entry *entry; 1174118611Snjl struct g_part_table *table; 1175118611Snjl struct sbuf *sb; 1176118611Snjl int error; 1177118611Snjl 1178118611Snjl gp = gpp->gpp_geom; 1179118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1180151937Sjkim g_topology_assert(); 1181151937Sjkim 1182118611Snjl table = gp->softc; 1183118611Snjl 1184118611Snjl LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1185118611Snjl if (entry->gpe_deleted || entry->gpe_internal) 1186118611Snjl continue; 1187118611Snjl if (entry->gpe_index == gpp->gpp_index) 1188118611Snjl break; 1189118611Snjl } 1190118611Snjl if (entry == NULL) { 1191118611Snjl gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1192118611Snjl return (ENOENT); 1193118611Snjl } 1194118611Snjl 1195118611Snjl error = G_PART_MODIFY(table, entry, gpp); 1196118611Snjl if (error) { 1197118611Snjl gctl_error(req, "%d", error); 1198118611Snjl return (error); 1199118611Snjl } 1200118611Snjl 1201118611Snjl if (!entry->gpe_created) 1202118611Snjl entry->gpe_modified = 1; 1203118611Snjl 1204118611Snjl /* Provide feedback if so requested. */ 1205118611Snjl if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1206118611Snjl sb = sbuf_new_auto(); 1207118611Snjl G_PART_FULLNAME(table, entry, sb, gp->name); 1208118611Snjl sbuf_cat(sb, " modified\n"); 1209118611Snjl sbuf_finish(sb); 1210118611Snjl gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1211118611Snjl sbuf_delete(sb); 1212118611Snjl } 1213118611Snjl return (0); 1214118611Snjl} 1215118611Snjl 1216118611Snjlstatic int 1217118611Snjlg_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) 1218118611Snjl{ 1219118611Snjl gctl_error(req, "%d verb 'move'", ENOSYS); 1220118611Snjl return (ENOSYS); 1221118611Snjl} 1222118611Snjl 1223118611Snjlstatic int 1224118611Snjlg_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) 1225118611Snjl{ 1226118611Snjl struct g_part_table *table; 1227118611Snjl struct g_geom *gp; 1228118611Snjl struct sbuf *sb; 1229118611Snjl int error, recovered; 1230118611Snjl 1231118611Snjl gp = gpp->gpp_geom; 1232118611Snjl G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1233118611Snjl g_topology_assert(); 1234118611Snjl table = gp->softc; 1235118611Snjl error = recovered = 0; 1236118611Snjl 1237118611Snjl if (table->gpt_corrupt) { 1238118611Snjl error = G_PART_RECOVER(table); 1239118611Snjl if (error == 0) 1240118611Snjl error = g_part_check_integrity(table, 1241 LIST_FIRST(&gp->consumer)); 1242 if (error) { 1243 gctl_error(req, "%d recovering '%s' failed", 1244 error, gp->name); 1245 return (error); 1246 } 1247 recovered = 1; 1248 } 1249 /* Provide feedback if so requested. */ 1250 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1251 sb = sbuf_new_auto(); 1252 if (recovered) 1253 sbuf_printf(sb, "%s recovered\n", gp->name); 1254 else 1255 sbuf_printf(sb, "%s recovering is not needed\n", 1256 gp->name); 1257 sbuf_finish(sb); 1258 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1259 sbuf_delete(sb); 1260 } 1261 return (0); 1262} 1263 1264static int 1265g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) 1266{ 1267 struct g_geom *gp; 1268 struct g_provider *pp; 1269 struct g_part_entry *pe, *entry; 1270 struct g_part_table *table; 1271 struct sbuf *sb; 1272 quad_t end; 1273 int error; 1274 off_t mediasize; 1275 1276 gp = gpp->gpp_geom; 1277 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1278 g_topology_assert(); 1279 table = gp->softc; 1280 1281 /* check gpp_index */ 1282 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1283 if (entry->gpe_deleted || entry->gpe_internal) 1284 continue; 1285 if (entry->gpe_index == gpp->gpp_index) 1286 break; 1287 } 1288 if (entry == NULL) { 1289 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1290 return (ENOENT); 1291 } 1292 1293 /* check gpp_size */ 1294 end = entry->gpe_start + gpp->gpp_size - 1; 1295 if (gpp->gpp_size < 1 || end > table->gpt_last) { 1296 gctl_error(req, "%d size '%jd'", EINVAL, 1297 (intmax_t)gpp->gpp_size); 1298 return (EINVAL); 1299 } 1300 1301 LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) { 1302 if (pe->gpe_deleted || pe->gpe_internal || pe == entry) 1303 continue; 1304 if (end >= pe->gpe_start && end <= pe->gpe_end) { 1305 gctl_error(req, "%d end '%jd'", ENOSPC, 1306 (intmax_t)end); 1307 return (ENOSPC); 1308 } 1309 if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) { 1310 gctl_error(req, "%d size '%jd'", ENOSPC, 1311 (intmax_t)gpp->gpp_size); 1312 return (ENOSPC); 1313 } 1314 } 1315 1316 pp = entry->gpe_pp; 1317 if ((g_debugflags & 16) == 0 && 1318 (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) { 1319 if (entry->gpe_end - entry->gpe_start + 1 > gpp->gpp_size) { 1320 /* Deny shrinking of an opened partition. */ 1321 gctl_error(req, "%d", EBUSY); 1322 return (EBUSY); 1323 } 1324 } 1325 1326 error = G_PART_RESIZE(table, entry, gpp); 1327 if (error) { 1328 gctl_error(req, "%d%s", error, error != EBUSY ? "": 1329 " resizing will lead to unexpected shrinking" 1330 " due to alignment"); 1331 return (error); 1332 } 1333 1334 if (!entry->gpe_created) 1335 entry->gpe_modified = 1; 1336 1337 /* update mediasize of changed provider */ 1338 mediasize = (entry->gpe_end - entry->gpe_start + 1) * 1339 pp->sectorsize; 1340 g_resize_provider(pp, mediasize); 1341 1342 /* Provide feedback if so requested. */ 1343 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1344 sb = sbuf_new_auto(); 1345 G_PART_FULLNAME(table, entry, sb, gp->name); 1346 sbuf_cat(sb, " resized\n"); 1347 sbuf_finish(sb); 1348 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1349 sbuf_delete(sb); 1350 } 1351 return (0); 1352} 1353 1354static int 1355g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, 1356 unsigned int set) 1357{ 1358 struct g_geom *gp; 1359 struct g_part_entry *entry; 1360 struct g_part_table *table; 1361 struct sbuf *sb; 1362 int error; 1363 1364 gp = gpp->gpp_geom; 1365 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1366 g_topology_assert(); 1367 1368 table = gp->softc; 1369 1370 if (gpp->gpp_parms & G_PART_PARM_INDEX) { 1371 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1372 if (entry->gpe_deleted || entry->gpe_internal) 1373 continue; 1374 if (entry->gpe_index == gpp->gpp_index) 1375 break; 1376 } 1377 if (entry == NULL) { 1378 gctl_error(req, "%d index '%d'", ENOENT, 1379 gpp->gpp_index); 1380 return (ENOENT); 1381 } 1382 } else 1383 entry = NULL; 1384 1385 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set); 1386 if (error) { 1387 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib); 1388 return (error); 1389 } 1390 1391 /* Provide feedback if so requested. */ 1392 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1393 sb = sbuf_new_auto(); 1394 sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib, 1395 (set) ? "" : "un"); 1396 if (entry) 1397 G_PART_FULLNAME(table, entry, sb, gp->name); 1398 else 1399 sbuf_cat(sb, gp->name); 1400 sbuf_cat(sb, "\n"); 1401 sbuf_finish(sb); 1402 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1403 sbuf_delete(sb); 1404 } 1405 return (0); 1406} 1407 1408static int 1409g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) 1410{ 1411 struct g_consumer *cp; 1412 struct g_provider *pp; 1413 struct g_geom *gp; 1414 struct g_part_entry *entry, *tmp; 1415 struct g_part_table *table; 1416 int error, reprobe; 1417 1418 gp = gpp->gpp_geom; 1419 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1420 g_topology_assert(); 1421 1422 table = gp->softc; 1423 if (!table->gpt_opened) { 1424 gctl_error(req, "%d", EPERM); 1425 return (EPERM); 1426 } 1427 1428 cp = LIST_FIRST(&gp->consumer); 1429 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1430 entry->gpe_modified = 0; 1431 if (entry->gpe_created) { 1432 pp = entry->gpe_pp; 1433 if (pp != NULL) { 1434 pp->private = NULL; 1435 entry->gpe_pp = NULL; 1436 g_wither_provider(pp, ENXIO); 1437 } 1438 entry->gpe_deleted = 1; 1439 } 1440 if (entry->gpe_deleted) { 1441 LIST_REMOVE(entry, gpe_entry); 1442 g_free(entry); 1443 } 1444 } 1445 1446 g_topology_unlock(); 1447 1448 reprobe = (table->gpt_scheme == &g_part_null_scheme || 1449 table->gpt_created) ? 1 : 0; 1450 1451 if (reprobe) { 1452 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1453 if (entry->gpe_internal) 1454 continue; 1455 error = EBUSY; 1456 goto fail; 1457 } 1458 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1459 LIST_REMOVE(entry, gpe_entry); 1460 g_free(entry); 1461 } 1462 error = g_part_probe(gp, cp, table->gpt_depth); 1463 if (error) { 1464 g_topology_lock(); 1465 g_access(cp, -1, -1, -1); 1466 g_part_wither(gp, error); 1467 return (0); 1468 } 1469 table = gp->softc; 1470 1471 /* 1472 * Synthesize a disk geometry. Some partitioning schemes 1473 * depend on it and since some file systems need it even 1474 * when the partitition scheme doesn't, we do it here in 1475 * scheme-independent code. 1476 */ 1477 pp = cp->provider; 1478 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1479 } 1480 1481 error = G_PART_READ(table, cp); 1482 if (error) 1483 goto fail; 1484 error = g_part_check_integrity(table, cp); 1485 if (error) 1486 goto fail; 1487 1488 g_topology_lock(); 1489 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1490 if (!entry->gpe_internal) 1491 g_part_new_provider(gp, table, entry); 1492 } 1493 1494 table->gpt_opened = 0; 1495 g_access(cp, -1, -1, -1); 1496 return (0); 1497 1498fail: 1499 g_topology_lock(); 1500 gctl_error(req, "%d", error); 1501 return (error); 1502} 1503 1504static void 1505g_part_wither(struct g_geom *gp, int error) 1506{ 1507 struct g_part_entry *entry; 1508 struct g_part_table *table; 1509 1510 table = gp->softc; 1511 if (table != NULL) { 1512 G_PART_DESTROY(table, NULL); 1513 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1514 LIST_REMOVE(entry, gpe_entry); 1515 g_free(entry); 1516 } 1517 if (gp->softc != NULL) { 1518 kobj_delete((kobj_t)gp->softc, M_GEOM); 1519 gp->softc = NULL; 1520 } 1521 } 1522 g_wither_geom(gp, error); 1523} 1524 1525/* 1526 * Class methods. 1527 */ 1528 1529static void 1530g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 1531{ 1532 struct g_part_parms gpp; 1533 struct g_part_table *table; 1534 struct gctl_req_arg *ap; 1535 enum g_part_ctl ctlreq; 1536 unsigned int i, mparms, oparms, parm; 1537 int auto_commit, close_on_error; 1538 int error, modifies; 1539 1540 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1541 g_topology_assert(); 1542 1543 ctlreq = G_PART_CTL_NONE; 1544 modifies = 1; 1545 mparms = 0; 1546 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1547 switch (*verb) { 1548 case 'a': 1549 if (!strcmp(verb, "add")) { 1550 ctlreq = G_PART_CTL_ADD; 1551 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1552 G_PART_PARM_START | G_PART_PARM_TYPE; 1553 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1554 } 1555 break; 1556 case 'b': 1557 if (!strcmp(verb, "bootcode")) { 1558 ctlreq = G_PART_CTL_BOOTCODE; 1559 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; 1560 } 1561 break; 1562 case 'c': 1563 if (!strcmp(verb, "commit")) { 1564 ctlreq = G_PART_CTL_COMMIT; 1565 mparms |= G_PART_PARM_GEOM; 1566 modifies = 0; 1567 } else if (!strcmp(verb, "create")) { 1568 ctlreq = G_PART_CTL_CREATE; 1569 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1570 oparms |= G_PART_PARM_ENTRIES; 1571 } 1572 break; 1573 case 'd': 1574 if (!strcmp(verb, "delete")) { 1575 ctlreq = G_PART_CTL_DELETE; 1576 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1577 } else if (!strcmp(verb, "destroy")) { 1578 ctlreq = G_PART_CTL_DESTROY; 1579 mparms |= G_PART_PARM_GEOM; 1580 oparms |= G_PART_PARM_FORCE; 1581 } 1582 break; 1583 case 'm': 1584 if (!strcmp(verb, "modify")) { 1585 ctlreq = G_PART_CTL_MODIFY; 1586 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1587 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1588 } else if (!strcmp(verb, "move")) { 1589 ctlreq = G_PART_CTL_MOVE; 1590 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1591 } 1592 break; 1593 case 'r': 1594 if (!strcmp(verb, "recover")) { 1595 ctlreq = G_PART_CTL_RECOVER; 1596 mparms |= G_PART_PARM_GEOM; 1597 } else if (!strcmp(verb, "resize")) { 1598 ctlreq = G_PART_CTL_RESIZE; 1599 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX | 1600 G_PART_PARM_SIZE; 1601 } 1602 break; 1603 case 's': 1604 if (!strcmp(verb, "set")) { 1605 ctlreq = G_PART_CTL_SET; 1606 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM; 1607 oparms |= G_PART_PARM_INDEX; 1608 } 1609 break; 1610 case 'u': 1611 if (!strcmp(verb, "undo")) { 1612 ctlreq = G_PART_CTL_UNDO; 1613 mparms |= G_PART_PARM_GEOM; 1614 modifies = 0; 1615 } else if (!strcmp(verb, "unset")) { 1616 ctlreq = G_PART_CTL_UNSET; 1617 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM; 1618 oparms |= G_PART_PARM_INDEX; 1619 } 1620 break; 1621 } 1622 if (ctlreq == G_PART_CTL_NONE) { 1623 gctl_error(req, "%d verb '%s'", EINVAL, verb); 1624 return; 1625 } 1626 1627 bzero(&gpp, sizeof(gpp)); 1628 for (i = 0; i < req->narg; i++) { 1629 ap = &req->arg[i]; 1630 parm = 0; 1631 switch (ap->name[0]) { 1632 case 'a': 1633 if (!strcmp(ap->name, "arg0")) { 1634 parm = mparms & 1635 (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER); 1636 } 1637 if (!strcmp(ap->name, "attrib")) 1638 parm = G_PART_PARM_ATTRIB; 1639 break; 1640 case 'b': 1641 if (!strcmp(ap->name, "bootcode")) 1642 parm = G_PART_PARM_BOOTCODE; 1643 break; 1644 case 'c': 1645 if (!strcmp(ap->name, "class")) 1646 continue; 1647 break; 1648 case 'e': 1649 if (!strcmp(ap->name, "entries")) 1650 parm = G_PART_PARM_ENTRIES; 1651 break; 1652 case 'f': 1653 if (!strcmp(ap->name, "flags")) 1654 parm = G_PART_PARM_FLAGS; 1655 else if (!strcmp(ap->name, "force")) 1656 parm = G_PART_PARM_FORCE; 1657 break; 1658 case 'i': 1659 if (!strcmp(ap->name, "index")) 1660 parm = G_PART_PARM_INDEX; 1661 break; 1662 case 'l': 1663 if (!strcmp(ap->name, "label")) 1664 parm = G_PART_PARM_LABEL; 1665 break; 1666 case 'o': 1667 if (!strcmp(ap->name, "output")) 1668 parm = G_PART_PARM_OUTPUT; 1669 break; 1670 case 's': 1671 if (!strcmp(ap->name, "scheme")) 1672 parm = G_PART_PARM_SCHEME; 1673 else if (!strcmp(ap->name, "size")) 1674 parm = G_PART_PARM_SIZE; 1675 else if (!strcmp(ap->name, "start")) 1676 parm = G_PART_PARM_START; 1677 break; 1678 case 't': 1679 if (!strcmp(ap->name, "type")) 1680 parm = G_PART_PARM_TYPE; 1681 break; 1682 case 'v': 1683 if (!strcmp(ap->name, "verb")) 1684 continue; 1685 else if (!strcmp(ap->name, "version")) 1686 parm = G_PART_PARM_VERSION; 1687 break; 1688 } 1689 if ((parm & (mparms | oparms)) == 0) { 1690 gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1691 return; 1692 } 1693 switch (parm) { 1694 case G_PART_PARM_ATTRIB: 1695 error = g_part_parm_str(req, ap->name, 1696 &gpp.gpp_attrib); 1697 break; 1698 case G_PART_PARM_BOOTCODE: 1699 error = g_part_parm_bootcode(req, ap->name, 1700 &gpp.gpp_codeptr, &gpp.gpp_codesize); 1701 break; 1702 case G_PART_PARM_ENTRIES: 1703 error = g_part_parm_intmax(req, ap->name, 1704 &gpp.gpp_entries); 1705 break; 1706 case G_PART_PARM_FLAGS: 1707 error = g_part_parm_str(req, ap->name, &gpp.gpp_flags); 1708 break; 1709 case G_PART_PARM_FORCE: 1710 error = g_part_parm_uint32(req, ap->name, 1711 &gpp.gpp_force); 1712 break; 1713 case G_PART_PARM_GEOM: 1714 error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom); 1715 break; 1716 case G_PART_PARM_INDEX: 1717 error = g_part_parm_intmax(req, ap->name, 1718 &gpp.gpp_index); 1719 break; 1720 case G_PART_PARM_LABEL: 1721 error = g_part_parm_str(req, ap->name, &gpp.gpp_label); 1722 break; 1723 case G_PART_PARM_OUTPUT: 1724 error = 0; /* Write-only parameter */ 1725 break; 1726 case G_PART_PARM_PROVIDER: 1727 error = g_part_parm_provider(req, ap->name, 1728 &gpp.gpp_provider); 1729 break; 1730 case G_PART_PARM_SCHEME: 1731 error = g_part_parm_scheme(req, ap->name, 1732 &gpp.gpp_scheme); 1733 break; 1734 case G_PART_PARM_SIZE: 1735 error = g_part_parm_quad(req, ap->name, &gpp.gpp_size); 1736 break; 1737 case G_PART_PARM_START: 1738 error = g_part_parm_quad(req, ap->name, 1739 &gpp.gpp_start); 1740 break; 1741 case G_PART_PARM_TYPE: 1742 error = g_part_parm_str(req, ap->name, &gpp.gpp_type); 1743 break; 1744 case G_PART_PARM_VERSION: 1745 error = g_part_parm_uint32(req, ap->name, 1746 &gpp.gpp_version); 1747 break; 1748 default: 1749 error = EDOOFUS; 1750 gctl_error(req, "%d %s", error, ap->name); 1751 break; 1752 } 1753 if (error != 0) { 1754 if (error == ENOATTR) { 1755 gctl_error(req, "%d param '%s'", error, 1756 ap->name); 1757 } 1758 return; 1759 } 1760 gpp.gpp_parms |= parm; 1761 } 1762 if ((gpp.gpp_parms & mparms) != mparms) { 1763 parm = mparms - (gpp.gpp_parms & mparms); 1764 gctl_error(req, "%d param '%x'", ENOATTR, parm); 1765 return; 1766 } 1767 1768 /* Obtain permissions if possible/necessary. */ 1769 close_on_error = 0; 1770 table = NULL; 1771 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1772 table = gpp.gpp_geom->softc; 1773 if (table != NULL && table->gpt_corrupt && 1774 ctlreq != G_PART_CTL_DESTROY && 1775 ctlreq != G_PART_CTL_RECOVER) { 1776 gctl_error(req, "%d table '%s' is corrupt", 1777 EPERM, gpp.gpp_geom->name); 1778 return; 1779 } 1780 if (table != NULL && !table->gpt_opened) { 1781 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1782 1, 1, 1); 1783 if (error) { 1784 gctl_error(req, "%d geom '%s'", error, 1785 gpp.gpp_geom->name); 1786 return; 1787 } 1788 table->gpt_opened = 1; 1789 close_on_error = 1; 1790 } 1791 } 1792 1793 /* Allow the scheme to check or modify the parameters. */ 1794 if (table != NULL) { 1795 error = G_PART_PRECHECK(table, ctlreq, &gpp); 1796 if (error) { 1797 gctl_error(req, "%d pre-check failed", error); 1798 goto out; 1799 } 1800 } else 1801 error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1802 1803 switch (ctlreq) { 1804 case G_PART_CTL_NONE: 1805 panic("%s", __func__); 1806 case G_PART_CTL_ADD: 1807 error = g_part_ctl_add(req, &gpp); 1808 break; 1809 case G_PART_CTL_BOOTCODE: 1810 error = g_part_ctl_bootcode(req, &gpp); 1811 break; 1812 case G_PART_CTL_COMMIT: 1813 error = g_part_ctl_commit(req, &gpp); 1814 break; 1815 case G_PART_CTL_CREATE: 1816 error = g_part_ctl_create(req, &gpp); 1817 break; 1818 case G_PART_CTL_DELETE: 1819 error = g_part_ctl_delete(req, &gpp); 1820 break; 1821 case G_PART_CTL_DESTROY: 1822 error = g_part_ctl_destroy(req, &gpp); 1823 break; 1824 case G_PART_CTL_MODIFY: 1825 error = g_part_ctl_modify(req, &gpp); 1826 break; 1827 case G_PART_CTL_MOVE: 1828 error = g_part_ctl_move(req, &gpp); 1829 break; 1830 case G_PART_CTL_RECOVER: 1831 error = g_part_ctl_recover(req, &gpp); 1832 break; 1833 case G_PART_CTL_RESIZE: 1834 error = g_part_ctl_resize(req, &gpp); 1835 break; 1836 case G_PART_CTL_SET: 1837 error = g_part_ctl_setunset(req, &gpp, 1); 1838 break; 1839 case G_PART_CTL_UNDO: 1840 error = g_part_ctl_undo(req, &gpp); 1841 break; 1842 case G_PART_CTL_UNSET: 1843 error = g_part_ctl_setunset(req, &gpp, 0); 1844 break; 1845 } 1846 1847 /* Implement automatic commit. */ 1848 if (!error) { 1849 auto_commit = (modifies && 1850 (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1851 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1852 if (auto_commit) { 1853 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s", 1854 __func__)); 1855 error = g_part_ctl_commit(req, &gpp); 1856 } 1857 } 1858 1859 out: 1860 if (error && close_on_error) { 1861 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1862 table->gpt_opened = 0; 1863 } 1864} 1865 1866static int 1867g_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1868 struct g_geom *gp) 1869{ 1870 1871 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1872 g_topology_assert(); 1873 1874 g_part_wither(gp, EINVAL); 1875 return (0); 1876} 1877 1878static struct g_geom * 1879g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1880{ 1881 struct g_consumer *cp; 1882 struct g_geom *gp; 1883 struct g_part_entry *entry; 1884 struct g_part_table *table; 1885 struct root_hold_token *rht; 1886 int attr, depth; 1887 int error; 1888 1889 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1890 g_topology_assert(); 1891 1892 /* Skip providers that are already open for writing. */ 1893 if (pp->acw > 0) 1894 return (NULL); 1895 1896 /* 1897 * Create a GEOM with consumer and hook it up to the provider. 1898 * With that we become part of the topology. Optain read access 1899 * to the provider. 1900 */ 1901 gp = g_new_geomf(mp, "%s", pp->name); 1902 cp = g_new_consumer(gp); 1903 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 1904 error = g_attach(cp, pp); 1905 if (error == 0) 1906 error = g_access(cp, 1, 0, 0); 1907 if (error != 0) { 1908 if (cp->provider) 1909 g_detach(cp); 1910 g_destroy_consumer(cp); 1911 g_destroy_geom(gp); 1912 return (NULL); 1913 } 1914 1915 rht = root_mount_hold(mp->name); 1916 g_topology_unlock(); 1917 1918 /* 1919 * Short-circuit the whole probing galore when there's no 1920 * media present. 1921 */ 1922 if (pp->mediasize == 0 || pp->sectorsize == 0) { 1923 error = ENODEV; 1924 goto fail; 1925 } 1926 1927 /* Make sure we can nest and if so, determine our depth. */ 1928 error = g_getattr("PART::isleaf", cp, &attr); 1929 if (!error && attr) { 1930 error = ENODEV; 1931 goto fail; 1932 } 1933 error = g_getattr("PART::depth", cp, &attr); 1934 depth = (!error) ? attr + 1 : 0; 1935 1936 error = g_part_probe(gp, cp, depth); 1937 if (error) 1938 goto fail; 1939 1940 table = gp->softc; 1941 1942 /* 1943 * Synthesize a disk geometry. Some partitioning schemes 1944 * depend on it and since some file systems need it even 1945 * when the partitition scheme doesn't, we do it here in 1946 * scheme-independent code. 1947 */ 1948 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1949 1950 error = G_PART_READ(table, cp); 1951 if (error) 1952 goto fail; 1953 error = g_part_check_integrity(table, cp); 1954 if (error) 1955 goto fail; 1956 1957 g_topology_lock(); 1958 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1959 if (!entry->gpe_internal) 1960 g_part_new_provider(gp, table, entry); 1961 } 1962 1963 root_mount_rel(rht); 1964 g_access(cp, -1, 0, 0); 1965 return (gp); 1966 1967 fail: 1968 g_topology_lock(); 1969 root_mount_rel(rht); 1970 g_access(cp, -1, 0, 0); 1971 g_detach(cp); 1972 g_destroy_consumer(cp); 1973 g_destroy_geom(gp); 1974 return (NULL); 1975} 1976 1977/* 1978 * Geom methods. 1979 */ 1980 1981static int 1982g_part_access(struct g_provider *pp, int dr, int dw, int de) 1983{ 1984 struct g_consumer *cp; 1985 1986 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1987 dw, de)); 1988 1989 cp = LIST_FIRST(&pp->geom->consumer); 1990 1991 /* We always gain write-exclusive access. */ 1992 return (g_access(cp, dr, dw, dw + de)); 1993} 1994 1995static void 1996g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1997 struct g_consumer *cp, struct g_provider *pp) 1998{ 1999 char buf[64]; 2000 struct g_part_entry *entry; 2001 struct g_part_table *table; 2002 2003 KASSERT(sb != NULL && gp != NULL, ("%s", __func__)); 2004 table = gp->softc; 2005 2006 if (indent == NULL) { 2007 KASSERT(cp == NULL && pp != NULL, ("%s", __func__)); 2008 entry = pp->private; 2009 if (entry == NULL) 2010 return; 2011 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 2012 (uintmax_t)entry->gpe_offset, 2013 G_PART_TYPE(table, entry, buf, sizeof(buf))); 2014 /* 2015 * libdisk compatibility quirk - the scheme dumps the 2016 * slicer name and partition type in a way that is 2017 * compatible with libdisk. When libdisk is not used 2018 * anymore, this should go away. 2019 */ 2020 G_PART_DUMPCONF(table, entry, sb, indent); 2021 } else if (cp != NULL) { /* Consumer configuration. */ 2022 KASSERT(pp == NULL, ("%s", __func__)); 2023 /* none */ 2024 } else if (pp != NULL) { /* Provider configuration. */ 2025 entry = pp->private; 2026 if (entry == NULL) 2027 return; 2028 sbuf_printf(sb, "%s<start>%ju</start>\n", indent, 2029 (uintmax_t)entry->gpe_start); 2030 sbuf_printf(sb, "%s<end>%ju</end>\n", indent, 2031 (uintmax_t)entry->gpe_end); 2032 sbuf_printf(sb, "%s<index>%u</index>\n", indent, 2033 entry->gpe_index); 2034 sbuf_printf(sb, "%s<type>%s</type>\n", indent, 2035 G_PART_TYPE(table, entry, buf, sizeof(buf))); 2036 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 2037 (uintmax_t)entry->gpe_offset); 2038 sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 2039 (uintmax_t)pp->mediasize); 2040 G_PART_DUMPCONF(table, entry, sb, indent); 2041 } else { /* Geom configuration. */ 2042 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 2043 table->gpt_scheme->name); 2044 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 2045 table->gpt_entries); 2046 sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 2047 (uintmax_t)table->gpt_first); 2048 sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 2049 (uintmax_t)table->gpt_last); 2050 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 2051 table->gpt_sectors); 2052 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 2053 table->gpt_heads); 2054 sbuf_printf(sb, "%s<state>%s</state>\n", indent, 2055 table->gpt_corrupt ? "CORRUPT": "OK"); 2056 sbuf_printf(sb, "%s<modified>%s</modified>\n", indent, 2057 table->gpt_opened ? "true": "false"); 2058 G_PART_DUMPCONF(table, NULL, sb, indent); 2059 } 2060} 2061 2062static void 2063g_part_resize(struct g_consumer *cp) 2064{ 2065 struct g_part_table *table; 2066 2067 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 2068 g_topology_assert(); 2069 2070 table = cp->geom->softc; 2071 if (table->gpt_opened == 0) { 2072 if (g_access(cp, 1, 1, 1) != 0) 2073 return; 2074 table->gpt_opened = 1; 2075 } 2076 if (G_PART_RESIZE(table, NULL, NULL) == 0) 2077 printf("GEOM_PART: %s was automatically resized.\n" 2078 " Use `gpart commit %s` to save changes or " 2079 "`gpart undo %s` to revert them.\n", cp->geom->name, 2080 cp->geom->name, cp->geom->name); 2081 if (g_part_check_integrity(table, cp) != 0) { 2082 g_access(cp, -1, -1, -1); 2083 table->gpt_opened = 0; 2084 g_part_wither(table->gpt_gp, ENXIO); 2085 } 2086} 2087 2088static void 2089g_part_orphan(struct g_consumer *cp) 2090{ 2091 struct g_provider *pp; 2092 struct g_part_table *table; 2093 2094 pp = cp->provider; 2095 KASSERT(pp != NULL, ("%s", __func__)); 2096 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 2097 g_topology_assert(); 2098 2099 KASSERT(pp->error != 0, ("%s", __func__)); 2100 table = cp->geom->softc; 2101 if (table != NULL && table->gpt_opened) 2102 g_access(cp, -1, -1, -1); 2103 g_part_wither(cp->geom, pp->error); 2104} 2105 2106static void 2107g_part_spoiled(struct g_consumer *cp) 2108{ 2109 2110 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 2111 g_topology_assert(); 2112 2113 cp->flags |= G_CF_ORPHAN; 2114 g_part_wither(cp->geom, ENXIO); 2115} 2116 2117static void 2118g_part_start(struct bio *bp) 2119{ 2120 struct bio *bp2; 2121 struct g_consumer *cp; 2122 struct g_geom *gp; 2123 struct g_part_entry *entry; 2124 struct g_part_table *table; 2125 struct g_kerneldump *gkd; 2126 struct g_provider *pp; 2127 char buf[64]; 2128 2129 pp = bp->bio_to; 2130 gp = pp->geom; 2131 table = gp->softc; 2132 cp = LIST_FIRST(&gp->consumer); 2133 2134 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 2135 pp->name)); 2136 2137 entry = pp->private; 2138 if (entry == NULL) { 2139 g_io_deliver(bp, ENXIO); 2140 return; 2141 } 2142 2143 switch(bp->bio_cmd) { 2144 case BIO_DELETE: 2145 case BIO_READ: 2146 case BIO_WRITE: 2147 if (bp->bio_offset >= pp->mediasize) { 2148 g_io_deliver(bp, EIO); 2149 return; 2150 } 2151 bp2 = g_clone_bio(bp); 2152 if (bp2 == NULL) { 2153 g_io_deliver(bp, ENOMEM); 2154 return; 2155 } 2156 if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 2157 bp2->bio_length = pp->mediasize - bp2->bio_offset; 2158 bp2->bio_done = g_std_done; 2159 bp2->bio_offset += entry->gpe_offset; 2160 g_io_request(bp2, cp); 2161 return; 2162 case BIO_FLUSH: 2163 break; 2164 case BIO_GETATTR: 2165 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 2166 return; 2167 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 2168 return; 2169 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 2170 return; 2171 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 2172 return; 2173 if (g_handleattr_str(bp, "PART::scheme", 2174 table->gpt_scheme->name)) 2175 return; 2176 if (g_handleattr_str(bp, "PART::type", 2177 G_PART_TYPE(table, entry, buf, sizeof(buf)))) 2178 return; 2179 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 2180 /* 2181 * Check that the partition is suitable for kernel 2182 * dumps. Typically only swap partitions should be 2183 * used. If the request comes from the nested scheme 2184 * we allow dumping there as well. 2185 */ 2186 if ((bp->bio_from == NULL || 2187 bp->bio_from->geom->class != &g_part_class) && 2188 G_PART_DUMPTO(table, entry) == 0) { 2189 g_io_deliver(bp, ENODEV); 2190 printf("GEOM_PART: Partition '%s' not suitable" 2191 " for kernel dumps (wrong type?)\n", 2192 pp->name); 2193 return; 2194 } 2195 gkd = (struct g_kerneldump *)bp->bio_data; 2196 if (gkd->offset >= pp->mediasize) { 2197 g_io_deliver(bp, EIO); 2198 return; 2199 } 2200 if (gkd->offset + gkd->length > pp->mediasize) 2201 gkd->length = pp->mediasize - gkd->offset; 2202 gkd->offset += entry->gpe_offset; 2203 } 2204 break; 2205 default: 2206 g_io_deliver(bp, EOPNOTSUPP); 2207 return; 2208 } 2209 2210 bp2 = g_clone_bio(bp); 2211 if (bp2 == NULL) { 2212 g_io_deliver(bp, ENOMEM); 2213 return; 2214 } 2215 bp2->bio_done = g_std_done; 2216 g_io_request(bp2, cp); 2217} 2218 2219static void 2220g_part_init(struct g_class *mp) 2221{ 2222 2223 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list); 2224} 2225 2226static void 2227g_part_fini(struct g_class *mp) 2228{ 2229 2230 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list); 2231} 2232 2233static void 2234g_part_unload_event(void *arg, int flag) 2235{ 2236 struct g_consumer *cp; 2237 struct g_geom *gp; 2238 struct g_provider *pp; 2239 struct g_part_scheme *scheme; 2240 struct g_part_table *table; 2241 uintptr_t *xchg; 2242 int acc, error; 2243 2244 if (flag == EV_CANCEL) 2245 return; 2246 2247 xchg = arg; 2248 error = 0; 2249 scheme = (void *)(*xchg); 2250 2251 g_topology_assert(); 2252 2253 LIST_FOREACH(gp, &g_part_class.geom, geom) { 2254 table = gp->softc; 2255 if (table->gpt_scheme != scheme) 2256 continue; 2257 2258 acc = 0; 2259 LIST_FOREACH(pp, &gp->provider, provider) 2260 acc += pp->acr + pp->acw + pp->ace; 2261 LIST_FOREACH(cp, &gp->consumer, consumer) 2262 acc += cp->acr + cp->acw + cp->ace; 2263 2264 if (!acc) 2265 g_part_wither(gp, ENOSYS); 2266 else 2267 error = EBUSY; 2268 } 2269 2270 if (!error) 2271 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 2272 2273 *xchg = error; 2274} 2275 2276int 2277g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) 2278{ 2279 struct g_part_scheme *iter; 2280 uintptr_t arg; 2281 int error; 2282 2283 error = 0; 2284 switch (type) { 2285 case MOD_LOAD: 2286 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { 2287 if (scheme == iter) { 2288 printf("GEOM_PART: scheme %s is already " 2289 "registered!\n", scheme->name); 2290 break; 2291 } 2292 } 2293 if (iter == NULL) { 2294 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, 2295 scheme_list); 2296 g_retaste(&g_part_class); 2297 } 2298 break; 2299 case MOD_UNLOAD: 2300 arg = (uintptr_t)scheme; 2301 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, 2302 NULL); 2303 if (error == 0) 2304 error = arg; 2305 break; 2306 default: 2307 error = EOPNOTSUPP; 2308 break; 2309 } 2310 2311 return (error); 2312} 2313