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