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