g_part.c revision 218014
1159720Syar/*- 2116014Sgrog * Copyright (c) 2002, 2005-2009 Marcel Moolenaar 3116014Sgrog * All rights reserved. 4116014Sgrog * 5116014Sgrog * Redistribution and use in source and binary forms, with or without 6116014Sgrog * modification, are permitted provided that the following conditions 7116014Sgrog * are met: 8116014Sgrog * 9116014Sgrog * 1. Redistributions of source code must retain the above copyright 10116014Sgrog * notice, this list of conditions and the following disclaimer. 11116014Sgrog * 2. Redistributions in binary form must reproduce the above copyright 12116014Sgrog * notice, this list of conditions and the following disclaimer in the 13116014Sgrog * documentation and/or other materials provided with the distribution. 14116014Sgrog * 15116014Sgrog * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116014Sgrog * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116014Sgrog * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116014Sgrog * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116014Sgrog * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116014Sgrog * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116014Sgrog * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116014Sgrog * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116014Sgrog * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116014Sgrog * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116014Sgrog */ 26116009Sgrog 27116009Sgrog#include <sys/cdefs.h> 28159720Syar__FBSDID("$FreeBSD: head/sys/geom/part/g_part.c 218014 2011-01-28 11:13:01Z ae $"); 29159720Syar 30159720Syar#include <sys/param.h> 31159720Syar#include <sys/bio.h> 32159720Syar#include <sys/diskmbr.h> 33159720Syar#include <sys/endian.h> 34116009Sgrog#include <sys/kernel.h> 35159720Syar#include <sys/kobj.h> 36116009Sgrog#include <sys/limits.h> 37159720Syar#include <sys/lock.h> 38159720Syar#include <sys/malloc.h> 39159720Syar#include <sys/mutex.h> 40116009Sgrog#include <sys/queue.h> 41116009Sgrog#include <sys/sbuf.h> 42116009Sgrog#include <sys/systm.h> 43116009Sgrog#include <sys/uuid.h> 44116009Sgrog#include <geom/geom.h> 45159720Syar#include <geom/geom_ctl.h> 46116009Sgrog#include <geom/geom_int.h> 47159720Syar#include <geom/part/g_part.h> 48159720Syar 49159720Syar#include "g_part_if.h" 50159720Syar 51159720Syar#ifndef _PATH_DEV 52159720Syar#define _PATH_DEV "/dev/" 53159720Syar#endif 54159720Syar 55159720Syarstatic kobj_method_t g_part_null_methods[] = { 56159720Syar { 0, 0 } 57159720Syar}; 58159720Syar 59159720Syarstatic struct g_part_scheme g_part_null_scheme = { 60159720Syar "(none)", 61159720Syar g_part_null_methods, 62159720Syar sizeof(struct g_part_table), 63159720Syar}; 64159720Syar 65159720SyarTAILQ_HEAD(, g_part_scheme) g_part_schemes = 66159720Syar TAILQ_HEAD_INITIALIZER(g_part_schemes); 67159720Syar 68159720Syarstruct g_part_alias_list { 69159720Syar const char *lexeme; 70159720Syar enum g_part_alias alias; 71159720Syar} g_part_alias_list[G_PART_ALIAS_COUNT] = { 72159720Syar { "apple-boot", G_PART_ALIAS_APPLE_BOOT }, 73159720Syar { "apple-hfs", G_PART_ALIAS_APPLE_HFS }, 74159720Syar { "apple-label", G_PART_ALIAS_APPLE_LABEL }, 75159720Syar { "apple-raid", G_PART_ALIAS_APPLE_RAID }, 76159720Syar { "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE }, 77159720Syar { "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY }, 78159720Syar { "apple-ufs", G_PART_ALIAS_APPLE_UFS }, 79159720Syar { "bios-boot", G_PART_ALIAS_BIOS_BOOT }, 80159720Syar { "ebr", G_PART_ALIAS_EBR }, 81159720Syar { "efi", G_PART_ALIAS_EFI }, 82159720Syar { "fat32", G_PART_ALIAS_MS_FAT32 }, 83159720Syar { "freebsd", G_PART_ALIAS_FREEBSD }, 84159720Syar { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT }, 85159720Syar { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP }, 86159720Syar { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS }, 87159720Syar { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM }, 88159720Syar { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS }, 89159720Syar { "linux-data", G_PART_ALIAS_LINUX_DATA }, 90159720Syar { "linux-lvm", G_PART_ALIAS_LINUX_LVM }, 91159720Syar { "linux-raid", G_PART_ALIAS_LINUX_RAID }, 92159720Syar { "linux-swap", G_PART_ALIAS_LINUX_SWAP }, 93159720Syar { "mbr", G_PART_ALIAS_MBR }, 94159720Syar { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA }, 95159720Syar { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA }, 96159720Syar { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA }, 97159720Syar { "ms-reserved", G_PART_ALIAS_MS_RESERVED }, 98159720Syar { "ntfs", G_PART_ALIAS_MS_NTFS }, 99116009Sgrog { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD }, 100116009Sgrog { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD }, 101116009Sgrog { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS }, 102116009Sgrog { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS }, 103116009Sgrog { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID }, 104116009Sgrog { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP }, 105116009Sgrog}; 106159720Syar 107116009Sgrog/* 108116009Sgrog * The GEOM partitioning class. 109116009Sgrog */ 110116009Sgrogstatic g_ctl_req_t g_part_ctlreq; 111116009Sgrogstatic g_ctl_destroy_geom_t g_part_destroy_geom; 112116009Sgrogstatic g_fini_t g_part_fini; 113116009Sgrogstatic g_init_t g_part_init; 114116009Sgrogstatic g_taste_t g_part_taste; 115116009Sgrog 116116009Sgrogstatic g_access_t g_part_access; 117116009Sgrogstatic g_dumpconf_t g_part_dumpconf; 118116009Sgrogstatic g_orphan_t g_part_orphan; 119116009Sgrogstatic g_spoiled_t g_part_spoiled; 120116009Sgrogstatic g_start_t g_part_start; 121116009Sgrog 122116009Sgrogstatic struct g_class g_part_class = { 123116009Sgrog .name = "PART", 124116009Sgrog .version = G_VERSION, 125116009Sgrog /* Class methods. */ 126116009Sgrog .ctlreq = g_part_ctlreq, 127116009Sgrog .destroy_geom = g_part_destroy_geom, 128116009Sgrog .fini = g_part_fini, 129116009Sgrog .init = g_part_init, 130116009Sgrog .taste = g_part_taste, 131116009Sgrog /* Geom methods. */ 132116009Sgrog .access = g_part_access, 133116009Sgrog .dumpconf = g_part_dumpconf, 134116009Sgrog .orphan = g_part_orphan, 135116009Sgrog .spoiled = g_part_spoiled, 136116009Sgrog .start = g_part_start, 137116009Sgrog}; 138116009Sgrog 139116009SgrogDECLARE_GEOM_CLASS(g_part_class, g_part); 140116009Sgrog 141116009Sgrog/* 142116009Sgrog * Support functions. 143116009Sgrog */ 144116009Sgrog 145116009Sgrogstatic void g_part_wither(struct g_geom *, int); 146159720Syar 147159720Syarconst char * 148122033Sgreeng_part_alias_name(enum g_part_alias alias) 149159720Syar{ 150159720Syar int i; 151159720Syar 152159720Syar for (i = 0; i < G_PART_ALIAS_COUNT; i++) { 153159720Syar if (g_part_alias_list[i].alias != alias) 154159720Syar continue; 155159720Syar return (g_part_alias_list[i].lexeme); 156159720Syar } 157159720Syar 158122033Sgreen return (NULL); 159159720Syar} 160159720Syar 161159720Syarvoid 162159720Syarg_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs, 163159720Syar u_int *bestheads) 164159720Syar{ 165159720Syar static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 }; 166159720Syar off_t chs, cylinders; 167159720Syar u_int heads; 168159720Syar int idx; 169159720Syar 170159720Syar *bestchs = 0; 171159720Syar *bestheads = 0; 172159720Syar for (idx = 0; candidate_heads[idx] != 0; idx++) { 173159720Syar heads = candidate_heads[idx]; 174159720Syar cylinders = blocks / heads / sectors; 175159720Syar if (cylinders < heads || cylinders < sectors) 176159720Syar break; 177122033Sgreen if (cylinders > 1023) 178159720Syar continue; 179159720Syar chs = cylinders * heads * sectors; 180159720Syar if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) { 181159720Syar *bestchs = chs; 182159720Syar *bestheads = heads; 183159720Syar } 184159720Syar } 185122033Sgreen} 186159720Syar 187159720Syarstatic void 188159720Syarg_part_geometry(struct g_part_table *table, struct g_consumer *cp, 189165372Syar off_t blocks) 190159720Syar{ 191159720Syar static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 }; 192159720Syar off_t chs, bestchs; 193159720Syar u_int heads, sectors; 194159720Syar int idx; 195159720Syar 196159720Syar if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || sectors == 0 || 197159720Syar g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) { 198159720Syar table->gpt_fixgeom = 0; 199159720Syar table->gpt_heads = 0; 200159720Syar table->gpt_sectors = 0; 201159720Syar bestchs = 0; 202159720Syar for (idx = 0; candidate_sectors[idx] != 0; idx++) { 203165372Syar sectors = candidate_sectors[idx]; 204159720Syar g_part_geometry_heads(blocks, sectors, &chs, &heads); 205159720Syar if (chs == 0) 206159720Syar continue; 207159720Syar /* 208159720Syar * Prefer a geometry with sectors > 1, but only if 209159720Syar * it doesn't bump down the numbver of heads to 1. 210159720Syar */ 211159720Syar if (chs > bestchs || (chs == bestchs && heads > 1 && 212159720Syar table->gpt_sectors == 1)) { 213159720Syar bestchs = chs; 214159720Syar table->gpt_heads = heads; 215159720Syar table->gpt_sectors = sectors; 216159720Syar } 217159720Syar } 218159720Syar /* 219159720Syar * If we didn't find a geometry at all, then the disk is 220159720Syar * too big. This means we can use the maximum number of 221159720Syar * heads and sectors. 222159720Syar */ 223159720Syar if (bestchs == 0) { 224159720Syar table->gpt_heads = 255; 225159720Syar table->gpt_sectors = 63; 226159720Syar } 227159720Syar } else { 228159720Syar table->gpt_fixgeom = 1; 229159720Syar table->gpt_heads = heads; 230159720Syar table->gpt_sectors = sectors; 231159720Syar } 232159720Syar} 233165372Syar 234159720Syarstruct g_part_entry * 235159720Syarg_part_new_entry(struct g_part_table *table, int index, quad_t start, 236122033Sgreen quad_t end) 237159720Syar{ 238165372Syar struct g_part_entry *entry, *last; 239159720Syar 240159720Syar last = NULL; 241122033Sgreen LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 242122033Sgreen if (entry->gpe_index == index) 243116017Sjmallett break; 244116017Sjmallett if (entry->gpe_index > index) { 245116009Sgrog entry = NULL; 246116009Sgrog break; 247116009Sgrog } 248162796Sru last = entry; 249159720Syar } 250159720Syar if (entry == NULL) { 251159720Syar entry = g_malloc(table->gpt_scheme->gps_entrysz, 252159720Syar M_WAITOK | M_ZERO); 253116016Sjmallett entry->gpe_index = index; 254159720Syar if (last == NULL) 255159720Syar LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 256159720Syar else 257122033Sgreen LIST_INSERT_AFTER(last, entry, gpe_entry); 258159720Syar } else 259159720Syar entry->gpe_offset = 0; 260159720Syar entry->gpe_start = start; 261159776Syar entry->gpe_end = end; 262159720Syar return (entry); 263116009Sgrog} 264116009Sgrog 265165372Syarstatic void 266159720Syarg_part_new_provider(struct g_geom *gp, struct g_part_table *table, 267159720Syar struct g_part_entry *entry) 268159720Syar{ 269159720Syar struct g_consumer *cp; 270159720Syar struct g_provider *pp; 271159720Syar struct sbuf *sb; 272159720Syar off_t offset; 273159720Syar 274159720Syar cp = LIST_FIRST(&gp->consumer); 275159720Syar pp = cp->provider; 276116009Sgrog 277116009Sgrog offset = entry->gpe_start * pp->sectorsize; 278116009Sgrog if (entry->gpe_offset < offset) 279159720Syar entry->gpe_offset = offset; 280159720Syar 281165372Syar if (entry->gpe_pp == NULL) { 282165372Syar sb = sbuf_new_auto(); 283165372Syar G_PART_FULLNAME(table, entry, sb, gp->name); 284159720Syar sbuf_finish(sb); 285159720Syar entry->gpe_pp = g_new_providerf(gp, "%s", sbuf_data(sb)); 286159720Syar sbuf_delete(sb); 287159720Syar entry->gpe_pp->private = entry; /* Close the circle. */ 288159720Syar } 289159720Syar entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */ 290159720Syar entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 291159720Syar pp->sectorsize; 292116009Sgrog entry->gpe_pp->mediasize -= entry->gpe_offset - offset; 293159720Syar entry->gpe_pp->sectorsize = pp->sectorsize; 294159720Syar entry->gpe_pp->flags = pp->flags & G_PF_CANDELETE; 295159720Syar entry->gpe_pp->stripesize = pp->stripesize; 296159720Syar entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset; 297159720Syar if (pp->stripesize > 0) 298116009Sgrog entry->gpe_pp->stripeoffset %= pp->stripesize; 299159720Syar g_error_provider(entry->gpe_pp, 0); 300116009Sgrog} 301159720Syar 302159720Syarstatic struct g_geom* 303159720Syarg_part_find_geom(const char *name) 304159720Syar{ 305159720Syar struct g_geom *gp; 306159720Syar LIST_FOREACH(gp, &g_part_class.geom, geom) { 307159720Syar if (!strcmp(name, gp->name)) 308159720Syar break; 309159720Syar } 310159720Syar return (gp); 311159720Syar} 312159720Syar 313159720Syarstatic int 314159720Syarg_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v) 315159720Syar{ 316159720Syar struct g_geom *gp; 317159720Syar const char *gname; 318159720Syar 319159720Syar gname = gctl_get_asciiparam(req, name); 320159720Syar if (gname == NULL) 321159720Syar return (ENOATTR); 322159720Syar if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 323159720Syar gname += sizeof(_PATH_DEV) - 1; 324159720Syar gp = g_part_find_geom(gname); 325159720Syar if (gp == NULL) { 326159720Syar gctl_error(req, "%d %s '%s'", EINVAL, name, gname); 327159720Syar return (EINVAL); 328159720Syar } 329159720Syar *v = gp; 330159720Syar return (0); 331159720Syar} 332159720Syar 333159720Syarstatic int 334159720Syarg_part_parm_provider(struct gctl_req *req, const char *name, 335159720Syar struct g_provider **v) 336159720Syar{ 337159720Syar struct g_provider *pp; 338159720Syar const char *pname; 339159720Syar 340159720Syar pname = gctl_get_asciiparam(req, name); 341116009Sgrog if (pname == NULL) 342116009Sgrog return (ENOATTR); 343159720Syar if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 344159720Syar pname += sizeof(_PATH_DEV) - 1; 345159720Syar pp = g_provider_by_name(pname); 346159720Syar if (pp == NULL) { 347159720Syar gctl_error(req, "%d %s '%s'", EINVAL, name, pname); 348159720Syar return (EINVAL); 349159720Syar } 350116009Sgrog *v = pp; 351159720Syar return (0); 352159720Syar} 353159720Syar 354116009Sgrogstatic int 355159720Syarg_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v) 356159720Syar{ 357116009Sgrog const char *p; 358159720Syar char *x; 359159720Syar quad_t q; 360159720Syar 361159720Syar p = gctl_get_asciiparam(req, name); 362159720Syar if (p == NULL) 363150410Sgrog return (ENOATTR); 364159720Syar q = strtoq(p, &x, 0); 365159720Syar if (*x != '\0' || q < 0) { 366159720Syar gctl_error(req, "%d %s '%s'", EINVAL, name, p); 367159720Syar return (EINVAL); 368159720Syar } 369159720Syar *v = q; 370159720Syar return (0); 371159720Syar} 372159720Syar 373159720Syarstatic int 374116009Sgrogg_part_parm_scheme(struct gctl_req *req, const char *name, 375159720Syar struct g_part_scheme **v) 376159720Syar{ 377159720Syar struct g_part_scheme *s; 378159720Syar const char *p; 379159720Syar 380159720Syar p = gctl_get_asciiparam(req, name); 381165372Syar if (p == NULL) 382165372Syar return (ENOATTR); 383165372Syar TAILQ_FOREACH(s, &g_part_schemes, scheme_list) { 384165372Syar if (s == &g_part_null_scheme) 385165372Syar continue; 386165372Syar if (!strcasecmp(s->name, p)) 387165372Syar break; 388165372Syar } 389165372Syar if (s == NULL) { 390165372Syar gctl_error(req, "%d %s '%s'", EINVAL, name, p); 391159720Syar return (EINVAL); 392159720Syar } 393165372Syar *v = s; 394165372Syar return (0); 395165372Syar} 396165372Syar 397165372Syarstatic int 398165372Syarg_part_parm_str(struct gctl_req *req, const char *name, const char **v) 399165372Syar{ 400165372Syar const char *p; 401165372Syar 402122033Sgreen p = gctl_get_asciiparam(req, name); 403165372Syar if (p == NULL) 404165372Syar return (ENOATTR); 405165372Syar /* An empty label is always valid. */ 406165372Syar if (strcmp(name, "label") != 0 && p[0] == '\0') { 407165372Syar gctl_error(req, "%d %s '%s'", EINVAL, name, p); 408165372Syar return (EINVAL); 409165372Syar } 410165372Syar *v = p; 411165372Syar return (0); 412165372Syar} 413165372Syar 414165372Syarstatic int 415165372Syarg_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v) 416165372Syar{ 417116009Sgrog const intmax_t *p; 418165372Syar int size; 419165372Syar 420165372Syar p = gctl_get_param(req, name, &size); 421116009Sgrog if (p == NULL) 422159720Syar return (ENOATTR); 423165372Syar if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) { 424159720Syar gctl_error(req, "%d %s '%jd'", EINVAL, name, *p); 425165372Syar return (EINVAL); 426159720Syar } 427116009Sgrog *v = (u_int)*p; 428 return (0); 429} 430 431static int 432g_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v) 433{ 434 const uint32_t *p; 435 int size; 436 437 p = gctl_get_param(req, name, &size); 438 if (p == NULL) 439 return (ENOATTR); 440 if (size != sizeof(*p) || *p > INT_MAX) { 441 gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p); 442 return (EINVAL); 443 } 444 *v = (u_int)*p; 445 return (0); 446} 447 448static int 449g_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v, 450 unsigned int *s) 451{ 452 const void *p; 453 int size; 454 455 p = gctl_get_param(req, name, &size); 456 if (p == NULL) 457 return (ENOATTR); 458 *v = p; 459 *s = size; 460 return (0); 461} 462 463static int 464g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth) 465{ 466 struct g_part_scheme *iter, *scheme; 467 struct g_part_table *table; 468 int pri, probe; 469 470 table = gp->softc; 471 scheme = (table != NULL) ? table->gpt_scheme : NULL; 472 pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN; 473 if (pri == 0) 474 goto done; 475 if (pri > 0) { /* error */ 476 scheme = NULL; 477 pri = INT_MIN; 478 } 479 480 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { 481 if (iter == &g_part_null_scheme) 482 continue; 483 table = (void *)kobj_create((kobj_class_t)iter, M_GEOM, 484 M_WAITOK); 485 table->gpt_gp = gp; 486 table->gpt_scheme = iter; 487 table->gpt_depth = depth; 488 probe = G_PART_PROBE(table, cp); 489 if (probe <= 0 && probe > pri) { 490 pri = probe; 491 scheme = iter; 492 if (gp->softc != NULL) 493 kobj_delete((kobj_t)gp->softc, M_GEOM); 494 gp->softc = table; 495 if (pri == 0) 496 goto done; 497 } else 498 kobj_delete((kobj_t)table, M_GEOM); 499 } 500 501done: 502 return ((scheme == NULL) ? ENXIO : 0); 503} 504 505/* 506 * Control request functions. 507 */ 508 509static int 510g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) 511{ 512 struct g_geom *gp; 513 struct g_provider *pp; 514 struct g_part_entry *delent, *last, *entry; 515 struct g_part_table *table; 516 struct sbuf *sb; 517 quad_t end; 518 unsigned int index; 519 int error; 520 521 gp = gpp->gpp_geom; 522 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 523 g_topology_assert(); 524 525 pp = LIST_FIRST(&gp->consumer)->provider; 526 table = gp->softc; 527 end = gpp->gpp_start + gpp->gpp_size - 1; 528 529 if (gpp->gpp_start < table->gpt_first || 530 gpp->gpp_start > table->gpt_last) { 531 gctl_error(req, "%d start '%jd'", EINVAL, 532 (intmax_t)gpp->gpp_start); 533 return (EINVAL); 534 } 535 if (end < gpp->gpp_start || end > table->gpt_last) { 536 gctl_error(req, "%d size '%jd'", EINVAL, 537 (intmax_t)gpp->gpp_size); 538 return (EINVAL); 539 } 540 if (gpp->gpp_index > table->gpt_entries) { 541 gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index); 542 return (EINVAL); 543 } 544 545 delent = last = NULL; 546 index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1; 547 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 548 if (entry->gpe_deleted) { 549 if (entry->gpe_index == index) 550 delent = entry; 551 continue; 552 } 553 if (entry->gpe_index == index) 554 index = entry->gpe_index + 1; 555 if (entry->gpe_index < index) 556 last = entry; 557 if (entry->gpe_internal) 558 continue; 559 if (gpp->gpp_start >= entry->gpe_start && 560 gpp->gpp_start <= entry->gpe_end) { 561 gctl_error(req, "%d start '%jd'", ENOSPC, 562 (intmax_t)gpp->gpp_start); 563 return (ENOSPC); 564 } 565 if (end >= entry->gpe_start && end <= entry->gpe_end) { 566 gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end); 567 return (ENOSPC); 568 } 569 if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) { 570 gctl_error(req, "%d size '%jd'", ENOSPC, 571 (intmax_t)gpp->gpp_size); 572 return (ENOSPC); 573 } 574 } 575 if (gpp->gpp_index > 0 && index != gpp->gpp_index) { 576 gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index); 577 return (EEXIST); 578 } 579 if (index > table->gpt_entries) { 580 gctl_error(req, "%d index '%d'", ENOSPC, index); 581 return (ENOSPC); 582 } 583 584 entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz, 585 M_WAITOK | M_ZERO) : delent; 586 entry->gpe_index = index; 587 entry->gpe_start = gpp->gpp_start; 588 entry->gpe_end = end; 589 error = G_PART_ADD(table, entry, gpp); 590 if (error) { 591 gctl_error(req, "%d", error); 592 if (delent == NULL) 593 g_free(entry); 594 return (error); 595 } 596 if (delent == NULL) { 597 if (last == NULL) 598 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 599 else 600 LIST_INSERT_AFTER(last, entry, gpe_entry); 601 entry->gpe_created = 1; 602 } else { 603 entry->gpe_deleted = 0; 604 entry->gpe_modified = 1; 605 } 606 g_part_new_provider(gp, table, entry); 607 608 /* Provide feedback if so requested. */ 609 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 610 sb = sbuf_new_auto(); 611 G_PART_FULLNAME(table, entry, sb, gp->name); 612 sbuf_cat(sb, " added\n"); 613 sbuf_finish(sb); 614 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 615 sbuf_delete(sb); 616 } 617 return (0); 618} 619 620static int 621g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp) 622{ 623 struct g_geom *gp; 624 struct g_part_table *table; 625 struct sbuf *sb; 626 int error, sz; 627 628 gp = gpp->gpp_geom; 629 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 630 g_topology_assert(); 631 632 table = gp->softc; 633 sz = table->gpt_scheme->gps_bootcodesz; 634 if (sz == 0) { 635 error = ENODEV; 636 goto fail; 637 } 638 if (gpp->gpp_codesize > sz) { 639 error = EFBIG; 640 goto fail; 641 } 642 643 error = G_PART_BOOTCODE(table, gpp); 644 if (error) 645 goto fail; 646 647 /* Provide feedback if so requested. */ 648 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 649 sb = sbuf_new_auto(); 650 sbuf_printf(sb, "bootcode written to %s\n", gp->name); 651 sbuf_finish(sb); 652 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 653 sbuf_delete(sb); 654 } 655 return (0); 656 657 fail: 658 gctl_error(req, "%d", error); 659 return (error); 660} 661 662static int 663g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp) 664{ 665 struct g_consumer *cp; 666 struct g_geom *gp; 667 struct g_provider *pp; 668 struct g_part_entry *entry, *tmp; 669 struct g_part_table *table; 670 char *buf; 671 int error, i; 672 673 gp = gpp->gpp_geom; 674 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 675 g_topology_assert(); 676 677 table = gp->softc; 678 if (!table->gpt_opened) { 679 gctl_error(req, "%d", EPERM); 680 return (EPERM); 681 } 682 683 g_topology_unlock(); 684 685 cp = LIST_FIRST(&gp->consumer); 686 if ((table->gpt_smhead | table->gpt_smtail) != 0) { 687 pp = cp->provider; 688 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 689 while (table->gpt_smhead != 0) { 690 i = ffs(table->gpt_smhead) - 1; 691 error = g_write_data(cp, i * pp->sectorsize, buf, 692 pp->sectorsize); 693 if (error) { 694 g_free(buf); 695 goto fail; 696 } 697 table->gpt_smhead &= ~(1 << i); 698 } 699 while (table->gpt_smtail != 0) { 700 i = ffs(table->gpt_smtail) - 1; 701 error = g_write_data(cp, pp->mediasize - (i + 1) * 702 pp->sectorsize, buf, pp->sectorsize); 703 if (error) { 704 g_free(buf); 705 goto fail; 706 } 707 table->gpt_smtail &= ~(1 << i); 708 } 709 g_free(buf); 710 } 711 712 if (table->gpt_scheme == &g_part_null_scheme) { 713 g_topology_lock(); 714 g_access(cp, -1, -1, -1); 715 g_part_wither(gp, ENXIO); 716 return (0); 717 } 718 719 error = G_PART_WRITE(table, cp); 720 if (error) 721 goto fail; 722 723 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 724 if (!entry->gpe_deleted) { 725 entry->gpe_created = 0; 726 entry->gpe_modified = 0; 727 continue; 728 } 729 LIST_REMOVE(entry, gpe_entry); 730 g_free(entry); 731 } 732 table->gpt_created = 0; 733 table->gpt_opened = 0; 734 735 g_topology_lock(); 736 g_access(cp, -1, -1, -1); 737 return (0); 738 739fail: 740 g_topology_lock(); 741 gctl_error(req, "%d", error); 742 return (error); 743} 744 745static int 746g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) 747{ 748 struct g_consumer *cp; 749 struct g_geom *gp; 750 struct g_provider *pp; 751 struct g_part_scheme *scheme; 752 struct g_part_table *null, *table; 753 struct sbuf *sb; 754 int attr, error; 755 756 pp = gpp->gpp_provider; 757 scheme = gpp->gpp_scheme; 758 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 759 g_topology_assert(); 760 761 /* Check that there isn't already a g_part geom on the provider. */ 762 gp = g_part_find_geom(pp->name); 763 if (gp != NULL) { 764 null = gp->softc; 765 if (null->gpt_scheme != &g_part_null_scheme) { 766 gctl_error(req, "%d geom '%s'", EEXIST, pp->name); 767 return (EEXIST); 768 } 769 } else 770 null = NULL; 771 772 if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) && 773 (gpp->gpp_entries < scheme->gps_minent || 774 gpp->gpp_entries > scheme->gps_maxent)) { 775 gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries); 776 return (EINVAL); 777 } 778 779 if (null == NULL) 780 gp = g_new_geomf(&g_part_class, "%s", pp->name); 781 gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM, 782 M_WAITOK); 783 table = gp->softc; 784 table->gpt_gp = gp; 785 table->gpt_scheme = gpp->gpp_scheme; 786 table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ? 787 gpp->gpp_entries : scheme->gps_minent; 788 LIST_INIT(&table->gpt_entry); 789 if (null == NULL) { 790 cp = g_new_consumer(gp); 791 error = g_attach(cp, pp); 792 if (error == 0) 793 error = g_access(cp, 1, 1, 1); 794 if (error != 0) { 795 g_part_wither(gp, error); 796 gctl_error(req, "%d geom '%s'", error, pp->name); 797 return (error); 798 } 799 table->gpt_opened = 1; 800 } else { 801 cp = LIST_FIRST(&gp->consumer); 802 table->gpt_opened = null->gpt_opened; 803 table->gpt_smhead = null->gpt_smhead; 804 table->gpt_smtail = null->gpt_smtail; 805 } 806 807 g_topology_unlock(); 808 809 /* Make sure the provider has media. */ 810 if (pp->mediasize == 0 || pp->sectorsize == 0) { 811 error = ENODEV; 812 goto fail; 813 } 814 815 /* Make sure we can nest and if so, determine our depth. */ 816 error = g_getattr("PART::isleaf", cp, &attr); 817 if (!error && attr) { 818 error = ENODEV; 819 goto fail; 820 } 821 error = g_getattr("PART::depth", cp, &attr); 822 table->gpt_depth = (!error) ? attr + 1 : 0; 823 824 /* 825 * Synthesize a disk geometry. Some partitioning schemes 826 * depend on it and since some file systems need it even 827 * when the partitition scheme doesn't, we do it here in 828 * scheme-independent code. 829 */ 830 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 831 832 error = G_PART_CREATE(table, gpp); 833 if (error) 834 goto fail; 835 836 g_topology_lock(); 837 838 table->gpt_created = 1; 839 if (null != NULL) 840 kobj_delete((kobj_t)null, M_GEOM); 841 842 /* 843 * Support automatic commit by filling in the gpp_geom 844 * parameter. 845 */ 846 gpp->gpp_parms |= G_PART_PARM_GEOM; 847 gpp->gpp_geom = gp; 848 849 /* Provide feedback if so requested. */ 850 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 851 sb = sbuf_new_auto(); 852 sbuf_printf(sb, "%s created\n", gp->name); 853 sbuf_finish(sb); 854 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 855 sbuf_delete(sb); 856 } 857 return (0); 858 859fail: 860 g_topology_lock(); 861 if (null == NULL) { 862 g_access(cp, -1, -1, -1); 863 g_part_wither(gp, error); 864 } else { 865 kobj_delete((kobj_t)gp->softc, M_GEOM); 866 gp->softc = null; 867 } 868 gctl_error(req, "%d provider", error); 869 return (error); 870} 871 872static int 873g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp) 874{ 875 struct g_geom *gp; 876 struct g_provider *pp; 877 struct g_part_entry *entry; 878 struct g_part_table *table; 879 struct sbuf *sb; 880 881 gp = gpp->gpp_geom; 882 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 883 g_topology_assert(); 884 885 table = gp->softc; 886 887 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 888 if (entry->gpe_deleted || entry->gpe_internal) 889 continue; 890 if (entry->gpe_index == gpp->gpp_index) 891 break; 892 } 893 if (entry == NULL) { 894 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 895 return (ENOENT); 896 } 897 898 pp = entry->gpe_pp; 899 if (pp != NULL) { 900 if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) { 901 gctl_error(req, "%d", EBUSY); 902 return (EBUSY); 903 } 904 905 pp->private = NULL; 906 entry->gpe_pp = NULL; 907 } 908 909 if (pp != NULL) 910 g_wither_provider(pp, ENXIO); 911 912 /* Provide feedback if so requested. */ 913 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 914 sb = sbuf_new_auto(); 915 G_PART_FULLNAME(table, entry, sb, gp->name); 916 sbuf_cat(sb, " deleted\n"); 917 sbuf_finish(sb); 918 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 919 sbuf_delete(sb); 920 } 921 922 if (entry->gpe_created) { 923 LIST_REMOVE(entry, gpe_entry); 924 g_free(entry); 925 } else { 926 entry->gpe_modified = 0; 927 entry->gpe_deleted = 1; 928 } 929 return (0); 930} 931 932static int 933g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp) 934{ 935 struct g_consumer *cp; 936 struct g_geom *gp; 937 struct g_provider *pp; 938 struct g_part_entry *entry, *tmp; 939 struct g_part_table *null, *table; 940 struct sbuf *sb; 941 int error; 942 943 gp = gpp->gpp_geom; 944 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 945 g_topology_assert(); 946 947 table = gp->softc; 948 /* Check for busy providers. */ 949 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 950 if (entry->gpe_deleted || entry->gpe_internal) 951 continue; 952 if (gpp->gpp_force) { 953 pp = entry->gpe_pp; 954 if (pp == NULL) 955 continue; 956 if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 957 continue; 958 } 959 gctl_error(req, "%d", EBUSY); 960 return (EBUSY); 961 } 962 963 if (gpp->gpp_force) { 964 /* Destroy all providers. */ 965 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 966 pp = entry->gpe_pp; 967 if (pp != NULL) { 968 pp->private = NULL; 969 g_wither_provider(pp, ENXIO); 970 } 971 LIST_REMOVE(entry, gpe_entry); 972 g_free(entry); 973 } 974 } 975 976 error = G_PART_DESTROY(table, gpp); 977 if (error) { 978 gctl_error(req, "%d", error); 979 return (error); 980 } 981 982 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM, 983 M_WAITOK); 984 null = gp->softc; 985 null->gpt_gp = gp; 986 null->gpt_scheme = &g_part_null_scheme; 987 LIST_INIT(&null->gpt_entry); 988 989 cp = LIST_FIRST(&gp->consumer); 990 pp = cp->provider; 991 null->gpt_last = pp->mediasize / pp->sectorsize - 1; 992 993 null->gpt_depth = table->gpt_depth; 994 null->gpt_opened = table->gpt_opened; 995 null->gpt_smhead = table->gpt_smhead; 996 null->gpt_smtail = table->gpt_smtail; 997 998 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 999 LIST_REMOVE(entry, gpe_entry); 1000 g_free(entry); 1001 } 1002 kobj_delete((kobj_t)table, M_GEOM); 1003 1004 /* Provide feedback if so requested. */ 1005 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1006 sb = sbuf_new_auto(); 1007 sbuf_printf(sb, "%s destroyed\n", gp->name); 1008 sbuf_finish(sb); 1009 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1010 sbuf_delete(sb); 1011 } 1012 return (0); 1013} 1014 1015static int 1016g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp) 1017{ 1018 struct g_geom *gp; 1019 struct g_part_entry *entry; 1020 struct g_part_table *table; 1021 struct sbuf *sb; 1022 int error; 1023 1024 gp = gpp->gpp_geom; 1025 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1026 g_topology_assert(); 1027 1028 table = gp->softc; 1029 1030 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1031 if (entry->gpe_deleted || entry->gpe_internal) 1032 continue; 1033 if (entry->gpe_index == gpp->gpp_index) 1034 break; 1035 } 1036 if (entry == NULL) { 1037 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1038 return (ENOENT); 1039 } 1040 1041 error = G_PART_MODIFY(table, entry, gpp); 1042 if (error) { 1043 gctl_error(req, "%d", error); 1044 return (error); 1045 } 1046 1047 if (!entry->gpe_created) 1048 entry->gpe_modified = 1; 1049 1050 /* Provide feedback if so requested. */ 1051 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1052 sb = sbuf_new_auto(); 1053 G_PART_FULLNAME(table, entry, sb, gp->name); 1054 sbuf_cat(sb, " modified\n"); 1055 sbuf_finish(sb); 1056 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1057 sbuf_delete(sb); 1058 } 1059 return (0); 1060} 1061 1062static int 1063g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) 1064{ 1065 gctl_error(req, "%d verb 'move'", ENOSYS); 1066 return (ENOSYS); 1067} 1068 1069static int 1070g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) 1071{ 1072 struct g_part_table *table; 1073 struct g_geom *gp; 1074 struct sbuf *sb; 1075 int error, recovered; 1076 1077 gp = gpp->gpp_geom; 1078 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1079 g_topology_assert(); 1080 table = gp->softc; 1081 error = recovered = 0; 1082 1083 if (table->gpt_corrupt) { 1084 error = G_PART_RECOVER(table); 1085 if (error) { 1086 gctl_error(req, "%d recovering '%s' failed", 1087 error, gp->name); 1088 return (error); 1089 } 1090 recovered = 1; 1091 } 1092 /* Provide feedback if so requested. */ 1093 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1094 sb = sbuf_new_auto(); 1095 if (recovered) 1096 sbuf_printf(sb, "%s recovered\n", gp->name); 1097 else 1098 sbuf_printf(sb, "%s recovering is not needed\n", 1099 gp->name); 1100 sbuf_finish(sb); 1101 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1102 sbuf_delete(sb); 1103 } 1104 return (0); 1105} 1106 1107static int 1108g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) 1109{ 1110 struct g_geom *gp; 1111 struct g_provider *pp; 1112 struct g_part_entry *pe, *entry; 1113 struct g_part_table *table; 1114 struct sbuf *sb; 1115 quad_t end; 1116 int error; 1117 1118 gp = gpp->gpp_geom; 1119 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1120 g_topology_assert(); 1121 table = gp->softc; 1122 1123 /* check gpp_index */ 1124 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1125 if (entry->gpe_deleted || entry->gpe_internal) 1126 continue; 1127 if (entry->gpe_index == gpp->gpp_index) 1128 break; 1129 } 1130 if (entry == NULL) { 1131 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1132 return (ENOENT); 1133 } 1134 1135 /* check gpp_size */ 1136 end = entry->gpe_start + gpp->gpp_size - 1; 1137 if (gpp->gpp_size < 1 || end > table->gpt_last) { 1138 gctl_error(req, "%d size '%jd'", EINVAL, 1139 (intmax_t)gpp->gpp_size); 1140 return (EINVAL); 1141 } 1142 1143 LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) { 1144 if (pe->gpe_deleted || pe->gpe_internal || pe == entry) 1145 continue; 1146 if (end >= pe->gpe_start && end <= pe->gpe_end) { 1147 gctl_error(req, "%d end '%jd'", ENOSPC, 1148 (intmax_t)end); 1149 return (ENOSPC); 1150 } 1151 if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) { 1152 gctl_error(req, "%d size '%jd'", ENOSPC, 1153 (intmax_t)gpp->gpp_size); 1154 return (ENOSPC); 1155 } 1156 } 1157 1158 pp = entry->gpe_pp; 1159 if ((g_debugflags & 16) == 0 && 1160 (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) { 1161 gctl_error(req, "%d", EBUSY); 1162 return (EBUSY); 1163 } 1164 1165 error = G_PART_RESIZE(table, entry, gpp); 1166 if (error) { 1167 gctl_error(req, "%d", error); 1168 return (error); 1169 } 1170 1171 if (!entry->gpe_created) 1172 entry->gpe_modified = 1; 1173 1174 /* update mediasize of changed provider */ 1175 pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 1176 pp->sectorsize; 1177 1178 /* Provide feedback if so requested. */ 1179 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1180 sb = sbuf_new_auto(); 1181 G_PART_FULLNAME(table, entry, sb, gp->name); 1182 sbuf_cat(sb, " resized\n"); 1183 sbuf_finish(sb); 1184 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1185 sbuf_delete(sb); 1186 } 1187 return (0); 1188} 1189 1190static int 1191g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, 1192 unsigned int set) 1193{ 1194 struct g_geom *gp; 1195 struct g_part_entry *entry; 1196 struct g_part_table *table; 1197 struct sbuf *sb; 1198 int error; 1199 1200 gp = gpp->gpp_geom; 1201 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1202 g_topology_assert(); 1203 1204 table = gp->softc; 1205 1206 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1207 if (entry->gpe_deleted || entry->gpe_internal) 1208 continue; 1209 if (entry->gpe_index == gpp->gpp_index) 1210 break; 1211 } 1212 if (entry == NULL) { 1213 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1214 return (ENOENT); 1215 } 1216 1217 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set); 1218 if (error) { 1219 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib); 1220 return (error); 1221 } 1222 1223 /* Provide feedback if so requested. */ 1224 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1225 sb = sbuf_new_auto(); 1226 sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib, 1227 (set) ? "" : "un"); 1228 G_PART_FULLNAME(table, entry, sb, gp->name); 1229 sbuf_printf(sb, "\n"); 1230 sbuf_finish(sb); 1231 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1232 sbuf_delete(sb); 1233 } 1234 return (0); 1235} 1236 1237static int 1238g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) 1239{ 1240 struct g_consumer *cp; 1241 struct g_provider *pp; 1242 struct g_geom *gp; 1243 struct g_part_entry *entry, *tmp; 1244 struct g_part_table *table; 1245 int error, reprobe; 1246 1247 gp = gpp->gpp_geom; 1248 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1249 g_topology_assert(); 1250 1251 table = gp->softc; 1252 if (!table->gpt_opened) { 1253 gctl_error(req, "%d", EPERM); 1254 return (EPERM); 1255 } 1256 1257 cp = LIST_FIRST(&gp->consumer); 1258 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1259 entry->gpe_modified = 0; 1260 if (entry->gpe_created) { 1261 pp = entry->gpe_pp; 1262 if (pp != NULL) { 1263 pp->private = NULL; 1264 entry->gpe_pp = NULL; 1265 g_wither_provider(pp, ENXIO); 1266 } 1267 entry->gpe_deleted = 1; 1268 } 1269 if (entry->gpe_deleted) { 1270 LIST_REMOVE(entry, gpe_entry); 1271 g_free(entry); 1272 } 1273 } 1274 1275 g_topology_unlock(); 1276 1277 reprobe = (table->gpt_scheme == &g_part_null_scheme || 1278 table->gpt_created) ? 1 : 0; 1279 1280 if (reprobe) { 1281 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1282 if (entry->gpe_internal) 1283 continue; 1284 error = EBUSY; 1285 goto fail; 1286 } 1287 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1288 LIST_REMOVE(entry, gpe_entry); 1289 g_free(entry); 1290 } 1291 error = g_part_probe(gp, cp, table->gpt_depth); 1292 if (error) { 1293 g_topology_lock(); 1294 g_access(cp, -1, -1, -1); 1295 g_part_wither(gp, error); 1296 return (0); 1297 } 1298 table = gp->softc; 1299 1300 /* 1301 * Synthesize a disk geometry. Some partitioning schemes 1302 * depend on it and since some file systems need it even 1303 * when the partitition scheme doesn't, we do it here in 1304 * scheme-independent code. 1305 */ 1306 pp = cp->provider; 1307 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1308 } 1309 1310 error = G_PART_READ(table, cp); 1311 if (error) 1312 goto fail; 1313 1314 g_topology_lock(); 1315 1316 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1317 if (!entry->gpe_internal) 1318 g_part_new_provider(gp, table, entry); 1319 } 1320 1321 table->gpt_opened = 0; 1322 g_access(cp, -1, -1, -1); 1323 return (0); 1324 1325fail: 1326 g_topology_lock(); 1327 gctl_error(req, "%d", error); 1328 return (error); 1329} 1330 1331static void 1332g_part_wither(struct g_geom *gp, int error) 1333{ 1334 struct g_part_entry *entry; 1335 struct g_part_table *table; 1336 1337 table = gp->softc; 1338 if (table != NULL) { 1339 G_PART_DESTROY(table, NULL); 1340 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1341 LIST_REMOVE(entry, gpe_entry); 1342 g_free(entry); 1343 } 1344 if (gp->softc != NULL) { 1345 kobj_delete((kobj_t)gp->softc, M_GEOM); 1346 gp->softc = NULL; 1347 } 1348 } 1349 g_wither_geom(gp, error); 1350} 1351 1352/* 1353 * Class methods. 1354 */ 1355 1356static void 1357g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 1358{ 1359 struct g_part_parms gpp; 1360 struct g_part_table *table; 1361 struct gctl_req_arg *ap; 1362 enum g_part_ctl ctlreq; 1363 unsigned int i, mparms, oparms, parm; 1364 int auto_commit, close_on_error; 1365 int error, modifies; 1366 1367 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1368 g_topology_assert(); 1369 1370 ctlreq = G_PART_CTL_NONE; 1371 modifies = 1; 1372 mparms = 0; 1373 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1374 switch (*verb) { 1375 case 'a': 1376 if (!strcmp(verb, "add")) { 1377 ctlreq = G_PART_CTL_ADD; 1378 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1379 G_PART_PARM_START | G_PART_PARM_TYPE; 1380 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1381 } 1382 break; 1383 case 'b': 1384 if (!strcmp(verb, "bootcode")) { 1385 ctlreq = G_PART_CTL_BOOTCODE; 1386 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; 1387 } 1388 break; 1389 case 'c': 1390 if (!strcmp(verb, "commit")) { 1391 ctlreq = G_PART_CTL_COMMIT; 1392 mparms |= G_PART_PARM_GEOM; 1393 modifies = 0; 1394 } else if (!strcmp(verb, "create")) { 1395 ctlreq = G_PART_CTL_CREATE; 1396 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1397 oparms |= G_PART_PARM_ENTRIES; 1398 } 1399 break; 1400 case 'd': 1401 if (!strcmp(verb, "delete")) { 1402 ctlreq = G_PART_CTL_DELETE; 1403 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1404 } else if (!strcmp(verb, "destroy")) { 1405 ctlreq = G_PART_CTL_DESTROY; 1406 mparms |= G_PART_PARM_GEOM; 1407 oparms |= G_PART_PARM_FORCE; 1408 } 1409 break; 1410 case 'm': 1411 if (!strcmp(verb, "modify")) { 1412 ctlreq = G_PART_CTL_MODIFY; 1413 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1414 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1415 } else if (!strcmp(verb, "move")) { 1416 ctlreq = G_PART_CTL_MOVE; 1417 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1418 } 1419 break; 1420 case 'r': 1421 if (!strcmp(verb, "recover")) { 1422 ctlreq = G_PART_CTL_RECOVER; 1423 mparms |= G_PART_PARM_GEOM; 1424 } else if (!strcmp(verb, "resize")) { 1425 ctlreq = G_PART_CTL_RESIZE; 1426 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX | 1427 G_PART_PARM_SIZE; 1428 } 1429 break; 1430 case 's': 1431 if (!strcmp(verb, "set")) { 1432 ctlreq = G_PART_CTL_SET; 1433 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1434 G_PART_PARM_INDEX; 1435 } 1436 break; 1437 case 'u': 1438 if (!strcmp(verb, "undo")) { 1439 ctlreq = G_PART_CTL_UNDO; 1440 mparms |= G_PART_PARM_GEOM; 1441 modifies = 0; 1442 } else if (!strcmp(verb, "unset")) { 1443 ctlreq = G_PART_CTL_UNSET; 1444 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1445 G_PART_PARM_INDEX; 1446 } 1447 break; 1448 } 1449 if (ctlreq == G_PART_CTL_NONE) { 1450 gctl_error(req, "%d verb '%s'", EINVAL, verb); 1451 return; 1452 } 1453 1454 bzero(&gpp, sizeof(gpp)); 1455 for (i = 0; i < req->narg; i++) { 1456 ap = &req->arg[i]; 1457 parm = 0; 1458 switch (ap->name[0]) { 1459 case 'a': 1460 if (!strcmp(ap->name, "arg0")) { 1461 parm = mparms & 1462 (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER); 1463 } 1464 if (!strcmp(ap->name, "attrib")) 1465 parm = G_PART_PARM_ATTRIB; 1466 break; 1467 case 'b': 1468 if (!strcmp(ap->name, "bootcode")) 1469 parm = G_PART_PARM_BOOTCODE; 1470 break; 1471 case 'c': 1472 if (!strcmp(ap->name, "class")) 1473 continue; 1474 break; 1475 case 'e': 1476 if (!strcmp(ap->name, "entries")) 1477 parm = G_PART_PARM_ENTRIES; 1478 break; 1479 case 'f': 1480 if (!strcmp(ap->name, "flags")) 1481 parm = G_PART_PARM_FLAGS; 1482 else if (!strcmp(ap->name, "force")) 1483 parm = G_PART_PARM_FORCE; 1484 break; 1485 case 'i': 1486 if (!strcmp(ap->name, "index")) 1487 parm = G_PART_PARM_INDEX; 1488 break; 1489 case 'l': 1490 if (!strcmp(ap->name, "label")) 1491 parm = G_PART_PARM_LABEL; 1492 break; 1493 case 'o': 1494 if (!strcmp(ap->name, "output")) 1495 parm = G_PART_PARM_OUTPUT; 1496 break; 1497 case 's': 1498 if (!strcmp(ap->name, "scheme")) 1499 parm = G_PART_PARM_SCHEME; 1500 else if (!strcmp(ap->name, "size")) 1501 parm = G_PART_PARM_SIZE; 1502 else if (!strcmp(ap->name, "start")) 1503 parm = G_PART_PARM_START; 1504 break; 1505 case 't': 1506 if (!strcmp(ap->name, "type")) 1507 parm = G_PART_PARM_TYPE; 1508 break; 1509 case 'v': 1510 if (!strcmp(ap->name, "verb")) 1511 continue; 1512 else if (!strcmp(ap->name, "version")) 1513 parm = G_PART_PARM_VERSION; 1514 break; 1515 } 1516 if ((parm & (mparms | oparms)) == 0) { 1517 gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1518 return; 1519 } 1520 switch (parm) { 1521 case G_PART_PARM_ATTRIB: 1522 error = g_part_parm_str(req, ap->name, 1523 &gpp.gpp_attrib); 1524 break; 1525 case G_PART_PARM_BOOTCODE: 1526 error = g_part_parm_bootcode(req, ap->name, 1527 &gpp.gpp_codeptr, &gpp.gpp_codesize); 1528 break; 1529 case G_PART_PARM_ENTRIES: 1530 error = g_part_parm_intmax(req, ap->name, 1531 &gpp.gpp_entries); 1532 break; 1533 case G_PART_PARM_FLAGS: 1534 error = g_part_parm_str(req, ap->name, &gpp.gpp_flags); 1535 break; 1536 case G_PART_PARM_FORCE: 1537 error = g_part_parm_uint32(req, ap->name, 1538 &gpp.gpp_force); 1539 break; 1540 case G_PART_PARM_GEOM: 1541 error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom); 1542 break; 1543 case G_PART_PARM_INDEX: 1544 error = g_part_parm_intmax(req, ap->name, 1545 &gpp.gpp_index); 1546 break; 1547 case G_PART_PARM_LABEL: 1548 error = g_part_parm_str(req, ap->name, &gpp.gpp_label); 1549 break; 1550 case G_PART_PARM_OUTPUT: 1551 error = 0; /* Write-only parameter */ 1552 break; 1553 case G_PART_PARM_PROVIDER: 1554 error = g_part_parm_provider(req, ap->name, 1555 &gpp.gpp_provider); 1556 break; 1557 case G_PART_PARM_SCHEME: 1558 error = g_part_parm_scheme(req, ap->name, 1559 &gpp.gpp_scheme); 1560 break; 1561 case G_PART_PARM_SIZE: 1562 error = g_part_parm_quad(req, ap->name, &gpp.gpp_size); 1563 break; 1564 case G_PART_PARM_START: 1565 error = g_part_parm_quad(req, ap->name, 1566 &gpp.gpp_start); 1567 break; 1568 case G_PART_PARM_TYPE: 1569 error = g_part_parm_str(req, ap->name, &gpp.gpp_type); 1570 break; 1571 case G_PART_PARM_VERSION: 1572 error = g_part_parm_uint32(req, ap->name, 1573 &gpp.gpp_version); 1574 break; 1575 default: 1576 error = EDOOFUS; 1577 gctl_error(req, "%d %s", error, ap->name); 1578 break; 1579 } 1580 if (error != 0) { 1581 if (error == ENOATTR) { 1582 gctl_error(req, "%d param '%s'", error, 1583 ap->name); 1584 } 1585 return; 1586 } 1587 gpp.gpp_parms |= parm; 1588 } 1589 if ((gpp.gpp_parms & mparms) != mparms) { 1590 parm = mparms - (gpp.gpp_parms & mparms); 1591 gctl_error(req, "%d param '%x'", ENOATTR, parm); 1592 return; 1593 } 1594 1595 /* Obtain permissions if possible/necessary. */ 1596 close_on_error = 0; 1597 table = NULL; 1598 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1599 table = gpp.gpp_geom->softc; 1600 if (table != NULL && table->gpt_corrupt && 1601 ctlreq != G_PART_CTL_DESTROY && 1602 ctlreq != G_PART_CTL_RECOVER) { 1603 gctl_error(req, "%d table '%s' is corrupt", 1604 EPERM, gpp.gpp_geom->name); 1605 return; 1606 } 1607 if (table != NULL && !table->gpt_opened) { 1608 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1609 1, 1, 1); 1610 if (error) { 1611 gctl_error(req, "%d geom '%s'", error, 1612 gpp.gpp_geom->name); 1613 return; 1614 } 1615 table->gpt_opened = 1; 1616 close_on_error = 1; 1617 } 1618 } 1619 1620 /* Allow the scheme to check or modify the parameters. */ 1621 if (table != NULL) { 1622 error = G_PART_PRECHECK(table, ctlreq, &gpp); 1623 if (error) { 1624 gctl_error(req, "%d pre-check failed", error); 1625 goto out; 1626 } 1627 } else 1628 error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1629 1630 switch (ctlreq) { 1631 case G_PART_CTL_NONE: 1632 panic("%s", __func__); 1633 case G_PART_CTL_ADD: 1634 error = g_part_ctl_add(req, &gpp); 1635 break; 1636 case G_PART_CTL_BOOTCODE: 1637 error = g_part_ctl_bootcode(req, &gpp); 1638 break; 1639 case G_PART_CTL_COMMIT: 1640 error = g_part_ctl_commit(req, &gpp); 1641 break; 1642 case G_PART_CTL_CREATE: 1643 error = g_part_ctl_create(req, &gpp); 1644 break; 1645 case G_PART_CTL_DELETE: 1646 error = g_part_ctl_delete(req, &gpp); 1647 break; 1648 case G_PART_CTL_DESTROY: 1649 error = g_part_ctl_destroy(req, &gpp); 1650 break; 1651 case G_PART_CTL_MODIFY: 1652 error = g_part_ctl_modify(req, &gpp); 1653 break; 1654 case G_PART_CTL_MOVE: 1655 error = g_part_ctl_move(req, &gpp); 1656 break; 1657 case G_PART_CTL_RECOVER: 1658 error = g_part_ctl_recover(req, &gpp); 1659 break; 1660 case G_PART_CTL_RESIZE: 1661 error = g_part_ctl_resize(req, &gpp); 1662 break; 1663 case G_PART_CTL_SET: 1664 error = g_part_ctl_setunset(req, &gpp, 1); 1665 break; 1666 case G_PART_CTL_UNDO: 1667 error = g_part_ctl_undo(req, &gpp); 1668 break; 1669 case G_PART_CTL_UNSET: 1670 error = g_part_ctl_setunset(req, &gpp, 0); 1671 break; 1672 } 1673 1674 /* Implement automatic commit. */ 1675 if (!error) { 1676 auto_commit = (modifies && 1677 (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1678 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1679 if (auto_commit) { 1680 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s", 1681 __func__)); 1682 error = g_part_ctl_commit(req, &gpp); 1683 } 1684 } 1685 1686 out: 1687 if (error && close_on_error) { 1688 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1689 table->gpt_opened = 0; 1690 } 1691} 1692 1693static int 1694g_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1695 struct g_geom *gp) 1696{ 1697 1698 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1699 g_topology_assert(); 1700 1701 g_part_wither(gp, EINVAL); 1702 return (0); 1703} 1704 1705static struct g_geom * 1706g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1707{ 1708 struct g_consumer *cp; 1709 struct g_geom *gp; 1710 struct g_part_entry *entry; 1711 struct g_part_table *table; 1712 struct root_hold_token *rht; 1713 int attr, depth; 1714 int error; 1715 1716 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1717 g_topology_assert(); 1718 1719 /* Skip providers that are already open for writing. */ 1720 if (pp->acw > 0) 1721 return (NULL); 1722 1723 /* 1724 * Create a GEOM with consumer and hook it up to the provider. 1725 * With that we become part of the topology. Optain read access 1726 * to the provider. 1727 */ 1728 gp = g_new_geomf(mp, "%s", pp->name); 1729 cp = g_new_consumer(gp); 1730 error = g_attach(cp, pp); 1731 if (error == 0) 1732 error = g_access(cp, 1, 0, 0); 1733 if (error != 0) { 1734 g_part_wither(gp, error); 1735 return (NULL); 1736 } 1737 1738 rht = root_mount_hold(mp->name); 1739 g_topology_unlock(); 1740 1741 /* 1742 * Short-circuit the whole probing galore when there's no 1743 * media present. 1744 */ 1745 if (pp->mediasize == 0 || pp->sectorsize == 0) { 1746 error = ENODEV; 1747 goto fail; 1748 } 1749 1750 /* Make sure we can nest and if so, determine our depth. */ 1751 error = g_getattr("PART::isleaf", cp, &attr); 1752 if (!error && attr) { 1753 error = ENODEV; 1754 goto fail; 1755 } 1756 error = g_getattr("PART::depth", cp, &attr); 1757 depth = (!error) ? attr + 1 : 0; 1758 1759 error = g_part_probe(gp, cp, depth); 1760 if (error) 1761 goto fail; 1762 1763 table = gp->softc; 1764 1765 /* 1766 * Synthesize a disk geometry. Some partitioning schemes 1767 * depend on it and since some file systems need it even 1768 * when the partitition scheme doesn't, we do it here in 1769 * scheme-independent code. 1770 */ 1771 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1772 1773 error = G_PART_READ(table, cp); 1774 if (error) 1775 goto fail; 1776 1777 g_topology_lock(); 1778 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1779 if (!entry->gpe_internal) 1780 g_part_new_provider(gp, table, entry); 1781 } 1782 1783 root_mount_rel(rht); 1784 g_access(cp, -1, 0, 0); 1785 return (gp); 1786 1787 fail: 1788 g_topology_lock(); 1789 root_mount_rel(rht); 1790 g_access(cp, -1, 0, 0); 1791 g_part_wither(gp, error); 1792 return (NULL); 1793} 1794 1795/* 1796 * Geom methods. 1797 */ 1798 1799static int 1800g_part_access(struct g_provider *pp, int dr, int dw, int de) 1801{ 1802 struct g_consumer *cp; 1803 1804 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1805 dw, de)); 1806 1807 cp = LIST_FIRST(&pp->geom->consumer); 1808 1809 /* We always gain write-exclusive access. */ 1810 return (g_access(cp, dr, dw, dw + de)); 1811} 1812 1813static void 1814g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1815 struct g_consumer *cp, struct g_provider *pp) 1816{ 1817 char buf[64]; 1818 struct g_part_entry *entry; 1819 struct g_part_table *table; 1820 1821 KASSERT(sb != NULL && gp != NULL, ("%s", __func__)); 1822 table = gp->softc; 1823 1824 if (indent == NULL) { 1825 KASSERT(cp == NULL && pp != NULL, ("%s", __func__)); 1826 entry = pp->private; 1827 if (entry == NULL) 1828 return; 1829 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 1830 (uintmax_t)entry->gpe_offset, 1831 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1832 /* 1833 * libdisk compatibility quirk - the scheme dumps the 1834 * slicer name and partition type in a way that is 1835 * compatible with libdisk. When libdisk is not used 1836 * anymore, this should go away. 1837 */ 1838 G_PART_DUMPCONF(table, entry, sb, indent); 1839 } else if (cp != NULL) { /* Consumer configuration. */ 1840 KASSERT(pp == NULL, ("%s", __func__)); 1841 /* none */ 1842 } else if (pp != NULL) { /* Provider configuration. */ 1843 entry = pp->private; 1844 if (entry == NULL) 1845 return; 1846 sbuf_printf(sb, "%s<start>%ju</start>\n", indent, 1847 (uintmax_t)entry->gpe_start); 1848 sbuf_printf(sb, "%s<end>%ju</end>\n", indent, 1849 (uintmax_t)entry->gpe_end); 1850 sbuf_printf(sb, "%s<index>%u</index>\n", indent, 1851 entry->gpe_index); 1852 sbuf_printf(sb, "%s<type>%s</type>\n", indent, 1853 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1854 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 1855 (uintmax_t)entry->gpe_offset); 1856 sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 1857 (uintmax_t)pp->mediasize); 1858 G_PART_DUMPCONF(table, entry, sb, indent); 1859 } else { /* Geom configuration. */ 1860 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 1861 table->gpt_scheme->name); 1862 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 1863 table->gpt_entries); 1864 sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 1865 (uintmax_t)table->gpt_first); 1866 sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 1867 (uintmax_t)table->gpt_last); 1868 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 1869 table->gpt_sectors); 1870 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 1871 table->gpt_heads); 1872 sbuf_printf(sb, "%s<state>%s</state>\n", indent, 1873 table->gpt_corrupt ? "CORRUPT": "OK"); 1874 sbuf_printf(sb, "%s<modified>%s</modified>\n", indent, 1875 table->gpt_opened ? "true": "false"); 1876 G_PART_DUMPCONF(table, NULL, sb, indent); 1877 } 1878} 1879 1880static void 1881g_part_orphan(struct g_consumer *cp) 1882{ 1883 struct g_provider *pp; 1884 struct g_part_table *table; 1885 1886 pp = cp->provider; 1887 KASSERT(pp != NULL, ("%s", __func__)); 1888 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 1889 g_topology_assert(); 1890 1891 KASSERT(pp->error != 0, ("%s", __func__)); 1892 table = cp->geom->softc; 1893 if (table != NULL && table->gpt_opened) 1894 g_access(cp, -1, -1, -1); 1895 g_part_wither(cp->geom, pp->error); 1896} 1897 1898static void 1899g_part_spoiled(struct g_consumer *cp) 1900{ 1901 1902 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 1903 g_topology_assert(); 1904 1905 g_part_wither(cp->geom, ENXIO); 1906} 1907 1908static void 1909g_part_start(struct bio *bp) 1910{ 1911 struct bio *bp2; 1912 struct g_consumer *cp; 1913 struct g_geom *gp; 1914 struct g_part_entry *entry; 1915 struct g_part_table *table; 1916 struct g_kerneldump *gkd; 1917 struct g_provider *pp; 1918 1919 pp = bp->bio_to; 1920 gp = pp->geom; 1921 table = gp->softc; 1922 cp = LIST_FIRST(&gp->consumer); 1923 1924 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 1925 pp->name)); 1926 1927 entry = pp->private; 1928 if (entry == NULL) { 1929 g_io_deliver(bp, ENXIO); 1930 return; 1931 } 1932 1933 switch(bp->bio_cmd) { 1934 case BIO_DELETE: 1935 case BIO_READ: 1936 case BIO_WRITE: 1937 if (bp->bio_offset >= pp->mediasize) { 1938 g_io_deliver(bp, EIO); 1939 return; 1940 } 1941 bp2 = g_clone_bio(bp); 1942 if (bp2 == NULL) { 1943 g_io_deliver(bp, ENOMEM); 1944 return; 1945 } 1946 if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 1947 bp2->bio_length = pp->mediasize - bp2->bio_offset; 1948 bp2->bio_done = g_std_done; 1949 bp2->bio_offset += entry->gpe_offset; 1950 g_io_request(bp2, cp); 1951 return; 1952 case BIO_FLUSH: 1953 break; 1954 case BIO_GETATTR: 1955 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 1956 return; 1957 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 1958 return; 1959 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 1960 return; 1961 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 1962 return; 1963 if (g_handleattr_str(bp, "PART::scheme", 1964 table->gpt_scheme->name)) 1965 return; 1966 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 1967 /* 1968 * Check that the partition is suitable for kernel 1969 * dumps. Typically only swap partitions should be 1970 * used. 1971 */ 1972 if (!G_PART_DUMPTO(table, entry)) { 1973 g_io_deliver(bp, ENODEV); 1974 printf("GEOM_PART: Partition '%s' not suitable" 1975 " for kernel dumps (wrong type?)\n", 1976 pp->name); 1977 return; 1978 } 1979 gkd = (struct g_kerneldump *)bp->bio_data; 1980 if (gkd->offset >= pp->mediasize) { 1981 g_io_deliver(bp, EIO); 1982 return; 1983 } 1984 if (gkd->offset + gkd->length > pp->mediasize) 1985 gkd->length = pp->mediasize - gkd->offset; 1986 gkd->offset += entry->gpe_offset; 1987 } 1988 break; 1989 default: 1990 g_io_deliver(bp, EOPNOTSUPP); 1991 return; 1992 } 1993 1994 bp2 = g_clone_bio(bp); 1995 if (bp2 == NULL) { 1996 g_io_deliver(bp, ENOMEM); 1997 return; 1998 } 1999 bp2->bio_done = g_std_done; 2000 g_io_request(bp2, cp); 2001} 2002 2003static void 2004g_part_init(struct g_class *mp) 2005{ 2006 2007 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list); 2008} 2009 2010static void 2011g_part_fini(struct g_class *mp) 2012{ 2013 2014 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list); 2015} 2016 2017static void 2018g_part_unload_event(void *arg, int flag) 2019{ 2020 struct g_consumer *cp; 2021 struct g_geom *gp; 2022 struct g_provider *pp; 2023 struct g_part_scheme *scheme; 2024 struct g_part_table *table; 2025 uintptr_t *xchg; 2026 int acc, error; 2027 2028 if (flag == EV_CANCEL) 2029 return; 2030 2031 xchg = arg; 2032 error = 0; 2033 scheme = (void *)(*xchg); 2034 2035 g_topology_assert(); 2036 2037 LIST_FOREACH(gp, &g_part_class.geom, geom) { 2038 table = gp->softc; 2039 if (table->gpt_scheme != scheme) 2040 continue; 2041 2042 acc = 0; 2043 LIST_FOREACH(pp, &gp->provider, provider) 2044 acc += pp->acr + pp->acw + pp->ace; 2045 LIST_FOREACH(cp, &gp->consumer, consumer) 2046 acc += cp->acr + cp->acw + cp->ace; 2047 2048 if (!acc) 2049 g_part_wither(gp, ENOSYS); 2050 else 2051 error = EBUSY; 2052 } 2053 2054 if (!error) 2055 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 2056 2057 *xchg = error; 2058} 2059 2060int 2061g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) 2062{ 2063 uintptr_t arg; 2064 int error; 2065 2066 switch (type) { 2067 case MOD_LOAD: 2068 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list); 2069 2070 error = g_retaste(&g_part_class); 2071 if (error) 2072 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 2073 break; 2074 case MOD_UNLOAD: 2075 arg = (uintptr_t)scheme; 2076 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, 2077 NULL); 2078 if (!error) 2079 error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg; 2080 break; 2081 default: 2082 error = EOPNOTSUPP; 2083 break; 2084 } 2085 2086 return (error); 2087} 2088