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