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