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