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