g_part.c revision 188329
1/*- 2 * Copyright (c) 2002, 2005-2008 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 188329 2009-02-08 20:15:08Z marcel $"); 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/systm.h> 43#include <sys/uuid.h> 44#include <geom/geom.h> 45#include <geom/geom_ctl.h> 46#include <geom/geom_int.h> 47#include <geom/part/g_part.h> 48 49#include "g_part_if.h" 50 51static kobj_method_t g_part_null_methods[] = { 52 { 0, 0 } 53}; 54 55static struct g_part_scheme g_part_null_scheme = { 56 "(none)", 57 g_part_null_methods, 58 sizeof(struct g_part_table), 59}; 60 61TAILQ_HEAD(, g_part_scheme) g_part_schemes = 62 TAILQ_HEAD_INITIALIZER(g_part_schemes); 63 64struct g_part_alias_list { 65 const char *lexeme; 66 enum g_part_alias alias; 67} g_part_alias_list[G_PART_ALIAS_COUNT] = { 68 { "apple-hfs", G_PART_ALIAS_APPLE_HFS }, 69 { "efi", G_PART_ALIAS_EFI }, 70 { "freebsd", G_PART_ALIAS_FREEBSD }, 71 { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT }, 72 { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP }, 73 { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS }, 74 { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM }, 75 { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS }, 76 { "mbr", G_PART_ALIAS_MBR } 77}; 78 79/* 80 * The GEOM partitioning class. 81 */ 82static g_ctl_req_t g_part_ctlreq; 83static g_ctl_destroy_geom_t g_part_destroy_geom; 84static g_fini_t g_part_fini; 85static g_init_t g_part_init; 86static g_taste_t g_part_taste; 87 88static g_access_t g_part_access; 89static g_dumpconf_t g_part_dumpconf; 90static g_orphan_t g_part_orphan; 91static g_spoiled_t g_part_spoiled; 92static g_start_t g_part_start; 93 94static struct g_class g_part_class = { 95 .name = "PART", 96 .version = G_VERSION, 97 /* Class methods. */ 98 .ctlreq = g_part_ctlreq, 99 .destroy_geom = g_part_destroy_geom, 100 .fini = g_part_fini, 101 .init = g_part_init, 102 .taste = g_part_taste, 103 /* Geom methods. */ 104 .access = g_part_access, 105 .dumpconf = g_part_dumpconf, 106 .orphan = g_part_orphan, 107 .spoiled = g_part_spoiled, 108 .start = g_part_start, 109}; 110 111DECLARE_GEOM_CLASS(g_part_class, g_part); 112 113enum g_part_ctl { 114 G_PART_CTL_NONE, 115 G_PART_CTL_ADD, 116 G_PART_CTL_BOOTCODE, 117 G_PART_CTL_COMMIT, 118 G_PART_CTL_CREATE, 119 G_PART_CTL_DELETE, 120 G_PART_CTL_DESTROY, 121 G_PART_CTL_MODIFY, 122 G_PART_CTL_MOVE, 123 G_PART_CTL_RECOVER, 124 G_PART_CTL_RESIZE, 125 G_PART_CTL_SET, 126 G_PART_CTL_UNDO, 127 G_PART_CTL_UNSET 128}; 129 130/* 131 * Support functions. 132 */ 133 134static void g_part_wither(struct g_geom *, int); 135 136const char * 137g_part_alias_name(enum g_part_alias alias) 138{ 139 int i; 140 141 for (i = 0; i < G_PART_ALIAS_COUNT; i++) { 142 if (g_part_alias_list[i].alias != alias) 143 continue; 144 return (g_part_alias_list[i].lexeme); 145 } 146 147 return (NULL); 148} 149 150void 151g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs, 152 u_int *bestheads) 153{ 154 static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 }; 155 off_t chs, cylinders; 156 u_int heads; 157 int idx; 158 159 *bestchs = 0; 160 *bestheads = 0; 161 for (idx = 0; candidate_heads[idx] != 0; idx++) { 162 heads = candidate_heads[idx]; 163 cylinders = blocks / heads / sectors; 164 if (cylinders < heads || cylinders < sectors) 165 break; 166 if (cylinders > 1023) 167 continue; 168 chs = cylinders * heads * sectors; 169 if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) { 170 *bestchs = chs; 171 *bestheads = heads; 172 } 173 } 174} 175 176static void 177g_part_geometry(struct g_part_table *table, struct g_consumer *cp, 178 off_t blocks) 179{ 180 static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 }; 181 off_t chs, bestchs; 182 u_int heads, sectors; 183 int idx; 184 185 if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || sectors == 0 || 186 g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) { 187 table->gpt_fixgeom = 0; 188 table->gpt_heads = 0; 189 table->gpt_sectors = 0; 190 bestchs = 0; 191 for (idx = 0; candidate_sectors[idx] != 0; idx++) { 192 sectors = candidate_sectors[idx]; 193 g_part_geometry_heads(blocks, sectors, &chs, &heads); 194 if (chs == 0) 195 continue; 196 /* 197 * Prefer a geometry with sectors > 1, but only if 198 * it doesn't bump down the numbver of heads to 1. 199 */ 200 if (chs > bestchs || (chs == bestchs && heads > 1 && 201 table->gpt_sectors == 1)) { 202 bestchs = chs; 203 table->gpt_heads = heads; 204 table->gpt_sectors = sectors; 205 } 206 } 207 /* 208 * If we didn't find a geometry at all, then the disk is 209 * too big. This means we can use the maximum number of 210 * heads and sectors. 211 */ 212 if (bestchs == 0) { 213 table->gpt_heads = 255; 214 table->gpt_sectors = 63; 215 } 216 } else { 217 table->gpt_fixgeom = 1; 218 table->gpt_heads = heads; 219 table->gpt_sectors = sectors; 220 } 221} 222 223struct g_part_entry * 224g_part_new_entry(struct g_part_table *table, int index, quad_t start, 225 quad_t end) 226{ 227 struct g_part_entry *entry, *last; 228 229 last = NULL; 230 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 231 if (entry->gpe_index == index) 232 break; 233 if (entry->gpe_index > index) { 234 entry = NULL; 235 break; 236 } 237 last = entry; 238 } 239 if (entry == NULL) { 240 entry = g_malloc(table->gpt_scheme->gps_entrysz, 241 M_WAITOK | M_ZERO); 242 entry->gpe_index = index; 243 if (last == NULL) 244 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 245 else 246 LIST_INSERT_AFTER(last, entry, gpe_entry); 247 } 248 entry->gpe_start = start; 249 entry->gpe_end = end; 250 return (entry); 251} 252 253static void 254g_part_new_provider(struct g_geom *gp, struct g_part_table *table, 255 struct g_part_entry *entry) 256{ 257 char buf[32]; 258 struct g_consumer *cp; 259 struct g_provider *pp; 260 261 cp = LIST_FIRST(&gp->consumer); 262 pp = cp->provider; 263 264 entry->gpe_offset = entry->gpe_start * pp->sectorsize; 265 266 if (entry->gpe_pp == NULL) { 267 entry->gpe_pp = g_new_providerf(gp, "%s%s", gp->name, 268 G_PART_NAME(table, entry, buf, sizeof(buf))); 269 entry->gpe_pp->private = entry; /* Close the circle. */ 270 } 271 entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */ 272 entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 273 pp->sectorsize; 274 entry->gpe_pp->sectorsize = pp->sectorsize; 275 entry->gpe_pp->flags = pp->flags & G_PF_CANDELETE; 276 if (pp->stripesize > 0) { 277 entry->gpe_pp->stripesize = pp->stripesize; 278 entry->gpe_pp->stripeoffset = (pp->stripeoffset + 279 entry->gpe_offset) % pp->stripesize; 280 } 281 g_error_provider(entry->gpe_pp, 0); 282} 283 284static int 285g_part_parm_geom(const char *p, struct g_geom **v) 286{ 287 struct g_geom *gp; 288 289 LIST_FOREACH(gp, &g_part_class.geom, geom) { 290 if (!strcmp(p, gp->name)) 291 break; 292 } 293 if (gp == NULL) 294 return (EINVAL); 295 *v = gp; 296 return (0); 297} 298 299static int 300g_part_parm_provider(const char *p, struct g_provider **v) 301{ 302 struct g_provider *pp; 303 304 pp = g_provider_by_name(p); 305 if (pp == NULL) 306 return (EINVAL); 307 *v = pp; 308 return (0); 309} 310 311static int 312g_part_parm_quad(const char *p, quad_t *v) 313{ 314 char *x; 315 quad_t q; 316 317 q = strtoq(p, &x, 0); 318 if (*x != '\0' || q < 0) 319 return (EINVAL); 320 *v = q; 321 return (0); 322} 323 324static int 325g_part_parm_scheme(const char *p, struct g_part_scheme **v) 326{ 327 struct g_part_scheme *s; 328 329 TAILQ_FOREACH(s, &g_part_schemes, scheme_list) { 330 if (s == &g_part_null_scheme) 331 continue; 332 if (!strcasecmp(s->name, p)) 333 break; 334 } 335 if (s == NULL) 336 return (EINVAL); 337 *v = s; 338 return (0); 339} 340 341static int 342g_part_parm_str(const char *p, const char **v) 343{ 344 345 if (p[0] == '\0') 346 return (EINVAL); 347 *v = p; 348 return (0); 349} 350 351static int 352g_part_parm_uint(const char *p, u_int *v) 353{ 354 char *x; 355 long l; 356 357 l = strtol(p, &x, 0); 358 if (*x != '\0' || l < 0 || l > INT_MAX) 359 return (EINVAL); 360 *v = (unsigned int)l; 361 return (0); 362} 363 364static int 365g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth) 366{ 367 struct g_part_scheme *iter, *scheme; 368 struct g_part_table *table; 369 int pri, probe; 370 371 table = gp->softc; 372 scheme = (table != NULL) ? table->gpt_scheme : NULL; 373 pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN; 374 if (pri == 0) 375 goto done; 376 if (pri > 0) { /* error */ 377 scheme = NULL; 378 pri = INT_MIN; 379 } 380 381 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { 382 if (iter == &g_part_null_scheme) 383 continue; 384 table = (void *)kobj_create((kobj_class_t)iter, M_GEOM, 385 M_WAITOK); 386 table->gpt_gp = gp; 387 table->gpt_scheme = iter; 388 table->gpt_depth = depth; 389 probe = G_PART_PROBE(table, cp); 390 if (probe <= 0 && probe > pri) { 391 pri = probe; 392 scheme = iter; 393 if (gp->softc != NULL) 394 kobj_delete((kobj_t)gp->softc, M_GEOM); 395 gp->softc = table; 396 if (pri == 0) 397 goto done; 398 } else 399 kobj_delete((kobj_t)table, M_GEOM); 400 } 401 402done: 403 return ((scheme == NULL) ? ENXIO : 0); 404} 405 406/* 407 * Control request functions. 408 */ 409 410static int 411g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) 412{ 413 char buf[32]; 414 struct g_geom *gp; 415 struct g_provider *pp; 416 struct g_part_entry *delent, *last, *entry; 417 struct g_part_table *table; 418 struct sbuf *sb; 419 quad_t end; 420 unsigned int index; 421 int error; 422 423 gp = gpp->gpp_geom; 424 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 425 g_topology_assert(); 426 427 pp = LIST_FIRST(&gp->consumer)->provider; 428 table = gp->softc; 429 end = gpp->gpp_start + gpp->gpp_size - 1; 430 431 if (gpp->gpp_start < table->gpt_first || 432 gpp->gpp_start > table->gpt_last) { 433 gctl_error(req, "%d start '%jd'", EINVAL, 434 (intmax_t)gpp->gpp_start); 435 return (EINVAL); 436 } 437 if (end < gpp->gpp_start || end > table->gpt_last) { 438 gctl_error(req, "%d size '%jd'", EINVAL, 439 (intmax_t)gpp->gpp_size); 440 return (EINVAL); 441 } 442 if (gpp->gpp_index > table->gpt_entries) { 443 gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index); 444 return (EINVAL); 445 } 446 447 delent = last = NULL; 448 index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1; 449 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 450 if (entry->gpe_deleted) { 451 if (entry->gpe_index == index) 452 delent = entry; 453 continue; 454 } 455 if (entry->gpe_index == index) 456 index = entry->gpe_index + 1; 457 if (entry->gpe_index < index) 458 last = entry; 459 if (entry->gpe_internal) 460 continue; 461 if (gpp->gpp_start >= entry->gpe_start && 462 gpp->gpp_start <= entry->gpe_end) { 463 gctl_error(req, "%d start '%jd'", ENOSPC, 464 (intmax_t)gpp->gpp_start); 465 return (ENOSPC); 466 } 467 if (end >= entry->gpe_start && end <= entry->gpe_end) { 468 gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end); 469 return (ENOSPC); 470 } 471 if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) { 472 gctl_error(req, "%d size '%jd'", ENOSPC, 473 (intmax_t)gpp->gpp_size); 474 return (ENOSPC); 475 } 476 } 477 if (gpp->gpp_index > 0 && index != gpp->gpp_index) { 478 gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index); 479 return (EEXIST); 480 } 481 482 entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz, 483 M_WAITOK | M_ZERO) : delent; 484 entry->gpe_index = index; 485 entry->gpe_start = gpp->gpp_start; 486 entry->gpe_end = end; 487 error = G_PART_ADD(table, entry, gpp); 488 if (error) { 489 gctl_error(req, "%d", error); 490 if (delent == NULL) 491 g_free(entry); 492 return (error); 493 } 494 if (delent == NULL) { 495 if (last == NULL) 496 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 497 else 498 LIST_INSERT_AFTER(last, entry, gpe_entry); 499 entry->gpe_created = 1; 500 } else { 501 entry->gpe_deleted = 0; 502 entry->gpe_modified = 1; 503 } 504 g_part_new_provider(gp, table, entry); 505 506 /* Provide feedback if so requested. */ 507 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 508 sb = sbuf_new_auto(); 509 sbuf_printf(sb, "%s%s added\n", gp->name, 510 G_PART_NAME(table, entry, buf, sizeof(buf))); 511 sbuf_finish(sb); 512 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 513 sbuf_delete(sb); 514 } 515 return (0); 516} 517 518static int 519g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp) 520{ 521 struct g_geom *gp; 522 struct g_part_table *table; 523 struct sbuf *sb; 524 int error, sz; 525 526 gp = gpp->gpp_geom; 527 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 528 g_topology_assert(); 529 530 table = gp->softc; 531 sz = table->gpt_scheme->gps_bootcodesz; 532 if (sz == 0) { 533 error = ENODEV; 534 goto fail; 535 } 536 if (gpp->gpp_codesize > sz) { 537 error = EFBIG; 538 goto fail; 539 } 540 541 error = G_PART_BOOTCODE(table, gpp); 542 if (error) 543 goto fail; 544 545 /* Provide feedback if so requested. */ 546 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 547 sb = sbuf_new_auto(); 548 sbuf_printf(sb, "%s has bootcode\n", gp->name); 549 sbuf_finish(sb); 550 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 551 sbuf_delete(sb); 552 } 553 return (0); 554 555 fail: 556 gctl_error(req, "%d", error); 557 return (error); 558} 559 560static int 561g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp) 562{ 563 struct g_consumer *cp; 564 struct g_geom *gp; 565 struct g_provider *pp; 566 struct g_part_entry *entry, *tmp; 567 struct g_part_table *table; 568 char *buf; 569 int error, i; 570 571 gp = gpp->gpp_geom; 572 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 573 g_topology_assert(); 574 575 table = gp->softc; 576 if (!table->gpt_opened) { 577 gctl_error(req, "%d", EPERM); 578 return (EPERM); 579 } 580 581 cp = LIST_FIRST(&gp->consumer); 582 if ((table->gpt_smhead | table->gpt_smtail) != 0) { 583 pp = cp->provider; 584 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 585 while (table->gpt_smhead != 0) { 586 i = ffs(table->gpt_smhead) - 1; 587 error = g_write_data(cp, i * pp->sectorsize, buf, 588 pp->sectorsize); 589 if (error) { 590 g_free(buf); 591 goto fail; 592 } 593 table->gpt_smhead &= ~(1 << i); 594 } 595 while (table->gpt_smtail != 0) { 596 i = ffs(table->gpt_smtail) - 1; 597 error = g_write_data(cp, pp->mediasize - (i + 1) * 598 pp->sectorsize, buf, pp->sectorsize); 599 if (error) { 600 g_free(buf); 601 goto fail; 602 } 603 table->gpt_smtail &= ~(1 << i); 604 } 605 g_free(buf); 606 } 607 608 if (table->gpt_scheme == &g_part_null_scheme) { 609 g_access(cp, -1, -1, -1); 610 g_part_wither(gp, ENXIO); 611 return (0); 612 } 613 614 error = G_PART_WRITE(table, cp); 615 if (error) 616 goto fail; 617 618 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 619 if (!entry->gpe_deleted) { 620 entry->gpe_created = 0; 621 entry->gpe_modified = 0; 622 continue; 623 } 624 LIST_REMOVE(entry, gpe_entry); 625 g_free(entry); 626 } 627 table->gpt_created = 0; 628 table->gpt_opened = 0; 629 g_access(cp, -1, -1, -1); 630 return (0); 631 632fail: 633 gctl_error(req, "%d", error); 634 return (error); 635} 636 637static int 638g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) 639{ 640 struct g_consumer *cp; 641 struct g_geom *gp; 642 struct g_provider *pp; 643 struct g_part_scheme *scheme; 644 struct g_part_table *null, *table; 645 struct sbuf *sb; 646 int attr, error; 647 648 pp = gpp->gpp_provider; 649 scheme = gpp->gpp_scheme; 650 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 651 g_topology_assert(); 652 653 /* Check that there isn't already a g_part geom on the provider. */ 654 error = g_part_parm_geom(pp->name, &gp); 655 if (!error) { 656 null = gp->softc; 657 if (null->gpt_scheme != &g_part_null_scheme) { 658 gctl_error(req, "%d geom '%s'", EEXIST, pp->name); 659 return (EEXIST); 660 } 661 } else 662 null = NULL; 663 664 if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) && 665 (gpp->gpp_entries < scheme->gps_minent || 666 gpp->gpp_entries > scheme->gps_maxent)) { 667 gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries); 668 return (EINVAL); 669 } 670 671 if (null == NULL) 672 gp = g_new_geomf(&g_part_class, "%s", pp->name); 673 gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM, 674 M_WAITOK); 675 table = gp->softc; 676 table->gpt_gp = gp; 677 table->gpt_scheme = gpp->gpp_scheme; 678 table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ? 679 gpp->gpp_entries : scheme->gps_minent; 680 LIST_INIT(&table->gpt_entry); 681 if (null == NULL) { 682 cp = g_new_consumer(gp); 683 error = g_attach(cp, pp); 684 if (error == 0) 685 error = g_access(cp, 1, 1, 1); 686 if (error != 0) { 687 g_part_wither(gp, error); 688 gctl_error(req, "%d geom '%s'", error, pp->name); 689 return (error); 690 } 691 table->gpt_opened = 1; 692 } else { 693 cp = LIST_FIRST(&gp->consumer); 694 table->gpt_opened = null->gpt_opened; 695 table->gpt_smhead = null->gpt_smhead; 696 table->gpt_smtail = null->gpt_smtail; 697 } 698 699 g_topology_unlock(); 700 701 /* Make sure the provider has media. */ 702 if (pp->mediasize == 0 || pp->sectorsize == 0) { 703 error = ENODEV; 704 goto fail; 705 } 706 707 /* Make sure we can nest and if so, determine our depth. */ 708 error = g_getattr("PART::isleaf", cp, &attr); 709 if (!error && attr) { 710 error = ENODEV; 711 goto fail; 712 } 713 error = g_getattr("PART::depth", cp, &attr); 714 table->gpt_depth = (!error) ? attr + 1 : 0; 715 716 /* If we're nested, get the absolute sector offset on disk. */ 717 if (table->gpt_depth) { 718 error = g_getattr("PART::offset", cp, &attr); 719 if (error) 720 goto fail; 721 table->gpt_offset = attr; 722 } 723 724 /* 725 * Synthesize a disk geometry. Some partitioning schemes 726 * depend on it and since some file systems need it even 727 * when the partitition scheme doesn't, we do it here in 728 * scheme-independent code. 729 */ 730 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 731 732 error = G_PART_CREATE(table, gpp); 733 if (error) 734 goto fail; 735 736 g_topology_lock(); 737 738 table->gpt_created = 1; 739 if (null != NULL) 740 kobj_delete((kobj_t)null, M_GEOM); 741 742 /* 743 * Support automatic commit by filling in the gpp_geom 744 * parameter. 745 */ 746 gpp->gpp_parms |= G_PART_PARM_GEOM; 747 gpp->gpp_geom = gp; 748 749 /* Provide feedback if so requested. */ 750 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 751 sb = sbuf_new_auto(); 752 sbuf_printf(sb, "%s created\n", gp->name); 753 sbuf_finish(sb); 754 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 755 sbuf_delete(sb); 756 } 757 return (0); 758 759fail: 760 g_topology_lock(); 761 if (null == NULL) { 762 g_access(cp, -1, -1, -1); 763 g_part_wither(gp, error); 764 } else { 765 kobj_delete((kobj_t)gp->softc, M_GEOM); 766 gp->softc = null; 767 } 768 gctl_error(req, "%d provider", error); 769 return (error); 770} 771 772static int 773g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp) 774{ 775 char buf[32]; 776 struct g_geom *gp; 777 struct g_provider *pp; 778 struct g_part_entry *entry; 779 struct g_part_table *table; 780 struct sbuf *sb; 781 782 gp = gpp->gpp_geom; 783 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 784 g_topology_assert(); 785 786 table = gp->softc; 787 788 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 789 if (entry->gpe_deleted || entry->gpe_internal) 790 continue; 791 if (entry->gpe_index == gpp->gpp_index) 792 break; 793 } 794 if (entry == NULL) { 795 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 796 return (ENOENT); 797 } 798 799 pp = entry->gpe_pp; 800 if (pp != NULL) { 801 if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) { 802 gctl_error(req, "%d", EBUSY); 803 return (EBUSY); 804 } 805 806 pp->private = NULL; 807 entry->gpe_pp = NULL; 808 } 809 810 if (entry->gpe_created) { 811 LIST_REMOVE(entry, gpe_entry); 812 g_free(entry); 813 } else { 814 entry->gpe_modified = 0; 815 entry->gpe_deleted = 1; 816 } 817 818 if (pp != NULL) 819 g_wither_provider(pp, ENXIO); 820 821 /* Provide feedback if so requested. */ 822 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 823 sb = sbuf_new_auto(); 824 sbuf_printf(sb, "%s%s deleted\n", gp->name, 825 G_PART_NAME(table, entry, buf, sizeof(buf))); 826 sbuf_finish(sb); 827 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 828 sbuf_delete(sb); 829 } 830 return (0); 831} 832 833static int 834g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp) 835{ 836 struct g_geom *gp; 837 struct g_part_entry *entry; 838 struct g_part_table *null, *table; 839 struct sbuf *sb; 840 int error; 841 842 gp = gpp->gpp_geom; 843 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 844 g_topology_assert(); 845 846 table = gp->softc; 847 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 848 if (entry->gpe_deleted || entry->gpe_internal) 849 continue; 850 gctl_error(req, "%d", EBUSY); 851 return (EBUSY); 852 } 853 854 error = G_PART_DESTROY(table, gpp); 855 if (error) { 856 gctl_error(req, "%d", error); 857 return (error); 858 } 859 860 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM, 861 M_WAITOK); 862 null = gp->softc; 863 null->gpt_gp = gp; 864 null->gpt_scheme = &g_part_null_scheme; 865 LIST_INIT(&null->gpt_entry); 866 null->gpt_depth = table->gpt_depth; 867 null->gpt_opened = table->gpt_opened; 868 null->gpt_smhead = table->gpt_smhead; 869 null->gpt_smtail = table->gpt_smtail; 870 871 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 872 LIST_REMOVE(entry, gpe_entry); 873 g_free(entry); 874 } 875 kobj_delete((kobj_t)table, M_GEOM); 876 877 /* Provide feedback if so requested. */ 878 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 879 sb = sbuf_new_auto(); 880 sbuf_printf(sb, "%s destroyed\n", gp->name); 881 sbuf_finish(sb); 882 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 883 sbuf_delete(sb); 884 } 885 return (0); 886} 887 888static int 889g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp) 890{ 891 char buf[32]; 892 struct g_geom *gp; 893 struct g_part_entry *entry; 894 struct g_part_table *table; 895 struct sbuf *sb; 896 int error; 897 898 gp = gpp->gpp_geom; 899 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 900 g_topology_assert(); 901 902 table = gp->softc; 903 904 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 905 if (entry->gpe_deleted || entry->gpe_internal) 906 continue; 907 if (entry->gpe_index == gpp->gpp_index) 908 break; 909 } 910 if (entry == NULL) { 911 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 912 return (ENOENT); 913 } 914 915 error = G_PART_MODIFY(table, entry, gpp); 916 if (error) { 917 gctl_error(req, "%d", error); 918 return (error); 919 } 920 921 if (!entry->gpe_created) 922 entry->gpe_modified = 1; 923 924 /* Provide feedback if so requested. */ 925 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 926 sb = sbuf_new_auto(); 927 sbuf_printf(sb, "%s%s modified\n", gp->name, 928 G_PART_NAME(table, entry, buf, sizeof(buf))); 929 sbuf_finish(sb); 930 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 931 sbuf_delete(sb); 932 } 933 return (0); 934} 935 936static int 937g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) 938{ 939 gctl_error(req, "%d verb 'move'", ENOSYS); 940 return (ENOSYS); 941} 942 943static int 944g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) 945{ 946 gctl_error(req, "%d verb 'recover'", ENOSYS); 947 return (ENOSYS); 948} 949 950static int 951g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) 952{ 953 gctl_error(req, "%d verb 'resize'", ENOSYS); 954 return (ENOSYS); 955} 956 957static int 958g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, 959 unsigned int set) 960{ 961 char buf[32]; 962 struct g_geom *gp; 963 struct g_part_entry *entry; 964 struct g_part_table *table; 965 struct sbuf *sb; 966 int error; 967 968 gp = gpp->gpp_geom; 969 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 970 g_topology_assert(); 971 972 table = gp->softc; 973 974 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 975 if (entry->gpe_deleted || entry->gpe_internal) 976 continue; 977 if (entry->gpe_index == gpp->gpp_index) 978 break; 979 } 980 if (entry == NULL) { 981 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 982 return (ENOENT); 983 } 984 985 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set); 986 if (error) { 987 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib); 988 return (error); 989 } 990 991 /* Provide feedback if so requested. */ 992 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 993 sb = sbuf_new_auto(); 994 sbuf_printf(sb, "%s%s has %s %sset\n", gp->name, 995 G_PART_NAME(table, entry, buf, sizeof(buf)), 996 gpp->gpp_attrib, (set) ? "" : "un"); 997 sbuf_finish(sb); 998 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 999 sbuf_delete(sb); 1000 } 1001 return (0); 1002} 1003 1004static int 1005g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) 1006{ 1007 struct g_consumer *cp; 1008 struct g_provider *pp; 1009 struct g_geom *gp; 1010 struct g_part_entry *entry, *tmp; 1011 struct g_part_table *table; 1012 int error, reprobe; 1013 1014 gp = gpp->gpp_geom; 1015 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1016 g_topology_assert(); 1017 1018 table = gp->softc; 1019 if (!table->gpt_opened) { 1020 gctl_error(req, "%d", EPERM); 1021 return (EPERM); 1022 } 1023 1024 cp = LIST_FIRST(&gp->consumer); 1025 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1026 entry->gpe_modified = 0; 1027 if (entry->gpe_created) { 1028 pp = entry->gpe_pp; 1029 if (pp != NULL) { 1030 pp->private = NULL; 1031 entry->gpe_pp = NULL; 1032 g_wither_provider(pp, ENXIO); 1033 } 1034 entry->gpe_deleted = 1; 1035 } 1036 if (entry->gpe_deleted) { 1037 LIST_REMOVE(entry, gpe_entry); 1038 g_free(entry); 1039 } 1040 } 1041 1042 g_topology_unlock(); 1043 1044 reprobe = (table->gpt_scheme == &g_part_null_scheme || 1045 table->gpt_created) ? 1 : 0; 1046 1047 if (reprobe) { 1048 if (!LIST_EMPTY(&table->gpt_entry)) { 1049 error = EBUSY; 1050 goto fail; 1051 } 1052 error = g_part_probe(gp, cp, table->gpt_depth); 1053 if (error) { 1054 g_topology_lock(); 1055 g_access(cp, -1, -1, -1); 1056 g_part_wither(gp, error); 1057 return (0); 1058 } 1059 table = gp->softc; 1060 } 1061 1062 error = G_PART_READ(table, cp); 1063 if (error) 1064 goto fail; 1065 1066 g_topology_lock(); 1067 1068 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1069 if (!entry->gpe_internal) 1070 g_part_new_provider(gp, table, entry); 1071 } 1072 1073 table->gpt_opened = 0; 1074 g_access(cp, -1, -1, -1); 1075 return (0); 1076 1077fail: 1078 g_topology_lock(); 1079 gctl_error(req, "%d", error); 1080 return (error); 1081} 1082 1083static void 1084g_part_wither(struct g_geom *gp, int error) 1085{ 1086 struct g_part_entry *entry; 1087 struct g_part_table *table; 1088 1089 table = gp->softc; 1090 if (table != NULL) { 1091 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1092 LIST_REMOVE(entry, gpe_entry); 1093 g_free(entry); 1094 } 1095 if (gp->softc != NULL) { 1096 kobj_delete((kobj_t)gp->softc, M_GEOM); 1097 gp->softc = NULL; 1098 } 1099 } 1100 g_wither_geom(gp, error); 1101} 1102 1103/* 1104 * Class methods. 1105 */ 1106 1107static void 1108g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 1109{ 1110 struct g_part_parms gpp; 1111 struct g_part_table *table; 1112 struct gctl_req_arg *ap; 1113 const char *p; 1114 enum g_part_ctl ctlreq; 1115 unsigned int i, mparms, oparms, parm; 1116 int auto_commit, close_on_error; 1117 int error, len, modifies; 1118 1119 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1120 g_topology_assert(); 1121 1122 ctlreq = G_PART_CTL_NONE; 1123 modifies = 1; 1124 mparms = 0; 1125 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1126 switch (*verb) { 1127 case 'a': 1128 if (!strcmp(verb, "add")) { 1129 ctlreq = G_PART_CTL_ADD; 1130 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1131 G_PART_PARM_START | G_PART_PARM_TYPE; 1132 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1133 } 1134 break; 1135 case 'b': 1136 if (!strcmp(verb, "bootcode")) { 1137 ctlreq = G_PART_CTL_BOOTCODE; 1138 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; 1139 } 1140 break; 1141 case 'c': 1142 if (!strcmp(verb, "commit")) { 1143 ctlreq = G_PART_CTL_COMMIT; 1144 mparms |= G_PART_PARM_GEOM; 1145 modifies = 0; 1146 } else if (!strcmp(verb, "create")) { 1147 ctlreq = G_PART_CTL_CREATE; 1148 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1149 oparms |= G_PART_PARM_ENTRIES; 1150 } 1151 break; 1152 case 'd': 1153 if (!strcmp(verb, "delete")) { 1154 ctlreq = G_PART_CTL_DELETE; 1155 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1156 } else if (!strcmp(verb, "destroy")) { 1157 ctlreq = G_PART_CTL_DESTROY; 1158 mparms |= G_PART_PARM_GEOM; 1159 } 1160 break; 1161 case 'm': 1162 if (!strcmp(verb, "modify")) { 1163 ctlreq = G_PART_CTL_MODIFY; 1164 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1165 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1166 } else if (!strcmp(verb, "move")) { 1167 ctlreq = G_PART_CTL_MOVE; 1168 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1169 } 1170 break; 1171 case 'r': 1172 if (!strcmp(verb, "recover")) { 1173 ctlreq = G_PART_CTL_RECOVER; 1174 mparms |= G_PART_PARM_GEOM; 1175 } else if (!strcmp(verb, "resize")) { 1176 ctlreq = G_PART_CTL_RESIZE; 1177 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1178 } 1179 break; 1180 case 's': 1181 if (!strcmp(verb, "set")) { 1182 ctlreq = G_PART_CTL_SET; 1183 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1184 G_PART_PARM_INDEX; 1185 } 1186 break; 1187 case 'u': 1188 if (!strcmp(verb, "undo")) { 1189 ctlreq = G_PART_CTL_UNDO; 1190 mparms |= G_PART_PARM_GEOM; 1191 modifies = 0; 1192 } else if (!strcmp(verb, "unset")) { 1193 ctlreq = G_PART_CTL_UNSET; 1194 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1195 G_PART_PARM_INDEX; 1196 } 1197 break; 1198 } 1199 if (ctlreq == G_PART_CTL_NONE) { 1200 gctl_error(req, "%d verb '%s'", EINVAL, verb); 1201 return; 1202 } 1203 1204 bzero(&gpp, sizeof(gpp)); 1205 for (i = 0; i < req->narg; i++) { 1206 ap = &req->arg[i]; 1207 parm = 0; 1208 switch (ap->name[0]) { 1209 case 'a': 1210 if (!strcmp(ap->name, "attrib")) 1211 parm = G_PART_PARM_ATTRIB; 1212 break; 1213 case 'b': 1214 if (!strcmp(ap->name, "bootcode")) 1215 parm = G_PART_PARM_BOOTCODE; 1216 break; 1217 case 'c': 1218 if (!strcmp(ap->name, "class")) 1219 continue; 1220 break; 1221 case 'e': 1222 if (!strcmp(ap->name, "entries")) 1223 parm = G_PART_PARM_ENTRIES; 1224 break; 1225 case 'f': 1226 if (!strcmp(ap->name, "flags")) 1227 parm = G_PART_PARM_FLAGS; 1228 break; 1229 case 'g': 1230 if (!strcmp(ap->name, "geom")) 1231 parm = G_PART_PARM_GEOM; 1232 break; 1233 case 'i': 1234 if (!strcmp(ap->name, "index")) 1235 parm = G_PART_PARM_INDEX; 1236 break; 1237 case 'l': 1238 if (!strcmp(ap->name, "label")) 1239 parm = G_PART_PARM_LABEL; 1240 break; 1241 case 'o': 1242 if (!strcmp(ap->name, "output")) 1243 parm = G_PART_PARM_OUTPUT; 1244 break; 1245 case 'p': 1246 if (!strcmp(ap->name, "provider")) 1247 parm = G_PART_PARM_PROVIDER; 1248 break; 1249 case 's': 1250 if (!strcmp(ap->name, "scheme")) 1251 parm = G_PART_PARM_SCHEME; 1252 else if (!strcmp(ap->name, "size")) 1253 parm = G_PART_PARM_SIZE; 1254 else if (!strcmp(ap->name, "start")) 1255 parm = G_PART_PARM_START; 1256 break; 1257 case 't': 1258 if (!strcmp(ap->name, "type")) 1259 parm = G_PART_PARM_TYPE; 1260 break; 1261 case 'v': 1262 if (!strcmp(ap->name, "verb")) 1263 continue; 1264 else if (!strcmp(ap->name, "version")) 1265 parm = G_PART_PARM_VERSION; 1266 break; 1267 } 1268 if ((parm & (mparms | oparms)) == 0) { 1269 gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1270 return; 1271 } 1272 if (parm == G_PART_PARM_BOOTCODE) 1273 p = gctl_get_param(req, ap->name, &len); 1274 else 1275 p = gctl_get_asciiparam(req, ap->name); 1276 if (p == NULL) { 1277 gctl_error(req, "%d param '%s'", ENOATTR, ap->name); 1278 return; 1279 } 1280 switch (parm) { 1281 case G_PART_PARM_ATTRIB: 1282 error = g_part_parm_str(p, &gpp.gpp_attrib); 1283 break; 1284 case G_PART_PARM_BOOTCODE: 1285 gpp.gpp_codeptr = p; 1286 gpp.gpp_codesize = len; 1287 error = 0; 1288 break; 1289 case G_PART_PARM_ENTRIES: 1290 error = g_part_parm_uint(p, &gpp.gpp_entries); 1291 break; 1292 case G_PART_PARM_FLAGS: 1293 if (p[0] == '\0') 1294 continue; 1295 error = g_part_parm_str(p, &gpp.gpp_flags); 1296 break; 1297 case G_PART_PARM_GEOM: 1298 error = g_part_parm_geom(p, &gpp.gpp_geom); 1299 break; 1300 case G_PART_PARM_INDEX: 1301 error = g_part_parm_uint(p, &gpp.gpp_index); 1302 break; 1303 case G_PART_PARM_LABEL: 1304 /* An empty label is always valid. */ 1305 gpp.gpp_label = p; 1306 error = 0; 1307 break; 1308 case G_PART_PARM_OUTPUT: 1309 error = 0; /* Write-only parameter */ 1310 break; 1311 case G_PART_PARM_PROVIDER: 1312 error = g_part_parm_provider(p, &gpp.gpp_provider); 1313 break; 1314 case G_PART_PARM_SCHEME: 1315 error = g_part_parm_scheme(p, &gpp.gpp_scheme); 1316 break; 1317 case G_PART_PARM_SIZE: 1318 error = g_part_parm_quad(p, &gpp.gpp_size); 1319 break; 1320 case G_PART_PARM_START: 1321 error = g_part_parm_quad(p, &gpp.gpp_start); 1322 break; 1323 case G_PART_PARM_TYPE: 1324 error = g_part_parm_str(p, &gpp.gpp_type); 1325 break; 1326 case G_PART_PARM_VERSION: 1327 error = g_part_parm_uint(p, &gpp.gpp_version); 1328 break; 1329 default: 1330 error = EDOOFUS; 1331 break; 1332 } 1333 if (error) { 1334 gctl_error(req, "%d %s '%s'", error, ap->name, p); 1335 return; 1336 } 1337 gpp.gpp_parms |= parm; 1338 } 1339 if ((gpp.gpp_parms & mparms) != mparms) { 1340 parm = mparms - (gpp.gpp_parms & mparms); 1341 gctl_error(req, "%d param '%x'", ENOATTR, parm); 1342 return; 1343 } 1344 1345 /* Obtain permissions if possible/necessary. */ 1346 close_on_error = 0; 1347 table = NULL; /* Suppress uninit. warning. */ 1348 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1349 table = gpp.gpp_geom->softc; 1350 if (table != NULL && !table->gpt_opened) { 1351 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1352 1, 1, 1); 1353 if (error) { 1354 gctl_error(req, "%d geom '%s'", error, 1355 gpp.gpp_geom->name); 1356 return; 1357 } 1358 table->gpt_opened = 1; 1359 close_on_error = 1; 1360 } 1361 } 1362 1363 error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1364 switch (ctlreq) { 1365 case G_PART_CTL_NONE: 1366 panic("%s", __func__); 1367 case G_PART_CTL_ADD: 1368 error = g_part_ctl_add(req, &gpp); 1369 break; 1370 case G_PART_CTL_BOOTCODE: 1371 error = g_part_ctl_bootcode(req, &gpp); 1372 break; 1373 case G_PART_CTL_COMMIT: 1374 error = g_part_ctl_commit(req, &gpp); 1375 break; 1376 case G_PART_CTL_CREATE: 1377 error = g_part_ctl_create(req, &gpp); 1378 break; 1379 case G_PART_CTL_DELETE: 1380 error = g_part_ctl_delete(req, &gpp); 1381 break; 1382 case G_PART_CTL_DESTROY: 1383 error = g_part_ctl_destroy(req, &gpp); 1384 break; 1385 case G_PART_CTL_MODIFY: 1386 error = g_part_ctl_modify(req, &gpp); 1387 break; 1388 case G_PART_CTL_MOVE: 1389 error = g_part_ctl_move(req, &gpp); 1390 break; 1391 case G_PART_CTL_RECOVER: 1392 error = g_part_ctl_recover(req, &gpp); 1393 break; 1394 case G_PART_CTL_RESIZE: 1395 error = g_part_ctl_resize(req, &gpp); 1396 break; 1397 case G_PART_CTL_SET: 1398 error = g_part_ctl_setunset(req, &gpp, 1); 1399 break; 1400 case G_PART_CTL_UNDO: 1401 error = g_part_ctl_undo(req, &gpp); 1402 break; 1403 case G_PART_CTL_UNSET: 1404 error = g_part_ctl_setunset(req, &gpp, 0); 1405 break; 1406 } 1407 1408 /* Implement automatic commit. */ 1409 if (!error) { 1410 auto_commit = (modifies && 1411 (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1412 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1413 if (auto_commit) { 1414 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__)); 1415 error = g_part_ctl_commit(req, &gpp); 1416 } 1417 } 1418 1419 if (error && close_on_error) { 1420 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1421 table->gpt_opened = 0; 1422 } 1423} 1424 1425static int 1426g_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1427 struct g_geom *gp) 1428{ 1429 1430 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1431 g_topology_assert(); 1432 1433 g_part_wither(gp, EINVAL); 1434 return (0); 1435} 1436 1437static struct g_geom * 1438g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1439{ 1440 struct g_consumer *cp; 1441 struct g_geom *gp; 1442 struct g_part_entry *entry; 1443 struct g_part_table *table; 1444 struct root_hold_token *rht; 1445 int attr, depth; 1446 int error; 1447 1448 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1449 g_topology_assert(); 1450 1451 /* 1452 * Create a GEOM with consumer and hook it up to the provider. 1453 * With that we become part of the topology. Optain read access 1454 * to the provider. 1455 */ 1456 gp = g_new_geomf(mp, "%s", pp->name); 1457 cp = g_new_consumer(gp); 1458 error = g_attach(cp, pp); 1459 if (error == 0) 1460 error = g_access(cp, 1, 0, 0); 1461 if (error != 0) { 1462 g_part_wither(gp, error); 1463 return (NULL); 1464 } 1465 1466 rht = root_mount_hold(mp->name); 1467 g_topology_unlock(); 1468 1469 /* 1470 * Short-circuit the whole probing galore when there's no 1471 * media present. 1472 */ 1473 if (pp->mediasize == 0 || pp->sectorsize == 0) { 1474 error = ENODEV; 1475 goto fail; 1476 } 1477 1478 /* Make sure we can nest and if so, determine our depth. */ 1479 error = g_getattr("PART::isleaf", cp, &attr); 1480 if (!error && attr) { 1481 error = ENODEV; 1482 goto fail; 1483 } 1484 error = g_getattr("PART::depth", cp, &attr); 1485 depth = (!error) ? attr + 1 : 0; 1486 1487 error = g_part_probe(gp, cp, depth); 1488 if (error) 1489 goto fail; 1490 1491 table = gp->softc; 1492 1493 /* If we're nested, get the absolute sector offset on disk. */ 1494 if (table->gpt_depth) { 1495 error = g_getattr("PART::offset", cp, &attr); 1496 if (error) 1497 goto fail; 1498 table->gpt_offset = attr; 1499 } 1500 1501 /* 1502 * Synthesize a disk geometry. Some partitioning schemes 1503 * depend on it and since some file systems need it even 1504 * when the partitition scheme doesn't, we do it here in 1505 * scheme-independent code. 1506 */ 1507 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1508 1509 error = G_PART_READ(table, cp); 1510 if (error) 1511 goto fail; 1512 1513 g_topology_lock(); 1514 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1515 if (!entry->gpe_internal) 1516 g_part_new_provider(gp, table, entry); 1517 } 1518 1519 root_mount_rel(rht); 1520 g_access(cp, -1, 0, 0); 1521 return (gp); 1522 1523 fail: 1524 g_topology_lock(); 1525 root_mount_rel(rht); 1526 g_access(cp, -1, 0, 0); 1527 g_part_wither(gp, error); 1528 return (NULL); 1529} 1530 1531/* 1532 * Geom methods. 1533 */ 1534 1535static int 1536g_part_access(struct g_provider *pp, int dr, int dw, int de) 1537{ 1538 struct g_consumer *cp; 1539 1540 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1541 dw, de)); 1542 1543 cp = LIST_FIRST(&pp->geom->consumer); 1544 1545 /* We always gain write-exclusive access. */ 1546 return (g_access(cp, dr, dw, dw + de)); 1547} 1548 1549static void 1550g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1551 struct g_consumer *cp, struct g_provider *pp) 1552{ 1553 char buf[64]; 1554 struct g_part_entry *entry; 1555 struct g_part_table *table; 1556 1557 KASSERT(sb != NULL && gp != NULL, (__func__)); 1558 table = gp->softc; 1559 1560 if (indent == NULL) { 1561 KASSERT(cp == NULL && pp != NULL, (__func__)); 1562 entry = pp->private; 1563 if (entry == NULL) 1564 return; 1565 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 1566 (uintmax_t)entry->gpe_offset, 1567 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1568 /* 1569 * libdisk compatibility quirk - the scheme dumps the 1570 * slicer name and partition type in a way that is 1571 * compatible with libdisk. When libdisk is not used 1572 * anymore, this should go away. 1573 */ 1574 G_PART_DUMPCONF(table, entry, sb, indent); 1575 } else if (cp != NULL) { /* Consumer configuration. */ 1576 KASSERT(pp == NULL, (__func__)); 1577 /* none */ 1578 } else if (pp != NULL) { /* Provider configuration. */ 1579 entry = pp->private; 1580 if (entry == NULL) 1581 return; 1582 sbuf_printf(sb, "%s<start>%ju</start>\n", indent, 1583 (uintmax_t)entry->gpe_start); 1584 sbuf_printf(sb, "%s<end>%ju</end>\n", indent, 1585 (uintmax_t)entry->gpe_end); 1586 sbuf_printf(sb, "%s<index>%u</index>\n", indent, 1587 entry->gpe_index); 1588 sbuf_printf(sb, "%s<type>%s</type>\n", indent, 1589 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1590 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 1591 (uintmax_t)entry->gpe_offset); 1592 sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 1593 (uintmax_t)pp->mediasize); 1594 G_PART_DUMPCONF(table, entry, sb, indent); 1595 } else { /* Geom configuration. */ 1596 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 1597 table->gpt_scheme->name); 1598 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 1599 table->gpt_entries); 1600 sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 1601 (uintmax_t)table->gpt_first); 1602 sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 1603 (uintmax_t)table->gpt_last); 1604 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 1605 table->gpt_sectors); 1606 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 1607 table->gpt_heads); 1608 G_PART_DUMPCONF(table, NULL, sb, indent); 1609 } 1610} 1611 1612static void 1613g_part_orphan(struct g_consumer *cp) 1614{ 1615 struct g_provider *pp; 1616 1617 pp = cp->provider; 1618 KASSERT(pp != NULL, (__func__)); 1619 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 1620 g_topology_assert(); 1621 1622 KASSERT(pp->error != 0, (__func__)); 1623 g_part_wither(cp->geom, pp->error); 1624} 1625 1626static void 1627g_part_spoiled(struct g_consumer *cp) 1628{ 1629 1630 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 1631 g_topology_assert(); 1632 1633 g_part_wither(cp->geom, ENXIO); 1634} 1635 1636static void 1637g_part_start(struct bio *bp) 1638{ 1639 struct bio *bp2; 1640 struct g_consumer *cp; 1641 struct g_geom *gp; 1642 struct g_part_entry *entry; 1643 struct g_part_table *table; 1644 struct g_kerneldump *gkd; 1645 struct g_provider *pp; 1646 1647 pp = bp->bio_to; 1648 gp = pp->geom; 1649 table = gp->softc; 1650 cp = LIST_FIRST(&gp->consumer); 1651 1652 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 1653 pp->name)); 1654 1655 entry = pp->private; 1656 if (entry == NULL) { 1657 g_io_deliver(bp, ENXIO); 1658 return; 1659 } 1660 1661 switch(bp->bio_cmd) { 1662 case BIO_DELETE: 1663 case BIO_READ: 1664 case BIO_WRITE: 1665 if (bp->bio_offset >= pp->mediasize) { 1666 g_io_deliver(bp, EIO); 1667 return; 1668 } 1669 bp2 = g_clone_bio(bp); 1670 if (bp2 == NULL) { 1671 g_io_deliver(bp, ENOMEM); 1672 return; 1673 } 1674 if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 1675 bp2->bio_length = pp->mediasize - bp2->bio_offset; 1676 bp2->bio_done = g_std_done; 1677 bp2->bio_offset += entry->gpe_offset; 1678 g_io_request(bp2, cp); 1679 return; 1680 case BIO_FLUSH: 1681 break; 1682 case BIO_GETATTR: 1683 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 1684 return; 1685 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 1686 return; 1687 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 1688 return; 1689 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 1690 return; 1691 if (g_handleattr_int(bp, "PART::offset", 1692 table->gpt_offset + entry->gpe_start)) 1693 return; 1694 if (g_handleattr_str(bp, "PART::scheme", 1695 table->gpt_scheme->name)) 1696 return; 1697 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 1698 /* 1699 * Check that the partition is suitable for kernel 1700 * dumps. Typically only swap partitions should be 1701 * used. 1702 */ 1703 if (!G_PART_DUMPTO(table, entry)) { 1704 g_io_deliver(bp, ENXIO); 1705 return; 1706 } 1707 gkd = (struct g_kerneldump *)bp->bio_data; 1708 if (gkd->offset >= pp->mediasize) { 1709 g_io_deliver(bp, EIO); 1710 return; 1711 } 1712 if (gkd->offset + gkd->length > pp->mediasize) 1713 gkd->length = pp->mediasize - gkd->offset; 1714 gkd->offset += entry->gpe_offset; 1715 } 1716 break; 1717 default: 1718 g_io_deliver(bp, EOPNOTSUPP); 1719 return; 1720 } 1721 1722 bp2 = g_clone_bio(bp); 1723 if (bp2 == NULL) { 1724 g_io_deliver(bp, ENOMEM); 1725 return; 1726 } 1727 bp2->bio_done = g_std_done; 1728 g_io_request(bp2, cp); 1729} 1730 1731static void 1732g_part_init(struct g_class *mp) 1733{ 1734 1735 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list); 1736} 1737 1738static void 1739g_part_fini(struct g_class *mp) 1740{ 1741 1742 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list); 1743} 1744 1745static void 1746g_part_unload_event(void *arg, int flag) 1747{ 1748 struct g_consumer *cp; 1749 struct g_geom *gp; 1750 struct g_provider *pp; 1751 struct g_part_scheme *scheme; 1752 struct g_part_table *table; 1753 uintptr_t *xchg; 1754 int acc, error; 1755 1756 if (flag == EV_CANCEL) 1757 return; 1758 1759 xchg = arg; 1760 error = 0; 1761 scheme = (void *)(*xchg); 1762 1763 g_topology_assert(); 1764 1765 LIST_FOREACH(gp, &g_part_class.geom, geom) { 1766 table = gp->softc; 1767 if (table->gpt_scheme != scheme) 1768 continue; 1769 1770 acc = 0; 1771 LIST_FOREACH(pp, &gp->provider, provider) 1772 acc += pp->acr + pp->acw + pp->ace; 1773 LIST_FOREACH(cp, &gp->consumer, consumer) 1774 acc += cp->acr + cp->acw + cp->ace; 1775 1776 if (!acc) 1777 g_part_wither(gp, ENOSYS); 1778 else 1779 error = EBUSY; 1780 } 1781 1782 if (!error) 1783 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 1784 1785 *xchg = error; 1786} 1787 1788int 1789g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) 1790{ 1791 uintptr_t arg; 1792 int error; 1793 1794 switch (type) { 1795 case MOD_LOAD: 1796 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list); 1797 1798 error = g_retaste(&g_part_class); 1799 if (error) 1800 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 1801 break; 1802 case MOD_UNLOAD: 1803 arg = (uintptr_t)scheme; 1804 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, 1805 NULL); 1806 if (!error) 1807 error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg; 1808 break; 1809 default: 1810 error = EOPNOTSUPP; 1811 break; 1812 } 1813 1814 return (error); 1815} 1816