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