g_part.c revision 256880
1251881Speter/*- 2251881Speter * Copyright (c) 2002, 2005-2009 Marcel Moolenaar 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * Redistribution and use in source and binary forms, with or without 6251881Speter * modification, are permitted provided that the following conditions 7251881Speter * are met: 8251881Speter * 9251881Speter * 1. Redistributions of source code must retain the above copyright 10251881Speter * notice, this list of conditions and the following disclaimer. 11251881Speter * 2. Redistributions in binary form must reproduce the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer in the 13251881Speter * documentation and/or other materials provided with the distribution. 14251881Speter * 15251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16251881Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17251881Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18251881Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19251881Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20251881Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21251881Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22251881Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23251881Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24251881Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25251881Speter */ 26251881Speter 27251881Speter#include <sys/cdefs.h> 28251881Speter__FBSDID("$FreeBSD: head/sys/geom/part/g_part.c 256880 2013-10-22 08:22:19Z mav $"); 29251881Speter 30251881Speter#include <sys/param.h> 31251881Speter#include <sys/bio.h> 32251881Speter#include <sys/endian.h> 33251881Speter#include <sys/kernel.h> 34251881Speter#include <sys/kobj.h> 35251881Speter#include <sys/limits.h> 36251881Speter#include <sys/lock.h> 37251881Speter#include <sys/malloc.h> 38251881Speter#include <sys/mutex.h> 39251881Speter#include <sys/queue.h> 40251881Speter#include <sys/sbuf.h> 41251881Speter#include <sys/sysctl.h> 42251881Speter#include <sys/systm.h> 43251881Speter#include <sys/uuid.h> 44251881Speter#include <geom/geom.h> 45251881Speter#include <geom/geom_ctl.h> 46251881Speter#include <geom/geom_int.h> 47251881Speter#include <geom/part/g_part.h> 48251881Speter 49251881Speter#include "g_part_if.h" 50251881Speter 51251881Speter#ifndef _PATH_DEV 52251881Speter#define _PATH_DEV "/dev/" 53251881Speter#endif 54251881Speter 55251881Speterstatic kobj_method_t g_part_null_methods[] = { 56251881Speter { 0, 0 } 57251881Speter}; 58251881Speter 59251881Speterstatic struct g_part_scheme g_part_null_scheme = { 60251881Speter "(none)", 61251881Speter g_part_null_methods, 62251881Speter sizeof(struct g_part_table), 63251881Speter}; 64251881Speter 65251881SpeterTAILQ_HEAD(, g_part_scheme) g_part_schemes = 66251881Speter TAILQ_HEAD_INITIALIZER(g_part_schemes); 67289180Speter 68289180Speterstruct g_part_alias_list { 69289180Speter const char *lexeme; 70251881Speter enum g_part_alias alias; 71251881Speter} g_part_alias_list[G_PART_ALIAS_COUNT] = { 72251881Speter { "apple-boot", G_PART_ALIAS_APPLE_BOOT }, 73251881Speter { "apple-hfs", G_PART_ALIAS_APPLE_HFS }, 74251881Speter { "apple-label", G_PART_ALIAS_APPLE_LABEL }, 75251881Speter { "apple-raid", G_PART_ALIAS_APPLE_RAID }, 76251881Speter { "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE }, 77251881Speter { "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY }, 78251881Speter { "apple-ufs", G_PART_ALIAS_APPLE_UFS }, 79251881Speter { "bios-boot", G_PART_ALIAS_BIOS_BOOT }, 80251881Speter { "ebr", G_PART_ALIAS_EBR }, 81251881Speter { "efi", G_PART_ALIAS_EFI }, 82251881Speter { "fat16", G_PART_ALIAS_MS_FAT16 }, 83251881Speter { "fat32", G_PART_ALIAS_MS_FAT32 }, 84251881Speter { "freebsd", G_PART_ALIAS_FREEBSD }, 85251881Speter { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT }, 86251881Speter { "freebsd-nandfs", G_PART_ALIAS_FREEBSD_NANDFS }, 87251881Speter { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP }, 88251881Speter { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS }, 89251881Speter { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM }, 90251881Speter { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS }, 91251881Speter { "linux-data", G_PART_ALIAS_LINUX_DATA }, 92251881Speter { "linux-lvm", G_PART_ALIAS_LINUX_LVM }, 93251881Speter { "linux-raid", G_PART_ALIAS_LINUX_RAID }, 94251881Speter { "linux-swap", G_PART_ALIAS_LINUX_SWAP }, 95251881Speter { "mbr", G_PART_ALIAS_MBR }, 96251881Speter { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA }, 97251881Speter { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA }, 98251881Speter { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA }, 99251881Speter { "ms-reserved", G_PART_ALIAS_MS_RESERVED }, 100251881Speter { "ntfs", G_PART_ALIAS_MS_NTFS }, 101251881Speter { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD }, 102251881Speter { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD }, 103251881Speter { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS }, 104251881Speter { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS }, 105251881Speter { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID }, 106251881Speter { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP }, 107251881Speter { "vmware-vmfs", G_PART_ALIAS_VMFS }, 108251881Speter { "vmware-vmkdiag", G_PART_ALIAS_VMKDIAG }, 109251881Speter { "vmware-reserved", G_PART_ALIAS_VMRESERVED }, 110251881Speter}; 111251881Speter 112251881SpeterSYSCTL_DECL(_kern_geom); 113251881SpeterSYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW, 0, 114251881Speter "GEOM_PART stuff"); 115251881Speterstatic u_int check_integrity = 1; 116251881SpeterTUNABLE_INT("kern.geom.part.check_integrity", &check_integrity); 117251881SpeterSYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity, 118251881Speter CTLFLAG_RW | CTLFLAG_TUN, &check_integrity, 1, 119251881Speter "Enable integrity checking"); 120251881Speter 121251881Speter/* 122251881Speter * The GEOM partitioning class. 123251881Speter */ 124251881Speterstatic g_ctl_req_t g_part_ctlreq; 125251881Speterstatic g_ctl_destroy_geom_t g_part_destroy_geom; 126251881Speterstatic g_fini_t g_part_fini; 127251881Speterstatic g_init_t g_part_init; 128251881Speterstatic g_taste_t g_part_taste; 129251881Speter 130251881Speterstatic g_access_t g_part_access; 131251881Speterstatic g_dumpconf_t g_part_dumpconf; 132251881Speterstatic g_orphan_t g_part_orphan; 133251881Speterstatic g_spoiled_t g_part_spoiled; 134251881Speterstatic g_start_t g_part_start; 135251881Speterstatic g_resize_t g_part_resize; 136251881Speter 137251881Speterstatic struct g_class g_part_class = { 138251881Speter .name = "PART", 139251881Speter .version = G_VERSION, 140251881Speter /* Class methods. */ 141251881Speter .ctlreq = g_part_ctlreq, 142251881Speter .destroy_geom = g_part_destroy_geom, 143251881Speter .fini = g_part_fini, 144251881Speter .init = g_part_init, 145251881Speter .taste = g_part_taste, 146251881Speter /* Geom methods. */ 147251881Speter .access = g_part_access, 148251881Speter .dumpconf = g_part_dumpconf, 149251881Speter .orphan = g_part_orphan, 150251881Speter .spoiled = g_part_spoiled, 151251881Speter .start = g_part_start, 152251881Speter .resize = g_part_resize 153251881Speter}; 154251881Speter 155251881SpeterDECLARE_GEOM_CLASS(g_part_class, g_part); 156251881SpeterMODULE_VERSION(g_part, 0); 157251881Speter 158251881Speter/* 159251881Speter * Support functions. 160251881Speter */ 161251881Speter 162251881Speterstatic void g_part_wither(struct g_geom *, int); 163251881Speter 164251881Speterconst char * 165251881Speterg_part_alias_name(enum g_part_alias alias) 166251881Speter{ 167251881Speter int i; 168251881Speter 169251881Speter for (i = 0; i < G_PART_ALIAS_COUNT; i++) { 170251881Speter if (g_part_alias_list[i].alias != alias) 171251881Speter continue; 172251881Speter return (g_part_alias_list[i].lexeme); 173251881Speter } 174251881Speter 175251881Speter return (NULL); 176251881Speter} 177251881Speter 178251881Spetervoid 179251881Speterg_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs, 180251881Speter u_int *bestheads) 181251881Speter{ 182251881Speter static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 }; 183251881Speter off_t chs, cylinders; 184251881Speter u_int heads; 185251881Speter int idx; 186251881Speter 187251881Speter *bestchs = 0; 188251881Speter *bestheads = 0; 189251881Speter for (idx = 0; candidate_heads[idx] != 0; idx++) { 190251881Speter heads = candidate_heads[idx]; 191251881Speter cylinders = blocks / heads / sectors; 192251881Speter if (cylinders < heads || cylinders < sectors) 193251881Speter break; 194251881Speter if (cylinders > 1023) 195251881Speter continue; 196251881Speter chs = cylinders * heads * sectors; 197251881Speter if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) { 198251881Speter *bestchs = chs; 199251881Speter *bestheads = heads; 200251881Speter } 201251881Speter } 202251881Speter} 203251881Speter 204251881Speterstatic void 205251881Speterg_part_geometry(struct g_part_table *table, struct g_consumer *cp, 206251881Speter off_t blocks) 207251881Speter{ 208251881Speter static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 }; 209251881Speter off_t chs, bestchs; 210251881Speter u_int heads, sectors; 211251881Speter int idx; 212251881Speter 213251881Speter if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || sectors == 0 || 214251881Speter g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) { 215251881Speter table->gpt_fixgeom = 0; 216251881Speter table->gpt_heads = 0; 217251881Speter table->gpt_sectors = 0; 218251881Speter bestchs = 0; 219251881Speter for (idx = 0; candidate_sectors[idx] != 0; idx++) { 220251881Speter sectors = candidate_sectors[idx]; 221251881Speter g_part_geometry_heads(blocks, sectors, &chs, &heads); 222251881Speter if (chs == 0) 223251881Speter continue; 224251881Speter /* 225251881Speter * Prefer a geometry with sectors > 1, but only if 226251881Speter * it doesn't bump down the number of heads to 1. 227251881Speter */ 228251881Speter if (chs > bestchs || (chs == bestchs && heads > 1 && 229251881Speter table->gpt_sectors == 1)) { 230251881Speter bestchs = chs; 231251881Speter table->gpt_heads = heads; 232251881Speter table->gpt_sectors = sectors; 233251881Speter } 234251881Speter } 235251881Speter /* 236251881Speter * If we didn't find a geometry at all, then the disk is 237251881Speter * too big. This means we can use the maximum number of 238251881Speter * heads and sectors. 239251881Speter */ 240251881Speter if (bestchs == 0) { 241251881Speter table->gpt_heads = 255; 242251881Speter table->gpt_sectors = 63; 243251881Speter } 244251881Speter } else { 245289180Speter table->gpt_fixgeom = 1; 246251881Speter table->gpt_heads = heads; 247251881Speter table->gpt_sectors = sectors; 248251881Speter } 249251881Speter} 250251881Speter 251251881Speter#define DPRINTF(...) if (bootverbose) { \ 252251881Speter printf("GEOM_PART: " __VA_ARGS__); \ 253251881Speter} 254251881Speter 255251881Speterstatic int 256251881Speterg_part_check_integrity(struct g_part_table *table, struct g_consumer *cp) 257251881Speter{ 258251881Speter struct g_part_entry *e1, *e2; 259251881Speter struct g_provider *pp; 260251881Speter off_t offset; 261251881Speter int failed; 262289180Speter 263251881Speter failed = 0; 264251881Speter pp = cp->provider; 265251881Speter if (table->gpt_last < table->gpt_first) { 266251881Speter DPRINTF("last LBA is below first LBA: %jd < %jd\n", 267251881Speter (intmax_t)table->gpt_last, (intmax_t)table->gpt_first); 268251881Speter failed++; 269251881Speter } 270251881Speter if (table->gpt_last > pp->mediasize / pp->sectorsize - 1) { 271251881Speter DPRINTF("last LBA extends beyond mediasize: " 272251881Speter "%jd > %jd\n", (intmax_t)table->gpt_last, 273251881Speter (intmax_t)pp->mediasize / pp->sectorsize - 1); 274251881Speter failed++; 275251881Speter } 276251881Speter LIST_FOREACH(e1, &table->gpt_entry, gpe_entry) { 277251881Speter if (e1->gpe_deleted || e1->gpe_internal) 278251881Speter continue; 279251881Speter if (e1->gpe_start < table->gpt_first) { 280251881Speter DPRINTF("partition %d has start offset below first " 281251881Speter "LBA: %jd < %jd\n", e1->gpe_index, 282251881Speter (intmax_t)e1->gpe_start, 283251881Speter (intmax_t)table->gpt_first); 284251881Speter failed++; 285251881Speter } 286251881Speter if (e1->gpe_start > table->gpt_last) { 287251881Speter DPRINTF("partition %d has start offset beyond last " 288251881Speter "LBA: %jd > %jd\n", e1->gpe_index, 289251881Speter (intmax_t)e1->gpe_start, 290251881Speter (intmax_t)table->gpt_last); 291251881Speter failed++; 292251881Speter } 293251881Speter if (e1->gpe_end < e1->gpe_start) { 294251881Speter DPRINTF("partition %d has end offset below start " 295251881Speter "offset: %jd < %jd\n", e1->gpe_index, 296251881Speter (intmax_t)e1->gpe_end, 297251881Speter (intmax_t)e1->gpe_start); 298251881Speter failed++; 299251881Speter } 300251881Speter if (e1->gpe_end > table->gpt_last) { 301251881Speter DPRINTF("partition %d has end offset beyond last " 302251881Speter "LBA: %jd > %jd\n", e1->gpe_index, 303251881Speter (intmax_t)e1->gpe_end, 304251881Speter (intmax_t)table->gpt_last); 305251881Speter failed++; 306251881Speter } 307251881Speter if (pp->stripesize > 0) { 308251881Speter offset = e1->gpe_start * pp->sectorsize; 309251881Speter if (e1->gpe_offset > offset) 310251881Speter offset = e1->gpe_offset; 311251881Speter if ((offset + pp->stripeoffset) % pp->stripesize) { 312251881Speter DPRINTF("partition %d is not aligned on %u " 313251881Speter "bytes\n", e1->gpe_index, pp->stripesize); 314251881Speter /* Don't treat this as a critical failure */ 315251881Speter } 316251881Speter } 317251881Speter e2 = e1; 318251881Speter while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) { 319251881Speter if (e2->gpe_deleted || e2->gpe_internal) 320251881Speter continue; 321251881Speter if (e1->gpe_start >= e2->gpe_start && 322251881Speter e1->gpe_start <= e2->gpe_end) { 323251881Speter DPRINTF("partition %d has start offset inside " 324251881Speter "partition %d: start[%d] %jd >= start[%d] " 325251881Speter "%jd <= end[%d] %jd\n", 326251881Speter e1->gpe_index, e2->gpe_index, 327251881Speter e2->gpe_index, (intmax_t)e2->gpe_start, 328251881Speter e1->gpe_index, (intmax_t)e1->gpe_start, 329251881Speter e2->gpe_index, (intmax_t)e2->gpe_end); 330251881Speter failed++; 331251881Speter } 332251881Speter if (e1->gpe_end >= e2->gpe_start && 333251881Speter e1->gpe_end <= e2->gpe_end) { 334251881Speter DPRINTF("partition %d has end offset inside " 335251881Speter "partition %d: start[%d] %jd >= end[%d] " 336251881Speter "%jd <= end[%d] %jd\n", 337251881Speter e1->gpe_index, e2->gpe_index, 338251881Speter e2->gpe_index, (intmax_t)e2->gpe_start, 339251881Speter e1->gpe_index, (intmax_t)e1->gpe_end, 340251881Speter e2->gpe_index, (intmax_t)e2->gpe_end); 341251881Speter failed++; 342251881Speter } 343251881Speter if (e1->gpe_start < e2->gpe_start && 344251881Speter e1->gpe_end > e2->gpe_end) { 345251881Speter DPRINTF("partition %d contains partition %d: " 346251881Speter "start[%d] %jd > start[%d] %jd, end[%d] " 347251881Speter "%jd < end[%d] %jd\n", 348251881Speter e1->gpe_index, e2->gpe_index, 349251881Speter e1->gpe_index, (intmax_t)e1->gpe_start, 350251881Speter e2->gpe_index, (intmax_t)e2->gpe_start, 351251881Speter e2->gpe_index, (intmax_t)e2->gpe_end, 352251881Speter e1->gpe_index, (intmax_t)e1->gpe_end); 353251881Speter failed++; 354251881Speter } 355251881Speter } 356251881Speter } 357251881Speter if (failed != 0) { 358251881Speter printf("GEOM_PART: integrity check failed (%s, %s)\n", 359251881Speter pp->name, table->gpt_scheme->name); 360251881Speter if (check_integrity != 0) 361251881Speter return (EINVAL); 362251881Speter table->gpt_corrupt = 1; 363251881Speter } 364251881Speter return (0); 365251881Speter} 366251881Speter#undef DPRINTF 367251881Speter 368251881Speterstruct g_part_entry * 369251881Speterg_part_new_entry(struct g_part_table *table, int index, quad_t start, 370251881Speter quad_t end) 371251881Speter{ 372251881Speter struct g_part_entry *entry, *last; 373251881Speter 374251881Speter last = NULL; 375251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 376251881Speter if (entry->gpe_index == index) 377251881Speter break; 378251881Speter if (entry->gpe_index > index) { 379251881Speter entry = NULL; 380251881Speter break; 381251881Speter } 382251881Speter last = entry; 383251881Speter } 384251881Speter if (entry == NULL) { 385251881Speter entry = g_malloc(table->gpt_scheme->gps_entrysz, 386251881Speter M_WAITOK | M_ZERO); 387251881Speter entry->gpe_index = index; 388251881Speter if (last == NULL) 389251881Speter LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 390251881Speter else 391251881Speter LIST_INSERT_AFTER(last, entry, gpe_entry); 392251881Speter } else 393251881Speter entry->gpe_offset = 0; 394251881Speter entry->gpe_start = start; 395251881Speter entry->gpe_end = end; 396251881Speter return (entry); 397251881Speter} 398251881Speter 399251881Speterstatic void 400251881Speterg_part_new_provider(struct g_geom *gp, struct g_part_table *table, 401251881Speter struct g_part_entry *entry) 402251881Speter{ 403251881Speter struct g_consumer *cp; 404251881Speter struct g_provider *pp; 405251881Speter struct sbuf *sb; 406251881Speter off_t offset; 407251881Speter 408251881Speter cp = LIST_FIRST(&gp->consumer); 409251881Speter pp = cp->provider; 410286506Speter 411251881Speter offset = entry->gpe_start * pp->sectorsize; 412251881Speter if (entry->gpe_offset < offset) 413251881Speter entry->gpe_offset = offset; 414251881Speter 415251881Speter if (entry->gpe_pp == NULL) { 416251881Speter sb = sbuf_new_auto(); 417251881Speter G_PART_FULLNAME(table, entry, sb, gp->name); 418251881Speter sbuf_finish(sb); 419251881Speter entry->gpe_pp = g_new_providerf(gp, "%s", sbuf_data(sb)); 420251881Speter sbuf_delete(sb); 421251881Speter entry->gpe_pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 422251881Speter entry->gpe_pp->private = entry; /* Close the circle. */ 423251881Speter } 424251881Speter entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */ 425251881Speter entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 426251881Speter pp->sectorsize; 427251881Speter entry->gpe_pp->mediasize -= entry->gpe_offset - offset; 428251881Speter entry->gpe_pp->sectorsize = pp->sectorsize; 429251881Speter entry->gpe_pp->stripesize = pp->stripesize; 430251881Speter entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset; 431251881Speter if (pp->stripesize > 0) 432251881Speter entry->gpe_pp->stripeoffset %= pp->stripesize; 433251881Speter entry->gpe_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; 434251881Speter g_error_provider(entry->gpe_pp, 0); 435251881Speter} 436251881Speter 437257936Speterstatic struct g_geom* 438251881Speterg_part_find_geom(const char *name) 439257936Speter{ 440251881Speter struct g_geom *gp; 441251881Speter LIST_FOREACH(gp, &g_part_class.geom, geom) { 442251881Speter if (!strcmp(name, gp->name)) 443257936Speter break; 444257936Speter } 445257936Speter return (gp); 446257936Speter} 447257936Speter 448257936Speterstatic int 449251881Speterg_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v) 450251881Speter{ 451251881Speter struct g_geom *gp; 452251881Speter const char *gname; 453251881Speter 454251881Speter gname = gctl_get_asciiparam(req, name); 455251881Speter if (gname == NULL) 456251881Speter return (ENOATTR); 457251881Speter if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 458251881Speter gname += sizeof(_PATH_DEV) - 1; 459251881Speter gp = g_part_find_geom(gname); 460251881Speter if (gp == NULL) { 461251881Speter gctl_error(req, "%d %s '%s'", EINVAL, name, gname); 462251881Speter return (EINVAL); 463251881Speter } 464251881Speter if ((gp->flags & G_GEOM_WITHER) != 0) { 465251881Speter gctl_error(req, "%d %s", ENXIO, gname); 466251881Speter return (ENXIO); 467251881Speter } 468251881Speter *v = gp; 469251881Speter return (0); 470251881Speter} 471251881Speter 472251881Speterstatic int 473251881Speterg_part_parm_provider(struct gctl_req *req, const char *name, 474251881Speter struct g_provider **v) 475251881Speter{ 476251881Speter struct g_provider *pp; 477251881Speter const char *pname; 478251881Speter 479251881Speter pname = gctl_get_asciiparam(req, name); 480251881Speter if (pname == NULL) 481251881Speter return (ENOATTR); 482251881Speter if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 483251881Speter pname += sizeof(_PATH_DEV) - 1; 484251881Speter pp = g_provider_by_name(pname); 485251881Speter if (pp == NULL) { 486251881Speter gctl_error(req, "%d %s '%s'", EINVAL, name, pname); 487251881Speter return (EINVAL); 488251881Speter } 489251881Speter *v = pp; 490251881Speter return (0); 491251881Speter} 492251881Speter 493251881Speterstatic int 494251881Speterg_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v) 495251881Speter{ 496251881Speter const char *p; 497251881Speter char *x; 498251881Speter quad_t q; 499251881Speter 500251881Speter p = gctl_get_asciiparam(req, name); 501251881Speter if (p == NULL) 502251881Speter return (ENOATTR); 503251881Speter q = strtoq(p, &x, 0); 504251881Speter if (*x != '\0' || q < 0) { 505251881Speter gctl_error(req, "%d %s '%s'", EINVAL, name, p); 506251881Speter return (EINVAL); 507251881Speter } 508251881Speter *v = q; 509251881Speter return (0); 510251881Speter} 511251881Speter 512251881Speterstatic int 513251881Speterg_part_parm_scheme(struct gctl_req *req, const char *name, 514251881Speter struct g_part_scheme **v) 515251881Speter{ 516251881Speter struct g_part_scheme *s; 517251881Speter const char *p; 518251881Speter 519251881Speter p = gctl_get_asciiparam(req, name); 520251881Speter if (p == NULL) 521251881Speter return (ENOATTR); 522251881Speter TAILQ_FOREACH(s, &g_part_schemes, scheme_list) { 523251881Speter if (s == &g_part_null_scheme) 524251881Speter continue; 525251881Speter if (!strcasecmp(s->name, p)) 526251881Speter break; 527251881Speter } 528251881Speter if (s == NULL) { 529251881Speter gctl_error(req, "%d %s '%s'", EINVAL, name, p); 530251881Speter return (EINVAL); 531251881Speter } 532251881Speter *v = s; 533251881Speter return (0); 534251881Speter} 535251881Speter 536251881Speterstatic int 537251881Speterg_part_parm_str(struct gctl_req *req, const char *name, const char **v) 538251881Speter{ 539251881Speter const char *p; 540251881Speter 541251881Speter p = gctl_get_asciiparam(req, name); 542251881Speter if (p == NULL) 543251881Speter return (ENOATTR); 544251881Speter /* An empty label is always valid. */ 545251881Speter if (strcmp(name, "label") != 0 && p[0] == '\0') { 546251881Speter gctl_error(req, "%d %s '%s'", EINVAL, name, p); 547251881Speter return (EINVAL); 548251881Speter } 549251881Speter *v = p; 550251881Speter return (0); 551251881Speter} 552251881Speter 553251881Speterstatic int 554251881Speterg_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v) 555251881Speter{ 556251881Speter const intmax_t *p; 557251881Speter int size; 558289180Speter 559251881Speter p = gctl_get_param(req, name, &size); 560251881Speter if (p == NULL) 561251881Speter return (ENOATTR); 562251881Speter if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) { 563251881Speter gctl_error(req, "%d %s '%jd'", EINVAL, name, *p); 564251881Speter return (EINVAL); 565251881Speter } 566251881Speter *v = (u_int)*p; 567251881Speter return (0); 568251881Speter} 569251881Speter 570251881Speterstatic int 571251881Speterg_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v) 572251881Speter{ 573251881Speter const uint32_t *p; 574251881Speter int size; 575251881Speter 576251881Speter p = gctl_get_param(req, name, &size); 577251881Speter if (p == NULL) 578251881Speter return (ENOATTR); 579251881Speter if (size != sizeof(*p) || *p > INT_MAX) { 580251881Speter gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p); 581251881Speter return (EINVAL); 582251881Speter } 583251881Speter *v = (u_int)*p; 584251881Speter return (0); 585251881Speter} 586251881Speter 587251881Speterstatic int 588251881Speterg_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v, 589251881Speter unsigned int *s) 590251881Speter{ 591251881Speter const void *p; 592251881Speter int size; 593251881Speter 594251881Speter p = gctl_get_param(req, name, &size); 595251881Speter if (p == NULL) 596251881Speter return (ENOATTR); 597251881Speter *v = p; 598251881Speter *s = size; 599251881Speter return (0); 600251881Speter} 601251881Speter 602251881Speterstatic int 603251881Speterg_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth) 604251881Speter{ 605251881Speter struct g_part_scheme *iter, *scheme; 606251881Speter struct g_part_table *table; 607251881Speter int pri, probe; 608251881Speter 609251881Speter table = gp->softc; 610251881Speter scheme = (table != NULL) ? table->gpt_scheme : NULL; 611251881Speter pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN; 612251881Speter if (pri == 0) 613251881Speter goto done; 614251881Speter if (pri > 0) { /* error */ 615251881Speter scheme = NULL; 616251881Speter pri = INT_MIN; 617251881Speter } 618251881Speter 619251881Speter TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { 620251881Speter if (iter == &g_part_null_scheme) 621251881Speter continue; 622251881Speter table = (void *)kobj_create((kobj_class_t)iter, M_GEOM, 623251881Speter M_WAITOK); 624251881Speter table->gpt_gp = gp; 625251881Speter table->gpt_scheme = iter; 626251881Speter table->gpt_depth = depth; 627251881Speter probe = G_PART_PROBE(table, cp); 628251881Speter if (probe <= 0 && probe > pri) { 629251881Speter pri = probe; 630251881Speter scheme = iter; 631251881Speter if (gp->softc != NULL) 632251881Speter kobj_delete((kobj_t)gp->softc, M_GEOM); 633251881Speter gp->softc = table; 634251881Speter if (pri == 0) 635251881Speter goto done; 636251881Speter } else 637251881Speter kobj_delete((kobj_t)table, M_GEOM); 638251881Speter } 639251881Speter 640251881Speterdone: 641251881Speter return ((scheme == NULL) ? ENXIO : 0); 642251881Speter} 643251881Speter 644251881Speter/* 645251881Speter * Control request functions. 646251881Speter */ 647251881Speter 648289180Speterstatic int 649251881Speterg_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) 650251881Speter{ 651251881Speter struct g_geom *gp; 652251881Speter struct g_provider *pp; 653251881Speter struct g_part_entry *delent, *last, *entry; 654251881Speter struct g_part_table *table; 655251881Speter struct sbuf *sb; 656251881Speter quad_t end; 657251881Speter unsigned int index; 658251881Speter int error; 659251881Speter 660251881Speter gp = gpp->gpp_geom; 661251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 662251881Speter g_topology_assert(); 663251881Speter 664251881Speter pp = LIST_FIRST(&gp->consumer)->provider; 665251881Speter table = gp->softc; 666251881Speter end = gpp->gpp_start + gpp->gpp_size - 1; 667251881Speter 668251881Speter if (gpp->gpp_start < table->gpt_first || 669251881Speter gpp->gpp_start > table->gpt_last) { 670251881Speter gctl_error(req, "%d start '%jd'", EINVAL, 671251881Speter (intmax_t)gpp->gpp_start); 672251881Speter return (EINVAL); 673251881Speter } 674251881Speter if (end < gpp->gpp_start || end > table->gpt_last) { 675251881Speter gctl_error(req, "%d size '%jd'", EINVAL, 676251881Speter (intmax_t)gpp->gpp_size); 677251881Speter return (EINVAL); 678251881Speter } 679251881Speter if (gpp->gpp_index > table->gpt_entries) { 680251881Speter gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index); 681251881Speter return (EINVAL); 682251881Speter } 683251881Speter 684251881Speter delent = last = NULL; 685251881Speter index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1; 686251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 687251881Speter if (entry->gpe_deleted) { 688251881Speter if (entry->gpe_index == index) 689251881Speter delent = entry; 690251881Speter continue; 691251881Speter } 692251881Speter if (entry->gpe_index == index) 693251881Speter index = entry->gpe_index + 1; 694251881Speter if (entry->gpe_index < index) 695251881Speter last = entry; 696251881Speter if (entry->gpe_internal) 697289180Speter continue; 698289180Speter if (gpp->gpp_start >= entry->gpe_start && 699289180Speter gpp->gpp_start <= entry->gpe_end) { 700251881Speter gctl_error(req, "%d start '%jd'", ENOSPC, 701251881Speter (intmax_t)gpp->gpp_start); 702251881Speter return (ENOSPC); 703251881Speter } 704251881Speter if (end >= entry->gpe_start && end <= entry->gpe_end) { 705251881Speter gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end); 706251881Speter return (ENOSPC); 707251881Speter } 708251881Speter if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) { 709251881Speter gctl_error(req, "%d size '%jd'", ENOSPC, 710251881Speter (intmax_t)gpp->gpp_size); 711251881Speter return (ENOSPC); 712251881Speter } 713251881Speter } 714251881Speter if (gpp->gpp_index > 0 && index != gpp->gpp_index) { 715251881Speter gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index); 716251881Speter return (EEXIST); 717251881Speter } 718251881Speter if (index > table->gpt_entries) { 719251881Speter gctl_error(req, "%d index '%d'", ENOSPC, index); 720251881Speter return (ENOSPC); 721251881Speter } 722251881Speter 723251881Speter entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz, 724251881Speter M_WAITOK | M_ZERO) : delent; 725251881Speter entry->gpe_index = index; 726251881Speter entry->gpe_start = gpp->gpp_start; 727251881Speter entry->gpe_end = end; 728251881Speter error = G_PART_ADD(table, entry, gpp); 729251881Speter if (error) { 730251881Speter gctl_error(req, "%d", error); 731251881Speter if (delent == NULL) 732251881Speter g_free(entry); 733251881Speter return (error); 734251881Speter } 735251881Speter if (delent == NULL) { 736251881Speter if (last == NULL) 737251881Speter LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 738251881Speter else 739251881Speter LIST_INSERT_AFTER(last, entry, gpe_entry); 740251881Speter entry->gpe_created = 1; 741251881Speter } else { 742251881Speter entry->gpe_deleted = 0; 743251881Speter entry->gpe_modified = 1; 744251881Speter } 745251881Speter g_part_new_provider(gp, table, entry); 746251881Speter 747251881Speter /* Provide feedback if so requested. */ 748251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 749251881Speter sb = sbuf_new_auto(); 750251881Speter G_PART_FULLNAME(table, entry, sb, gp->name); 751251881Speter if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0) 752251881Speter sbuf_printf(sb, " added, but partition is not " 753251881Speter "aligned on %u bytes\n", pp->stripesize); 754251881Speter else 755251881Speter sbuf_cat(sb, " added\n"); 756251881Speter sbuf_finish(sb); 757251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 758251881Speter sbuf_delete(sb); 759251881Speter } 760251881Speter return (0); 761251881Speter} 762251881Speter 763251881Speterstatic int 764251881Speterg_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp) 765251881Speter{ 766251881Speter struct g_geom *gp; 767251881Speter struct g_part_table *table; 768251881Speter struct sbuf *sb; 769251881Speter int error, sz; 770251881Speter 771251881Speter gp = gpp->gpp_geom; 772251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 773251881Speter g_topology_assert(); 774251881Speter 775251881Speter table = gp->softc; 776251881Speter sz = table->gpt_scheme->gps_bootcodesz; 777251881Speter if (sz == 0) { 778251881Speter error = ENODEV; 779251881Speter goto fail; 780251881Speter } 781251881Speter if (gpp->gpp_codesize > sz) { 782251881Speter error = EFBIG; 783251881Speter goto fail; 784251881Speter } 785251881Speter 786251881Speter error = G_PART_BOOTCODE(table, gpp); 787251881Speter if (error) 788251881Speter goto fail; 789251881Speter 790251881Speter /* Provide feedback if so requested. */ 791251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 792251881Speter sb = sbuf_new_auto(); 793251881Speter sbuf_printf(sb, "bootcode written to %s\n", gp->name); 794251881Speter sbuf_finish(sb); 795251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 796251881Speter sbuf_delete(sb); 797251881Speter } 798251881Speter return (0); 799251881Speter 800251881Speter fail: 801251881Speter gctl_error(req, "%d", error); 802251881Speter return (error); 803251881Speter} 804251881Speter 805251881Speterstatic int 806251881Speterg_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp) 807251881Speter{ 808251881Speter struct g_consumer *cp; 809251881Speter struct g_geom *gp; 810251881Speter struct g_provider *pp; 811251881Speter struct g_part_entry *entry, *tmp; 812251881Speter struct g_part_table *table; 813251881Speter char *buf; 814251881Speter int error, i; 815251881Speter 816251881Speter gp = gpp->gpp_geom; 817251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 818251881Speter g_topology_assert(); 819251881Speter 820251881Speter table = gp->softc; 821251881Speter if (!table->gpt_opened) { 822251881Speter gctl_error(req, "%d", EPERM); 823251881Speter return (EPERM); 824251881Speter } 825251881Speter 826251881Speter g_topology_unlock(); 827251881Speter 828251881Speter cp = LIST_FIRST(&gp->consumer); 829251881Speter if ((table->gpt_smhead | table->gpt_smtail) != 0) { 830251881Speter pp = cp->provider; 831251881Speter buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 832251881Speter while (table->gpt_smhead != 0) { 833286506Speter i = ffs(table->gpt_smhead) - 1; 834286506Speter error = g_write_data(cp, i * pp->sectorsize, buf, 835251881Speter pp->sectorsize); 836251881Speter if (error) { 837251881Speter g_free(buf); 838251881Speter goto fail; 839251881Speter } 840251881Speter table->gpt_smhead &= ~(1 << i); 841251881Speter } 842251881Speter while (table->gpt_smtail != 0) { 843251881Speter i = ffs(table->gpt_smtail) - 1; 844251881Speter error = g_write_data(cp, pp->mediasize - (i + 1) * 845251881Speter pp->sectorsize, buf, pp->sectorsize); 846251881Speter if (error) { 847251881Speter g_free(buf); 848251881Speter goto fail; 849251881Speter } 850251881Speter table->gpt_smtail &= ~(1 << i); 851251881Speter } 852251881Speter g_free(buf); 853251881Speter } 854251881Speter 855251881Speter if (table->gpt_scheme == &g_part_null_scheme) { 856251881Speter g_topology_lock(); 857251881Speter g_access(cp, -1, -1, -1); 858251881Speter g_part_wither(gp, ENXIO); 859251881Speter return (0); 860251881Speter } 861251881Speter 862251881Speter error = G_PART_WRITE(table, cp); 863251881Speter if (error) 864251881Speter goto fail; 865251881Speter 866251881Speter LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 867251881Speter if (!entry->gpe_deleted) { 868251881Speter entry->gpe_created = 0; 869251881Speter entry->gpe_modified = 0; 870251881Speter continue; 871251881Speter } 872251881Speter LIST_REMOVE(entry, gpe_entry); 873251881Speter g_free(entry); 874251881Speter } 875251881Speter table->gpt_created = 0; 876251881Speter table->gpt_opened = 0; 877251881Speter 878251881Speter g_topology_lock(); 879251881Speter g_access(cp, -1, -1, -1); 880251881Speter return (0); 881251881Speter 882251881Speterfail: 883251881Speter g_topology_lock(); 884251881Speter gctl_error(req, "%d", error); 885251881Speter return (error); 886251881Speter} 887251881Speter 888251881Speterstatic int 889251881Speterg_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) 890251881Speter{ 891251881Speter struct g_consumer *cp; 892251881Speter struct g_geom *gp; 893251881Speter struct g_provider *pp; 894251881Speter struct g_part_scheme *scheme; 895251881Speter struct g_part_table *null, *table; 896251881Speter struct sbuf *sb; 897251881Speter int attr, error; 898251881Speter 899251881Speter pp = gpp->gpp_provider; 900251881Speter scheme = gpp->gpp_scheme; 901251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 902251881Speter g_topology_assert(); 903251881Speter 904251881Speter /* Check that there isn't already a g_part geom on the provider. */ 905286506Speter gp = g_part_find_geom(pp->name); 906251881Speter if (gp != NULL) { 907251881Speter null = gp->softc; 908251881Speter if (null->gpt_scheme != &g_part_null_scheme) { 909251881Speter gctl_error(req, "%d geom '%s'", EEXIST, pp->name); 910251881Speter return (EEXIST); 911251881Speter } 912251881Speter } else 913251881Speter null = NULL; 914251881Speter 915251881Speter if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) && 916251881Speter (gpp->gpp_entries < scheme->gps_minent || 917251881Speter gpp->gpp_entries > scheme->gps_maxent)) { 918251881Speter gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries); 919251881Speter return (EINVAL); 920251881Speter } 921251881Speter 922251881Speter if (null == NULL) 923251881Speter gp = g_new_geomf(&g_part_class, "%s", pp->name); 924251881Speter gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM, 925251881Speter M_WAITOK); 926251881Speter table = gp->softc; 927251881Speter table->gpt_gp = gp; 928251881Speter table->gpt_scheme = gpp->gpp_scheme; 929251881Speter table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ? 930251881Speter gpp->gpp_entries : scheme->gps_minent; 931251881Speter LIST_INIT(&table->gpt_entry); 932251881Speter if (null == NULL) { 933251881Speter cp = g_new_consumer(gp); 934251881Speter cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 935251881Speter error = g_attach(cp, pp); 936251881Speter if (error == 0) 937251881Speter error = g_access(cp, 1, 1, 1); 938251881Speter if (error != 0) { 939251881Speter g_part_wither(gp, error); 940251881Speter gctl_error(req, "%d geom '%s'", error, pp->name); 941251881Speter return (error); 942251881Speter } 943251881Speter table->gpt_opened = 1; 944251881Speter } else { 945251881Speter cp = LIST_FIRST(&gp->consumer); 946251881Speter table->gpt_opened = null->gpt_opened; 947251881Speter table->gpt_smhead = null->gpt_smhead; 948251881Speter table->gpt_smtail = null->gpt_smtail; 949251881Speter } 950251881Speter 951251881Speter g_topology_unlock(); 952251881Speter 953251881Speter /* Make sure the provider has media. */ 954251881Speter if (pp->mediasize == 0 || pp->sectorsize == 0) { 955251881Speter error = ENODEV; 956251881Speter goto fail; 957251881Speter } 958251881Speter 959251881Speter /* Make sure we can nest and if so, determine our depth. */ 960251881Speter error = g_getattr("PART::isleaf", cp, &attr); 961251881Speter if (!error && attr) { 962251881Speter error = ENODEV; 963251881Speter goto fail; 964251881Speter } 965251881Speter error = g_getattr("PART::depth", cp, &attr); 966251881Speter table->gpt_depth = (!error) ? attr + 1 : 0; 967251881Speter 968251881Speter /* 969251881Speter * Synthesize a disk geometry. Some partitioning schemes 970251881Speter * depend on it and since some file systems need it even 971251881Speter * when the partitition scheme doesn't, we do it here in 972251881Speter * scheme-independent code. 973251881Speter */ 974251881Speter g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 975251881Speter 976251881Speter error = G_PART_CREATE(table, gpp); 977251881Speter if (error) 978251881Speter goto fail; 979251881Speter 980251881Speter g_topology_lock(); 981251881Speter 982251881Speter table->gpt_created = 1; 983251881Speter if (null != NULL) 984251881Speter kobj_delete((kobj_t)null, M_GEOM); 985251881Speter 986251881Speter /* 987251881Speter * Support automatic commit by filling in the gpp_geom 988251881Speter * parameter. 989251881Speter */ 990251881Speter gpp->gpp_parms |= G_PART_PARM_GEOM; 991251881Speter gpp->gpp_geom = gp; 992251881Speter 993251881Speter /* Provide feedback if so requested. */ 994251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 995251881Speter sb = sbuf_new_auto(); 996251881Speter sbuf_printf(sb, "%s created\n", gp->name); 997251881Speter sbuf_finish(sb); 998251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 999251881Speter sbuf_delete(sb); 1000251881Speter } 1001251881Speter return (0); 1002251881Speter 1003251881Speterfail: 1004251881Speter g_topology_lock(); 1005251881Speter if (null == NULL) { 1006251881Speter g_access(cp, -1, -1, -1); 1007251881Speter g_part_wither(gp, error); 1008251881Speter } else { 1009251881Speter kobj_delete((kobj_t)gp->softc, M_GEOM); 1010251881Speter gp->softc = null; 1011251881Speter } 1012251881Speter gctl_error(req, "%d provider", error); 1013251881Speter return (error); 1014251881Speter} 1015251881Speter 1016251881Speterstatic int 1017251881Speterg_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp) 1018251881Speter{ 1019251881Speter struct g_geom *gp; 1020251881Speter struct g_provider *pp; 1021251881Speter struct g_part_entry *entry; 1022251881Speter struct g_part_table *table; 1023286506Speter struct sbuf *sb; 1024286506Speter 1025286506Speter gp = gpp->gpp_geom; 1026286506Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1027286506Speter g_topology_assert(); 1028286506Speter 1029286506Speter table = gp->softc; 1030286506Speter 1031251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1032251881Speter if (entry->gpe_deleted || entry->gpe_internal) 1033251881Speter continue; 1034251881Speter if (entry->gpe_index == gpp->gpp_index) 1035251881Speter break; 1036251881Speter } 1037251881Speter if (entry == NULL) { 1038251881Speter gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1039251881Speter return (ENOENT); 1040286506Speter } 1041286506Speter 1042286506Speter pp = entry->gpe_pp; 1043286506Speter if (pp != NULL) { 1044286506Speter if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) { 1045286506Speter gctl_error(req, "%d", EBUSY); 1046286506Speter return (EBUSY); 1047286506Speter } 1048286506Speter 1049286506Speter pp->private = NULL; 1050286506Speter entry->gpe_pp = NULL; 1051286506Speter } 1052286506Speter 1053286506Speter if (pp != NULL) 1054286506Speter g_wither_provider(pp, ENXIO); 1055286506Speter 1056286506Speter /* Provide feedback if so requested. */ 1057286506Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1058286506Speter sb = sbuf_new_auto(); 1059286506Speter G_PART_FULLNAME(table, entry, sb, gp->name); 1060286506Speter sbuf_cat(sb, " deleted\n"); 1061286506Speter sbuf_finish(sb); 1062286506Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1063286506Speter sbuf_delete(sb); 1064286506Speter } 1065286506Speter 1066286506Speter if (entry->gpe_created) { 1067286506Speter LIST_REMOVE(entry, gpe_entry); 1068286506Speter g_free(entry); 1069286506Speter } else { 1070286506Speter entry->gpe_modified = 0; 1071286506Speter entry->gpe_deleted = 1; 1072286506Speter } 1073286506Speter return (0); 1074286506Speter} 1075286506Speter 1076286506Speterstatic int 1077286506Speterg_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp) 1078286506Speter{ 1079286506Speter struct g_consumer *cp; 1080286506Speter struct g_geom *gp; 1081251881Speter struct g_provider *pp; 1082251881Speter struct g_part_entry *entry, *tmp; 1083251881Speter struct g_part_table *null, *table; 1084251881Speter struct sbuf *sb; 1085251881Speter int error; 1086251881Speter 1087251881Speter gp = gpp->gpp_geom; 1088286506Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1089251881Speter g_topology_assert(); 1090251881Speter 1091251881Speter table = gp->softc; 1092251881Speter /* Check for busy providers. */ 1093289180Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1094289180Speter if (entry->gpe_deleted || entry->gpe_internal) 1095289180Speter continue; 1096289180Speter if (gpp->gpp_force) { 1097289180Speter pp = entry->gpe_pp; 1098289180Speter if (pp == NULL) 1099251881Speter continue; 1100289180Speter if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 1101289180Speter continue; 1102251881Speter } 1103289180Speter gctl_error(req, "%d", EBUSY); 1104289180Speter return (EBUSY); 1105289180Speter } 1106289180Speter 1107251881Speter if (gpp->gpp_force) { 1108251881Speter /* Destroy all providers. */ 1109289180Speter LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1110289180Speter pp = entry->gpe_pp; 1111251881Speter if (pp != NULL) { 1112289180Speter pp->private = NULL; 1113289180Speter g_wither_provider(pp, ENXIO); 1114289180Speter } 1115289180Speter LIST_REMOVE(entry, gpe_entry); 1116289180Speter g_free(entry); 1117289180Speter } 1118289180Speter } 1119251881Speter 1120289180Speter error = G_PART_DESTROY(table, gpp); 1121251881Speter if (error) { 1122289180Speter gctl_error(req, "%d", error); 1123289180Speter return (error); 1124251881Speter } 1125289180Speter 1126251881Speter gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM, 1127289180Speter M_WAITOK); 1128289180Speter null = gp->softc; 1129289180Speter null->gpt_gp = gp; 1130289180Speter null->gpt_scheme = &g_part_null_scheme; 1131251881Speter LIST_INIT(&null->gpt_entry); 1132289180Speter 1133289180Speter cp = LIST_FIRST(&gp->consumer); 1134289180Speter pp = cp->provider; 1135289180Speter null->gpt_last = pp->mediasize / pp->sectorsize - 1; 1136251881Speter 1137289180Speter null->gpt_depth = table->gpt_depth; 1138289180Speter null->gpt_opened = table->gpt_opened; 1139289180Speter null->gpt_smhead = table->gpt_smhead; 1140251881Speter null->gpt_smtail = table->gpt_smtail; 1141289180Speter 1142289180Speter while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1143289180Speter LIST_REMOVE(entry, gpe_entry); 1144289180Speter g_free(entry); 1145289180Speter } 1146289180Speter kobj_delete((kobj_t)table, M_GEOM); 1147289180Speter 1148289180Speter /* Provide feedback if so requested. */ 1149289180Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1150289180Speter sb = sbuf_new_auto(); 1151289180Speter sbuf_printf(sb, "%s destroyed\n", gp->name); 1152289180Speter sbuf_finish(sb); 1153289180Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1154289180Speter sbuf_delete(sb); 1155289180Speter } 1156289180Speter return (0); 1157289180Speter} 1158289180Speter 1159289180Speterstatic int 1160289180Speterg_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp) 1161289180Speter{ 1162289180Speter struct g_geom *gp; 1163289180Speter struct g_part_entry *entry; 1164289180Speter struct g_part_table *table; 1165289180Speter struct sbuf *sb; 1166289180Speter int error; 1167251881Speter 1168251881Speter gp = gpp->gpp_geom; 1169251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1170251881Speter g_topology_assert(); 1171251881Speter 1172251881Speter table = gp->softc; 1173251881Speter 1174286506Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1175286506Speter if (entry->gpe_deleted || entry->gpe_internal) 1176286506Speter continue; 1177286506Speter if (entry->gpe_index == gpp->gpp_index) 1178251881Speter break; 1179286506Speter } 1180251881Speter if (entry == NULL) { 1181251881Speter gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1182286506Speter return (ENOENT); 1183251881Speter } 1184286506Speter 1185286506Speter error = G_PART_MODIFY(table, entry, gpp); 1186286506Speter if (error) { 1187251881Speter gctl_error(req, "%d", error); 1188251881Speter return (error); 1189251881Speter } 1190251881Speter 1191251881Speter if (!entry->gpe_created) 1192251881Speter entry->gpe_modified = 1; 1193251881Speter 1194251881Speter /* Provide feedback if so requested. */ 1195251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1196251881Speter sb = sbuf_new_auto(); 1197251881Speter G_PART_FULLNAME(table, entry, sb, gp->name); 1198251881Speter sbuf_cat(sb, " modified\n"); 1199251881Speter sbuf_finish(sb); 1200251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1201251881Speter sbuf_delete(sb); 1202251881Speter } 1203251881Speter return (0); 1204251881Speter} 1205251881Speter 1206251881Speterstatic int 1207251881Speterg_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) 1208251881Speter{ 1209251881Speter gctl_error(req, "%d verb 'move'", ENOSYS); 1210251881Speter return (ENOSYS); 1211251881Speter} 1212251881Speter 1213251881Speterstatic int 1214251881Speterg_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) 1215251881Speter{ 1216251881Speter struct g_part_table *table; 1217251881Speter struct g_geom *gp; 1218251881Speter struct sbuf *sb; 1219251881Speter int error, recovered; 1220251881Speter 1221251881Speter gp = gpp->gpp_geom; 1222251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1223251881Speter g_topology_assert(); 1224251881Speter table = gp->softc; 1225251881Speter error = recovered = 0; 1226251881Speter 1227251881Speter if (table->gpt_corrupt) { 1228251881Speter error = G_PART_RECOVER(table); 1229251881Speter if (error == 0) 1230251881Speter error = g_part_check_integrity(table, 1231251881Speter LIST_FIRST(&gp->consumer)); 1232251881Speter if (error) { 1233251881Speter gctl_error(req, "%d recovering '%s' failed", 1234251881Speter error, gp->name); 1235251881Speter return (error); 1236251881Speter } 1237251881Speter recovered = 1; 1238251881Speter } 1239251881Speter /* Provide feedback if so requested. */ 1240251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1241251881Speter sb = sbuf_new_auto(); 1242251881Speter if (recovered) 1243251881Speter sbuf_printf(sb, "%s recovered\n", gp->name); 1244251881Speter else 1245251881Speter sbuf_printf(sb, "%s recovering is not needed\n", 1246251881Speter gp->name); 1247251881Speter sbuf_finish(sb); 1248251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1249251881Speter sbuf_delete(sb); 1250251881Speter } 1251251881Speter return (0); 1252251881Speter} 1253251881Speter 1254251881Speterstatic int 1255251881Speterg_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) 1256251881Speter{ 1257251881Speter struct g_geom *gp; 1258251881Speter struct g_provider *pp; 1259251881Speter struct g_part_entry *pe, *entry; 1260251881Speter struct g_part_table *table; 1261251881Speter struct sbuf *sb; 1262251881Speter quad_t end; 1263251881Speter int error; 1264251881Speter off_t mediasize; 1265251881Speter 1266251881Speter gp = gpp->gpp_geom; 1267251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1268251881Speter g_topology_assert(); 1269251881Speter table = gp->softc; 1270251881Speter 1271251881Speter /* check gpp_index */ 1272251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1273251881Speter if (entry->gpe_deleted || entry->gpe_internal) 1274251881Speter continue; 1275251881Speter if (entry->gpe_index == gpp->gpp_index) 1276251881Speter break; 1277251881Speter } 1278251881Speter if (entry == NULL) { 1279251881Speter gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1280251881Speter return (ENOENT); 1281251881Speter } 1282251881Speter 1283251881Speter /* check gpp_size */ 1284251881Speter end = entry->gpe_start + gpp->gpp_size - 1; 1285251881Speter if (gpp->gpp_size < 1 || end > table->gpt_last) { 1286251881Speter gctl_error(req, "%d size '%jd'", EINVAL, 1287251881Speter (intmax_t)gpp->gpp_size); 1288251881Speter return (EINVAL); 1289251881Speter } 1290251881Speter 1291251881Speter LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) { 1292251881Speter if (pe->gpe_deleted || pe->gpe_internal || pe == entry) 1293251881Speter continue; 1294251881Speter if (end >= pe->gpe_start && end <= pe->gpe_end) { 1295251881Speter gctl_error(req, "%d end '%jd'", ENOSPC, 1296251881Speter (intmax_t)end); 1297251881Speter return (ENOSPC); 1298251881Speter } 1299251881Speter if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) { 1300251881Speter gctl_error(req, "%d size '%jd'", ENOSPC, 1301251881Speter (intmax_t)gpp->gpp_size); 1302251881Speter return (ENOSPC); 1303251881Speter } 1304251881Speter } 1305251881Speter 1306251881Speter pp = entry->gpe_pp; 1307251881Speter if ((g_debugflags & 16) == 0 && 1308251881Speter (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) { 1309251881Speter if (entry->gpe_end - entry->gpe_start + 1 > gpp->gpp_size) { 1310251881Speter /* Deny shrinking of an opened partition. */ 1311251881Speter gctl_error(req, "%d", EBUSY); 1312251881Speter return (EBUSY); 1313251881Speter } 1314251881Speter } 1315251881Speter 1316251881Speter error = G_PART_RESIZE(table, entry, gpp); 1317251881Speter if (error) { 1318251881Speter gctl_error(req, "%d", error); 1319251881Speter return (error); 1320251881Speter } 1321251881Speter 1322251881Speter if (!entry->gpe_created) 1323251881Speter entry->gpe_modified = 1; 1324251881Speter 1325251881Speter /* update mediasize of changed provider */ 1326251881Speter mediasize = (entry->gpe_end - entry->gpe_start + 1) * 1327251881Speter pp->sectorsize; 1328251881Speter g_resize_provider(pp, mediasize); 1329251881Speter 1330251881Speter /* Provide feedback if so requested. */ 1331251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1332251881Speter sb = sbuf_new_auto(); 1333251881Speter G_PART_FULLNAME(table, entry, sb, gp->name); 1334251881Speter sbuf_cat(sb, " resized\n"); 1335251881Speter sbuf_finish(sb); 1336251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1337251881Speter sbuf_delete(sb); 1338251881Speter } 1339251881Speter return (0); 1340251881Speter} 1341251881Speter 1342251881Speterstatic int 1343251881Speterg_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, 1344251881Speter unsigned int set) 1345251881Speter{ 1346251881Speter struct g_geom *gp; 1347251881Speter struct g_part_entry *entry; 1348251881Speter struct g_part_table *table; 1349251881Speter struct sbuf *sb; 1350251881Speter int error; 1351251881Speter 1352251881Speter gp = gpp->gpp_geom; 1353251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1354251881Speter g_topology_assert(); 1355251881Speter 1356251881Speter table = gp->softc; 1357251881Speter 1358251881Speter if (gpp->gpp_parms & G_PART_PARM_INDEX) { 1359251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1360251881Speter if (entry->gpe_deleted || entry->gpe_internal) 1361251881Speter continue; 1362251881Speter if (entry->gpe_index == gpp->gpp_index) 1363251881Speter break; 1364251881Speter } 1365251881Speter if (entry == NULL) { 1366251881Speter gctl_error(req, "%d index '%d'", ENOENT, 1367251881Speter gpp->gpp_index); 1368251881Speter return (ENOENT); 1369251881Speter } 1370251881Speter } else 1371251881Speter entry = NULL; 1372251881Speter 1373251881Speter error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set); 1374251881Speter if (error) { 1375251881Speter gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib); 1376251881Speter return (error); 1377251881Speter } 1378251881Speter 1379251881Speter /* Provide feedback if so requested. */ 1380251881Speter if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1381251881Speter sb = sbuf_new_auto(); 1382251881Speter sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib, 1383251881Speter (set) ? "" : "un"); 1384251881Speter if (entry) 1385251881Speter G_PART_FULLNAME(table, entry, sb, gp->name); 1386251881Speter else 1387251881Speter sbuf_cat(sb, gp->name); 1388251881Speter sbuf_cat(sb, "\n"); 1389251881Speter sbuf_finish(sb); 1390251881Speter gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1391251881Speter sbuf_delete(sb); 1392251881Speter } 1393251881Speter return (0); 1394251881Speter} 1395251881Speter 1396251881Speterstatic int 1397251881Speterg_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) 1398251881Speter{ 1399251881Speter struct g_consumer *cp; 1400251881Speter struct g_provider *pp; 1401251881Speter struct g_geom *gp; 1402251881Speter struct g_part_entry *entry, *tmp; 1403251881Speter struct g_part_table *table; 1404251881Speter int error, reprobe; 1405251881Speter 1406251881Speter gp = gpp->gpp_geom; 1407251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1408251881Speter g_topology_assert(); 1409251881Speter 1410251881Speter table = gp->softc; 1411251881Speter if (!table->gpt_opened) { 1412251881Speter gctl_error(req, "%d", EPERM); 1413251881Speter return (EPERM); 1414251881Speter } 1415251881Speter 1416251881Speter cp = LIST_FIRST(&gp->consumer); 1417251881Speter LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1418251881Speter entry->gpe_modified = 0; 1419251881Speter if (entry->gpe_created) { 1420251881Speter pp = entry->gpe_pp; 1421251881Speter if (pp != NULL) { 1422251881Speter pp->private = NULL; 1423251881Speter entry->gpe_pp = NULL; 1424251881Speter g_wither_provider(pp, ENXIO); 1425251881Speter } 1426251881Speter entry->gpe_deleted = 1; 1427251881Speter } 1428251881Speter if (entry->gpe_deleted) { 1429251881Speter LIST_REMOVE(entry, gpe_entry); 1430251881Speter g_free(entry); 1431251881Speter } 1432251881Speter } 1433251881Speter 1434251881Speter g_topology_unlock(); 1435251881Speter 1436251881Speter reprobe = (table->gpt_scheme == &g_part_null_scheme || 1437251881Speter table->gpt_created) ? 1 : 0; 1438251881Speter 1439251881Speter if (reprobe) { 1440251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1441251881Speter if (entry->gpe_internal) 1442251881Speter continue; 1443251881Speter error = EBUSY; 1444251881Speter goto fail; 1445251881Speter } 1446251881Speter while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1447251881Speter LIST_REMOVE(entry, gpe_entry); 1448251881Speter g_free(entry); 1449251881Speter } 1450251881Speter error = g_part_probe(gp, cp, table->gpt_depth); 1451251881Speter if (error) { 1452251881Speter g_topology_lock(); 1453251881Speter g_access(cp, -1, -1, -1); 1454251881Speter g_part_wither(gp, error); 1455251881Speter return (0); 1456251881Speter } 1457251881Speter table = gp->softc; 1458251881Speter 1459251881Speter /* 1460251881Speter * Synthesize a disk geometry. Some partitioning schemes 1461251881Speter * depend on it and since some file systems need it even 1462251881Speter * when the partitition scheme doesn't, we do it here in 1463251881Speter * scheme-independent code. 1464251881Speter */ 1465251881Speter pp = cp->provider; 1466251881Speter g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1467251881Speter } 1468251881Speter 1469251881Speter error = G_PART_READ(table, cp); 1470251881Speter if (error) 1471251881Speter goto fail; 1472251881Speter error = g_part_check_integrity(table, cp); 1473251881Speter if (error) 1474251881Speter goto fail; 1475251881Speter 1476251881Speter g_topology_lock(); 1477251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1478251881Speter if (!entry->gpe_internal) 1479251881Speter g_part_new_provider(gp, table, entry); 1480251881Speter } 1481251881Speter 1482251881Speter table->gpt_opened = 0; 1483251881Speter g_access(cp, -1, -1, -1); 1484251881Speter return (0); 1485251881Speter 1486251881Speterfail: 1487251881Speter g_topology_lock(); 1488251881Speter gctl_error(req, "%d", error); 1489251881Speter return (error); 1490251881Speter} 1491251881Speter 1492251881Speterstatic void 1493251881Speterg_part_wither(struct g_geom *gp, int error) 1494251881Speter{ 1495251881Speter struct g_part_entry *entry; 1496251881Speter struct g_part_table *table; 1497251881Speter 1498251881Speter table = gp->softc; 1499251881Speter if (table != NULL) { 1500251881Speter G_PART_DESTROY(table, NULL); 1501251881Speter while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1502251881Speter LIST_REMOVE(entry, gpe_entry); 1503251881Speter g_free(entry); 1504251881Speter } 1505251881Speter if (gp->softc != NULL) { 1506251881Speter kobj_delete((kobj_t)gp->softc, M_GEOM); 1507251881Speter gp->softc = NULL; 1508251881Speter } 1509251881Speter } 1510251881Speter g_wither_geom(gp, error); 1511251881Speter} 1512251881Speter 1513251881Speter/* 1514251881Speter * Class methods. 1515251881Speter */ 1516251881Speter 1517251881Speterstatic void 1518251881Speterg_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 1519251881Speter{ 1520251881Speter struct g_part_parms gpp; 1521251881Speter struct g_part_table *table; 1522251881Speter struct gctl_req_arg *ap; 1523251881Speter enum g_part_ctl ctlreq; 1524251881Speter unsigned int i, mparms, oparms, parm; 1525251881Speter int auto_commit, close_on_error; 1526251881Speter int error, modifies; 1527251881Speter 1528251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1529251881Speter g_topology_assert(); 1530251881Speter 1531251881Speter ctlreq = G_PART_CTL_NONE; 1532251881Speter modifies = 1; 1533251881Speter mparms = 0; 1534251881Speter oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1535251881Speter switch (*verb) { 1536251881Speter case 'a': 1537251881Speter if (!strcmp(verb, "add")) { 1538251881Speter ctlreq = G_PART_CTL_ADD; 1539251881Speter mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1540251881Speter G_PART_PARM_START | G_PART_PARM_TYPE; 1541251881Speter oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1542251881Speter } 1543251881Speter break; 1544251881Speter case 'b': 1545251881Speter if (!strcmp(verb, "bootcode")) { 1546251881Speter ctlreq = G_PART_CTL_BOOTCODE; 1547251881Speter mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; 1548251881Speter } 1549251881Speter break; 1550251881Speter case 'c': 1551251881Speter if (!strcmp(verb, "commit")) { 1552251881Speter ctlreq = G_PART_CTL_COMMIT; 1553251881Speter mparms |= G_PART_PARM_GEOM; 1554251881Speter modifies = 0; 1555251881Speter } else if (!strcmp(verb, "create")) { 1556251881Speter ctlreq = G_PART_CTL_CREATE; 1557251881Speter mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1558251881Speter oparms |= G_PART_PARM_ENTRIES; 1559251881Speter } 1560251881Speter break; 1561251881Speter case 'd': 1562251881Speter if (!strcmp(verb, "delete")) { 1563251881Speter ctlreq = G_PART_CTL_DELETE; 1564251881Speter mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1565251881Speter } else if (!strcmp(verb, "destroy")) { 1566251881Speter ctlreq = G_PART_CTL_DESTROY; 1567251881Speter mparms |= G_PART_PARM_GEOM; 1568251881Speter oparms |= G_PART_PARM_FORCE; 1569251881Speter } 1570251881Speter break; 1571251881Speter case 'm': 1572251881Speter if (!strcmp(verb, "modify")) { 1573251881Speter ctlreq = G_PART_CTL_MODIFY; 1574251881Speter mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1575251881Speter oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1576251881Speter } else if (!strcmp(verb, "move")) { 1577251881Speter ctlreq = G_PART_CTL_MOVE; 1578251881Speter mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1579251881Speter } 1580251881Speter break; 1581251881Speter case 'r': 1582251881Speter if (!strcmp(verb, "recover")) { 1583251881Speter ctlreq = G_PART_CTL_RECOVER; 1584251881Speter mparms |= G_PART_PARM_GEOM; 1585251881Speter } else if (!strcmp(verb, "resize")) { 1586251881Speter ctlreq = G_PART_CTL_RESIZE; 1587251881Speter mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX | 1588251881Speter G_PART_PARM_SIZE; 1589251881Speter } 1590251881Speter break; 1591251881Speter case 's': 1592251881Speter if (!strcmp(verb, "set")) { 1593251881Speter ctlreq = G_PART_CTL_SET; 1594251881Speter mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM; 1595251881Speter oparms |= G_PART_PARM_INDEX; 1596251881Speter } 1597251881Speter break; 1598251881Speter case 'u': 1599251881Speter if (!strcmp(verb, "undo")) { 1600251881Speter ctlreq = G_PART_CTL_UNDO; 1601251881Speter mparms |= G_PART_PARM_GEOM; 1602251881Speter modifies = 0; 1603251881Speter } else if (!strcmp(verb, "unset")) { 1604251881Speter ctlreq = G_PART_CTL_UNSET; 1605251881Speter mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM; 1606251881Speter oparms |= G_PART_PARM_INDEX; 1607251881Speter } 1608251881Speter break; 1609251881Speter } 1610251881Speter if (ctlreq == G_PART_CTL_NONE) { 1611251881Speter gctl_error(req, "%d verb '%s'", EINVAL, verb); 1612251881Speter return; 1613251881Speter } 1614251881Speter 1615251881Speter bzero(&gpp, sizeof(gpp)); 1616251881Speter for (i = 0; i < req->narg; i++) { 1617251881Speter ap = &req->arg[i]; 1618251881Speter parm = 0; 1619251881Speter switch (ap->name[0]) { 1620251881Speter case 'a': 1621251881Speter if (!strcmp(ap->name, "arg0")) { 1622251881Speter parm = mparms & 1623251881Speter (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER); 1624251881Speter } 1625251881Speter if (!strcmp(ap->name, "attrib")) 1626251881Speter parm = G_PART_PARM_ATTRIB; 1627251881Speter break; 1628251881Speter case 'b': 1629251881Speter if (!strcmp(ap->name, "bootcode")) 1630251881Speter parm = G_PART_PARM_BOOTCODE; 1631251881Speter break; 1632251881Speter case 'c': 1633251881Speter if (!strcmp(ap->name, "class")) 1634251881Speter continue; 1635251881Speter break; 1636251881Speter case 'e': 1637251881Speter if (!strcmp(ap->name, "entries")) 1638251881Speter parm = G_PART_PARM_ENTRIES; 1639251881Speter break; 1640251881Speter case 'f': 1641251881Speter if (!strcmp(ap->name, "flags")) 1642251881Speter parm = G_PART_PARM_FLAGS; 1643251881Speter else if (!strcmp(ap->name, "force")) 1644251881Speter parm = G_PART_PARM_FORCE; 1645251881Speter break; 1646251881Speter case 'i': 1647251881Speter if (!strcmp(ap->name, "index")) 1648251881Speter parm = G_PART_PARM_INDEX; 1649251881Speter break; 1650251881Speter case 'l': 1651251881Speter if (!strcmp(ap->name, "label")) 1652251881Speter parm = G_PART_PARM_LABEL; 1653251881Speter break; 1654251881Speter case 'o': 1655251881Speter if (!strcmp(ap->name, "output")) 1656251881Speter parm = G_PART_PARM_OUTPUT; 1657251881Speter break; 1658251881Speter case 's': 1659251881Speter if (!strcmp(ap->name, "scheme")) 1660251881Speter parm = G_PART_PARM_SCHEME; 1661251881Speter else if (!strcmp(ap->name, "size")) 1662251881Speter parm = G_PART_PARM_SIZE; 1663251881Speter else if (!strcmp(ap->name, "start")) 1664251881Speter parm = G_PART_PARM_START; 1665251881Speter break; 1666251881Speter case 't': 1667251881Speter if (!strcmp(ap->name, "type")) 1668251881Speter parm = G_PART_PARM_TYPE; 1669251881Speter break; 1670251881Speter case 'v': 1671251881Speter if (!strcmp(ap->name, "verb")) 1672251881Speter continue; 1673251881Speter else if (!strcmp(ap->name, "version")) 1674251881Speter parm = G_PART_PARM_VERSION; 1675251881Speter break; 1676251881Speter } 1677251881Speter if ((parm & (mparms | oparms)) == 0) { 1678251881Speter gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1679251881Speter return; 1680251881Speter } 1681251881Speter switch (parm) { 1682251881Speter case G_PART_PARM_ATTRIB: 1683251881Speter error = g_part_parm_str(req, ap->name, 1684251881Speter &gpp.gpp_attrib); 1685251881Speter break; 1686251881Speter case G_PART_PARM_BOOTCODE: 1687251881Speter error = g_part_parm_bootcode(req, ap->name, 1688251881Speter &gpp.gpp_codeptr, &gpp.gpp_codesize); 1689251881Speter break; 1690251881Speter case G_PART_PARM_ENTRIES: 1691251881Speter error = g_part_parm_intmax(req, ap->name, 1692251881Speter &gpp.gpp_entries); 1693251881Speter break; 1694251881Speter case G_PART_PARM_FLAGS: 1695251881Speter error = g_part_parm_str(req, ap->name, &gpp.gpp_flags); 1696251881Speter break; 1697251881Speter case G_PART_PARM_FORCE: 1698251881Speter error = g_part_parm_uint32(req, ap->name, 1699251881Speter &gpp.gpp_force); 1700251881Speter break; 1701251881Speter case G_PART_PARM_GEOM: 1702251881Speter error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom); 1703251881Speter break; 1704251881Speter case G_PART_PARM_INDEX: 1705251881Speter error = g_part_parm_intmax(req, ap->name, 1706251881Speter &gpp.gpp_index); 1707251881Speter break; 1708251881Speter case G_PART_PARM_LABEL: 1709251881Speter error = g_part_parm_str(req, ap->name, &gpp.gpp_label); 1710251881Speter break; 1711251881Speter case G_PART_PARM_OUTPUT: 1712251881Speter error = 0; /* Write-only parameter */ 1713251881Speter break; 1714251881Speter case G_PART_PARM_PROVIDER: 1715251881Speter error = g_part_parm_provider(req, ap->name, 1716251881Speter &gpp.gpp_provider); 1717251881Speter break; 1718251881Speter case G_PART_PARM_SCHEME: 1719251881Speter error = g_part_parm_scheme(req, ap->name, 1720251881Speter &gpp.gpp_scheme); 1721251881Speter break; 1722251881Speter case G_PART_PARM_SIZE: 1723251881Speter error = g_part_parm_quad(req, ap->name, &gpp.gpp_size); 1724251881Speter break; 1725251881Speter case G_PART_PARM_START: 1726251881Speter error = g_part_parm_quad(req, ap->name, 1727251881Speter &gpp.gpp_start); 1728251881Speter break; 1729251881Speter case G_PART_PARM_TYPE: 1730251881Speter error = g_part_parm_str(req, ap->name, &gpp.gpp_type); 1731251881Speter break; 1732251881Speter case G_PART_PARM_VERSION: 1733251881Speter error = g_part_parm_uint32(req, ap->name, 1734251881Speter &gpp.gpp_version); 1735251881Speter break; 1736251881Speter default: 1737251881Speter error = EDOOFUS; 1738251881Speter gctl_error(req, "%d %s", error, ap->name); 1739251881Speter break; 1740251881Speter } 1741251881Speter if (error != 0) { 1742251881Speter if (error == ENOATTR) { 1743251881Speter gctl_error(req, "%d param '%s'", error, 1744251881Speter ap->name); 1745251881Speter } 1746251881Speter return; 1747251881Speter } 1748251881Speter gpp.gpp_parms |= parm; 1749251881Speter } 1750251881Speter if ((gpp.gpp_parms & mparms) != mparms) { 1751251881Speter parm = mparms - (gpp.gpp_parms & mparms); 1752251881Speter gctl_error(req, "%d param '%x'", ENOATTR, parm); 1753251881Speter return; 1754251881Speter } 1755251881Speter 1756251881Speter /* Obtain permissions if possible/necessary. */ 1757251881Speter close_on_error = 0; 1758251881Speter table = NULL; 1759251881Speter if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1760251881Speter table = gpp.gpp_geom->softc; 1761251881Speter if (table != NULL && table->gpt_corrupt && 1762251881Speter ctlreq != G_PART_CTL_DESTROY && 1763251881Speter ctlreq != G_PART_CTL_RECOVER) { 1764251881Speter gctl_error(req, "%d table '%s' is corrupt", 1765251881Speter EPERM, gpp.gpp_geom->name); 1766251881Speter return; 1767251881Speter } 1768251881Speter if (table != NULL && !table->gpt_opened) { 1769251881Speter error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1770251881Speter 1, 1, 1); 1771251881Speter if (error) { 1772251881Speter gctl_error(req, "%d geom '%s'", error, 1773251881Speter gpp.gpp_geom->name); 1774251881Speter return; 1775251881Speter } 1776251881Speter table->gpt_opened = 1; 1777251881Speter close_on_error = 1; 1778251881Speter } 1779251881Speter } 1780251881Speter 1781251881Speter /* Allow the scheme to check or modify the parameters. */ 1782251881Speter if (table != NULL) { 1783251881Speter error = G_PART_PRECHECK(table, ctlreq, &gpp); 1784251881Speter if (error) { 1785251881Speter gctl_error(req, "%d pre-check failed", error); 1786251881Speter goto out; 1787251881Speter } 1788251881Speter } else 1789251881Speter error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1790251881Speter 1791251881Speter switch (ctlreq) { 1792251881Speter case G_PART_CTL_NONE: 1793251881Speter panic("%s", __func__); 1794251881Speter case G_PART_CTL_ADD: 1795251881Speter error = g_part_ctl_add(req, &gpp); 1796251881Speter break; 1797251881Speter case G_PART_CTL_BOOTCODE: 1798251881Speter error = g_part_ctl_bootcode(req, &gpp); 1799251881Speter break; 1800251881Speter case G_PART_CTL_COMMIT: 1801251881Speter error = g_part_ctl_commit(req, &gpp); 1802251881Speter break; 1803251881Speter case G_PART_CTL_CREATE: 1804251881Speter error = g_part_ctl_create(req, &gpp); 1805251881Speter break; 1806251881Speter case G_PART_CTL_DELETE: 1807251881Speter error = g_part_ctl_delete(req, &gpp); 1808251881Speter break; 1809251881Speter case G_PART_CTL_DESTROY: 1810251881Speter error = g_part_ctl_destroy(req, &gpp); 1811251881Speter break; 1812251881Speter case G_PART_CTL_MODIFY: 1813251881Speter error = g_part_ctl_modify(req, &gpp); 1814251881Speter break; 1815251881Speter case G_PART_CTL_MOVE: 1816251881Speter error = g_part_ctl_move(req, &gpp); 1817251881Speter break; 1818251881Speter case G_PART_CTL_RECOVER: 1819251881Speter error = g_part_ctl_recover(req, &gpp); 1820251881Speter break; 1821251881Speter case G_PART_CTL_RESIZE: 1822251881Speter error = g_part_ctl_resize(req, &gpp); 1823251881Speter break; 1824251881Speter case G_PART_CTL_SET: 1825251881Speter error = g_part_ctl_setunset(req, &gpp, 1); 1826251881Speter break; 1827251881Speter case G_PART_CTL_UNDO: 1828251881Speter error = g_part_ctl_undo(req, &gpp); 1829251881Speter break; 1830251881Speter case G_PART_CTL_UNSET: 1831251881Speter error = g_part_ctl_setunset(req, &gpp, 0); 1832251881Speter break; 1833251881Speter } 1834251881Speter 1835251881Speter /* Implement automatic commit. */ 1836251881Speter if (!error) { 1837251881Speter auto_commit = (modifies && 1838251881Speter (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1839251881Speter strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1840251881Speter if (auto_commit) { 1841251881Speter KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s", 1842251881Speter __func__)); 1843251881Speter error = g_part_ctl_commit(req, &gpp); 1844251881Speter } 1845251881Speter } 1846251881Speter 1847251881Speter out: 1848251881Speter if (error && close_on_error) { 1849251881Speter g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1850251881Speter table->gpt_opened = 0; 1851251881Speter } 1852251881Speter} 1853251881Speter 1854251881Speterstatic int 1855251881Speterg_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1856251881Speter struct g_geom *gp) 1857251881Speter{ 1858251881Speter 1859251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1860251881Speter g_topology_assert(); 1861251881Speter 1862251881Speter g_part_wither(gp, EINVAL); 1863251881Speter return (0); 1864251881Speter} 1865251881Speter 1866251881Speterstatic struct g_geom * 1867251881Speterg_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1868251881Speter{ 1869251881Speter struct g_consumer *cp; 1870251881Speter struct g_geom *gp; 1871251881Speter struct g_part_entry *entry; 1872251881Speter struct g_part_table *table; 1873251881Speter struct root_hold_token *rht; 1874251881Speter int attr, depth; 1875251881Speter int error; 1876251881Speter 1877251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1878251881Speter g_topology_assert(); 1879251881Speter 1880251881Speter /* Skip providers that are already open for writing. */ 1881251881Speter if (pp->acw > 0) 1882251881Speter return (NULL); 1883251881Speter 1884251881Speter /* 1885251881Speter * Create a GEOM with consumer and hook it up to the provider. 1886251881Speter * With that we become part of the topology. Optain read access 1887251881Speter * to the provider. 1888251881Speter */ 1889251881Speter gp = g_new_geomf(mp, "%s", pp->name); 1890251881Speter cp = g_new_consumer(gp); 1891251881Speter cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 1892251881Speter error = g_attach(cp, pp); 1893251881Speter if (error == 0) 1894251881Speter error = g_access(cp, 1, 0, 0); 1895251881Speter if (error != 0) { 1896251881Speter if (cp->provider) 1897251881Speter g_detach(cp); 1898251881Speter g_destroy_consumer(cp); 1899251881Speter g_destroy_geom(gp); 1900251881Speter return (NULL); 1901251881Speter } 1902251881Speter 1903251881Speter rht = root_mount_hold(mp->name); 1904251881Speter g_topology_unlock(); 1905251881Speter 1906251881Speter /* 1907251881Speter * Short-circuit the whole probing galore when there's no 1908251881Speter * media present. 1909251881Speter */ 1910251881Speter if (pp->mediasize == 0 || pp->sectorsize == 0) { 1911251881Speter error = ENODEV; 1912251881Speter goto fail; 1913251881Speter } 1914251881Speter 1915251881Speter /* Make sure we can nest and if so, determine our depth. */ 1916251881Speter error = g_getattr("PART::isleaf", cp, &attr); 1917251881Speter if (!error && attr) { 1918251881Speter error = ENODEV; 1919251881Speter goto fail; 1920251881Speter } 1921251881Speter error = g_getattr("PART::depth", cp, &attr); 1922251881Speter depth = (!error) ? attr + 1 : 0; 1923251881Speter 1924251881Speter error = g_part_probe(gp, cp, depth); 1925251881Speter if (error) 1926251881Speter goto fail; 1927251881Speter 1928251881Speter table = gp->softc; 1929251881Speter 1930251881Speter /* 1931251881Speter * Synthesize a disk geometry. Some partitioning schemes 1932251881Speter * depend on it and since some file systems need it even 1933251881Speter * when the partitition scheme doesn't, we do it here in 1934251881Speter * scheme-independent code. 1935251881Speter */ 1936251881Speter g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1937251881Speter 1938251881Speter error = G_PART_READ(table, cp); 1939251881Speter if (error) 1940251881Speter goto fail; 1941251881Speter error = g_part_check_integrity(table, cp); 1942251881Speter if (error) 1943251881Speter goto fail; 1944251881Speter 1945251881Speter g_topology_lock(); 1946251881Speter LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1947251881Speter if (!entry->gpe_internal) 1948251881Speter g_part_new_provider(gp, table, entry); 1949251881Speter } 1950251881Speter 1951251881Speter root_mount_rel(rht); 1952251881Speter g_access(cp, -1, 0, 0); 1953251881Speter return (gp); 1954251881Speter 1955251881Speter fail: 1956251881Speter g_topology_lock(); 1957251881Speter root_mount_rel(rht); 1958251881Speter g_access(cp, -1, 0, 0); 1959251881Speter g_detach(cp); 1960251881Speter g_destroy_consumer(cp); 1961251881Speter g_destroy_geom(gp); 1962251881Speter return (NULL); 1963251881Speter} 1964251881Speter 1965251881Speter/* 1966251881Speter * Geom methods. 1967251881Speter */ 1968251881Speter 1969251881Speterstatic int 1970251881Speterg_part_access(struct g_provider *pp, int dr, int dw, int de) 1971251881Speter{ 1972251881Speter struct g_consumer *cp; 1973251881Speter 1974251881Speter G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1975251881Speter dw, de)); 1976251881Speter 1977251881Speter cp = LIST_FIRST(&pp->geom->consumer); 1978251881Speter 1979251881Speter /* We always gain write-exclusive access. */ 1980251881Speter return (g_access(cp, dr, dw, dw + de)); 1981251881Speter} 1982251881Speter 1983251881Speterstatic void 1984251881Speterg_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1985251881Speter struct g_consumer *cp, struct g_provider *pp) 1986251881Speter{ 1987251881Speter char buf[64]; 1988251881Speter struct g_part_entry *entry; 1989251881Speter struct g_part_table *table; 1990251881Speter 1991251881Speter KASSERT(sb != NULL && gp != NULL, ("%s", __func__)); 1992251881Speter table = gp->softc; 1993251881Speter 1994251881Speter if (indent == NULL) { 1995251881Speter KASSERT(cp == NULL && pp != NULL, ("%s", __func__)); 1996251881Speter entry = pp->private; 1997251881Speter if (entry == NULL) 1998251881Speter return; 1999251881Speter sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 2000251881Speter (uintmax_t)entry->gpe_offset, 2001251881Speter G_PART_TYPE(table, entry, buf, sizeof(buf))); 2002251881Speter /* 2003251881Speter * libdisk compatibility quirk - the scheme dumps the 2004251881Speter * slicer name and partition type in a way that is 2005251881Speter * compatible with libdisk. When libdisk is not used 2006251881Speter * anymore, this should go away. 2007251881Speter */ 2008251881Speter G_PART_DUMPCONF(table, entry, sb, indent); 2009251881Speter } else if (cp != NULL) { /* Consumer configuration. */ 2010251881Speter KASSERT(pp == NULL, ("%s", __func__)); 2011251881Speter /* none */ 2012251881Speter } else if (pp != NULL) { /* Provider configuration. */ 2013251881Speter entry = pp->private; 2014251881Speter if (entry == NULL) 2015251881Speter return; 2016251881Speter sbuf_printf(sb, "%s<start>%ju</start>\n", indent, 2017251881Speter (uintmax_t)entry->gpe_start); 2018251881Speter sbuf_printf(sb, "%s<end>%ju</end>\n", indent, 2019251881Speter (uintmax_t)entry->gpe_end); 2020251881Speter sbuf_printf(sb, "%s<index>%u</index>\n", indent, 2021251881Speter entry->gpe_index); 2022251881Speter sbuf_printf(sb, "%s<type>%s</type>\n", indent, 2023251881Speter G_PART_TYPE(table, entry, buf, sizeof(buf))); 2024251881Speter sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 2025251881Speter (uintmax_t)entry->gpe_offset); 2026251881Speter sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 2027251881Speter (uintmax_t)pp->mediasize); 2028251881Speter G_PART_DUMPCONF(table, entry, sb, indent); 2029251881Speter } else { /* Geom configuration. */ 2030251881Speter sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 2031251881Speter table->gpt_scheme->name); 2032251881Speter sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 2033251881Speter table->gpt_entries); 2034251881Speter sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 2035251881Speter (uintmax_t)table->gpt_first); 2036251881Speter sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 2037251881Speter (uintmax_t)table->gpt_last); 2038251881Speter sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 2039251881Speter table->gpt_sectors); 2040251881Speter sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 2041286506Speter table->gpt_heads); 2042251881Speter sbuf_printf(sb, "%s<state>%s</state>\n", indent, 2043286506Speter table->gpt_corrupt ? "CORRUPT": "OK"); 2044286506Speter sbuf_printf(sb, "%s<modified>%s</modified>\n", indent, 2045286506Speter table->gpt_opened ? "true": "false"); 2046286506Speter G_PART_DUMPCONF(table, NULL, sb, indent); 2047286506Speter } 2048286506Speter} 2049286506Speter 2050251881Speterstatic void 2051251881Speterg_part_resize(struct g_consumer *cp) 2052251881Speter{ 2053251881Speter struct g_part_table *table; 2054251881Speter 2055251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 2056251881Speter g_topology_assert(); 2057251881Speter 2058251881Speter table = cp->geom->softc; 2059251881Speter if (table->gpt_opened == 0) { 2060251881Speter if (g_access(cp, 1, 1, 1) != 0) 2061251881Speter return; 2062251881Speter table->gpt_opened = 1; 2063251881Speter } 2064251881Speter if (G_PART_RESIZE(table, NULL, NULL) == 0) 2065251881Speter printf("GEOM_PART: %s was automatically resized\n", 2066251881Speter cp->geom->name); 2067251881Speter if (g_part_check_integrity(table, cp) != 0) { 2068251881Speter g_access(cp, -1, -1, -1); 2069251881Speter table->gpt_opened = 0; 2070251881Speter g_part_wither(table->gpt_gp, ENXIO); 2071251881Speter } 2072251881Speter} 2073251881Speter 2074251881Speterstatic void 2075251881Speterg_part_orphan(struct g_consumer *cp) 2076251881Speter{ 2077251881Speter struct g_provider *pp; 2078251881Speter struct g_part_table *table; 2079251881Speter 2080251881Speter pp = cp->provider; 2081251881Speter KASSERT(pp != NULL, ("%s", __func__)); 2082251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 2083251881Speter g_topology_assert(); 2084251881Speter 2085251881Speter KASSERT(pp->error != 0, ("%s", __func__)); 2086251881Speter table = cp->geom->softc; 2087251881Speter if (table != NULL && table->gpt_opened) 2088251881Speter g_access(cp, -1, -1, -1); 2089251881Speter g_part_wither(cp->geom, pp->error); 2090251881Speter} 2091251881Speter 2092251881Speterstatic void 2093251881Speterg_part_spoiled(struct g_consumer *cp) 2094251881Speter{ 2095251881Speter 2096251881Speter G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 2097251881Speter g_topology_assert(); 2098251881Speter 2099251881Speter cp->flags |= G_CF_ORPHAN; 2100251881Speter g_part_wither(cp->geom, ENXIO); 2101251881Speter} 2102251881Speter 2103286506Speterstatic void 2104251881Speterg_part_start(struct bio *bp) 2105251881Speter{ 2106251881Speter struct bio *bp2; 2107251881Speter struct g_consumer *cp; 2108251881Speter struct g_geom *gp; 2109251881Speter struct g_part_entry *entry; 2110251881Speter struct g_part_table *table; 2111251881Speter struct g_kerneldump *gkd; 2112251881Speter struct g_provider *pp; 2113251881Speter char buf[64]; 2114251881Speter 2115251881Speter pp = bp->bio_to; 2116251881Speter gp = pp->geom; 2117251881Speter table = gp->softc; 2118251881Speter cp = LIST_FIRST(&gp->consumer); 2119251881Speter 2120251881Speter G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 2121251881Speter pp->name)); 2122251881Speter 2123251881Speter entry = pp->private; 2124251881Speter if (entry == NULL) { 2125251881Speter g_io_deliver(bp, ENXIO); 2126251881Speter return; 2127251881Speter } 2128251881Speter 2129251881Speter switch(bp->bio_cmd) { 2130251881Speter case BIO_DELETE: 2131251881Speter case BIO_READ: 2132251881Speter case BIO_WRITE: 2133251881Speter if (bp->bio_offset >= pp->mediasize) { 2134251881Speter g_io_deliver(bp, EIO); 2135251881Speter return; 2136251881Speter } 2137251881Speter bp2 = g_clone_bio(bp); 2138251881Speter if (bp2 == NULL) { 2139251881Speter g_io_deliver(bp, ENOMEM); 2140251881Speter return; 2141251881Speter } 2142251881Speter if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 2143251881Speter bp2->bio_length = pp->mediasize - bp2->bio_offset; 2144251881Speter bp2->bio_done = g_std_done; 2145251881Speter bp2->bio_offset += entry->gpe_offset; 2146251881Speter g_io_request(bp2, cp); 2147251881Speter return; 2148251881Speter case BIO_FLUSH: 2149251881Speter break; 2150251881Speter case BIO_GETATTR: 2151251881Speter if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 2152251881Speter return; 2153251881Speter if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 2154251881Speter return; 2155251881Speter if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 2156251881Speter return; 2157251881Speter if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 2158251881Speter return; 2159251881Speter if (g_handleattr_str(bp, "PART::scheme", 2160251881Speter table->gpt_scheme->name)) 2161251881Speter return; 2162251881Speter if (g_handleattr_str(bp, "PART::type", 2163251881Speter G_PART_TYPE(table, entry, buf, sizeof(buf)))) 2164251881Speter return; 2165251881Speter if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 2166251881Speter /* 2167251881Speter * Check that the partition is suitable for kernel 2168251881Speter * dumps. Typically only swap partitions should be 2169251881Speter * used. If the request comes from the nested scheme 2170251881Speter * we allow dumping there as well. 2171251881Speter */ 2172251881Speter if ((bp->bio_from == NULL || 2173251881Speter bp->bio_from->geom->class != &g_part_class) && 2174251881Speter G_PART_DUMPTO(table, entry) == 0) { 2175251881Speter g_io_deliver(bp, ENODEV); 2176251881Speter printf("GEOM_PART: Partition '%s' not suitable" 2177251881Speter " for kernel dumps (wrong type?)\n", 2178251881Speter pp->name); 2179251881Speter return; 2180251881Speter } 2181251881Speter gkd = (struct g_kerneldump *)bp->bio_data; 2182251881Speter if (gkd->offset >= pp->mediasize) { 2183251881Speter g_io_deliver(bp, EIO); 2184251881Speter return; 2185251881Speter } 2186251881Speter if (gkd->offset + gkd->length > pp->mediasize) 2187251881Speter gkd->length = pp->mediasize - gkd->offset; 2188251881Speter gkd->offset += entry->gpe_offset; 2189251881Speter } 2190251881Speter break; 2191251881Speter default: 2192251881Speter g_io_deliver(bp, EOPNOTSUPP); 2193251881Speter return; 2194251881Speter } 2195251881Speter 2196251881Speter bp2 = g_clone_bio(bp); 2197251881Speter if (bp2 == NULL) { 2198251881Speter g_io_deliver(bp, ENOMEM); 2199289180Speter return; 2200251881Speter } 2201251881Speter bp2->bio_done = g_std_done; 2202251881Speter g_io_request(bp2, cp); 2203251881Speter} 2204251881Speter 2205251881Speterstatic void 2206251881Speterg_part_init(struct g_class *mp) 2207251881Speter{ 2208251881Speter 2209251881Speter TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list); 2210251881Speter} 2211251881Speter 2212251881Speterstatic void 2213251881Speterg_part_fini(struct g_class *mp) 2214251881Speter{ 2215251881Speter 2216251881Speter TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list); 2217251881Speter} 2218251881Speter 2219251881Speterstatic void 2220251881Speterg_part_unload_event(void *arg, int flag) 2221251881Speter{ 2222251881Speter struct g_consumer *cp; 2223251881Speter struct g_geom *gp; 2224289180Speter struct g_provider *pp; 2225251881Speter struct g_part_scheme *scheme; 2226251881Speter struct g_part_table *table; 2227251881Speter uintptr_t *xchg; 2228251881Speter int acc, error; 2229251881Speter 2230251881Speter if (flag == EV_CANCEL) 2231251881Speter return; 2232251881Speter 2233251881Speter xchg = arg; 2234251881Speter error = 0; 2235251881Speter scheme = (void *)(*xchg); 2236251881Speter 2237251881Speter g_topology_assert(); 2238251881Speter 2239251881Speter LIST_FOREACH(gp, &g_part_class.geom, geom) { 2240251881Speter table = gp->softc; 2241251881Speter if (table->gpt_scheme != scheme) 2242251881Speter continue; 2243251881Speter 2244251881Speter acc = 0; 2245251881Speter LIST_FOREACH(pp, &gp->provider, provider) 2246251881Speter acc += pp->acr + pp->acw + pp->ace; 2247251881Speter LIST_FOREACH(cp, &gp->consumer, consumer) 2248251881Speter acc += cp->acr + cp->acw + cp->ace; 2249251881Speter 2250251881Speter if (!acc) 2251251881Speter g_part_wither(gp, ENOSYS); 2252251881Speter else 2253251881Speter error = EBUSY; 2254251881Speter } 2255251881Speter 2256251881Speter if (!error) 2257251881Speter TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 2258251881Speter 2259251881Speter *xchg = error; 2260251881Speter} 2261251881Speter 2262251881Speterint 2263251881Speterg_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) 2264251881Speter{ 2265251881Speter struct g_part_scheme *iter; 2266251881Speter uintptr_t arg; 2267289180Speter int error; 2268251881Speter 2269251881Speter error = 0; 2270251881Speter switch (type) { 2271251881Speter case MOD_LOAD: 2272251881Speter TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { 2273251881Speter if (scheme == iter) { 2274251881Speter printf("GEOM_PART: scheme %s is already " 2275251881Speter "registered!\n", scheme->name); 2276251881Speter break; 2277251881Speter } 2278251881Speter } 2279251881Speter if (iter == NULL) { 2280251881Speter TAILQ_INSERT_TAIL(&g_part_schemes, scheme, 2281251881Speter scheme_list); 2282251881Speter g_retaste(&g_part_class); 2283286506Speter } 2284286506Speter break; 2285286506Speter case MOD_UNLOAD: 2286286506Speter arg = (uintptr_t)scheme; 2287286506Speter error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, 2288286506Speter NULL); 2289286506Speter if (error == 0) 2290286506Speter error = arg; 2291286506Speter break; 2292286506Speter default: 2293286506Speter error = EOPNOTSUPP; 2294286506Speter break; 2295251881Speter } 2296251881Speter 2297251881Speter return (error); 2298286506Speter} 2299289180Speter