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