g_part.c revision 207094
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 207094 2010-04-23 03:11:39Z marcel $"); 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 { "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 */ 106static g_ctl_req_t g_part_ctlreq; 107static g_ctl_destroy_geom_t g_part_destroy_geom; 108static g_fini_t g_part_fini; 109static g_init_t g_part_init; 110static g_taste_t g_part_taste; 111 112static g_access_t g_part_access; 113static g_dumpconf_t g_part_dumpconf; 114static g_orphan_t g_part_orphan; 115static g_spoiled_t g_part_spoiled; 116static g_start_t g_part_start; 117 118static 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 135DECLARE_GEOM_CLASS(g_part_class, g_part); 136 137/* 138 * Support functions. 139 */ 140 141static void g_part_wither(struct g_geom *, int); 142 143const char * 144g_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 157void 158g_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 183static void 184g_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 230struct g_part_entry * 231g_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 261static void 262g_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 298static int 299g_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 318static int 319g_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 333static int 334g_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 346static int 347g_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 363static int 364g_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 373static int 374g_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 386static int 387g_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 424done: 425 return ((scheme == NULL) ? ENXIO : 0); 426} 427 428/* 429 * Control request functions. 430 */ 431 432static int 433g_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 543static int 544g_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 585static int 586g_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 662fail: 663 g_topology_lock(); 664 gctl_error(req, "%d", error); 665 return (error); 666} 667 668static int 669g_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 782fail: 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 795static int 796g_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 855static int 856g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp) 857{ 858 struct g_geom *gp; 859 struct g_part_entry *entry; 860 struct g_part_table *null, *table; 861 struct sbuf *sb; 862 int error; 863 864 gp = gpp->gpp_geom; 865 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 866 g_topology_assert(); 867 868 table = gp->softc; 869 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 870 if (entry->gpe_deleted || entry->gpe_internal) 871 continue; 872 gctl_error(req, "%d", EBUSY); 873 return (EBUSY); 874 } 875 876 error = G_PART_DESTROY(table, gpp); 877 if (error) { 878 gctl_error(req, "%d", error); 879 return (error); 880 } 881 882 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM, 883 M_WAITOK); 884 null = gp->softc; 885 null->gpt_gp = gp; 886 null->gpt_scheme = &g_part_null_scheme; 887 LIST_INIT(&null->gpt_entry); 888 null->gpt_depth = table->gpt_depth; 889 null->gpt_opened = table->gpt_opened; 890 null->gpt_smhead = table->gpt_smhead; 891 null->gpt_smtail = table->gpt_smtail; 892 893 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 894 LIST_REMOVE(entry, gpe_entry); 895 g_free(entry); 896 } 897 kobj_delete((kobj_t)table, M_GEOM); 898 899 /* Provide feedback if so requested. */ 900 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 901 sb = sbuf_new_auto(); 902 sbuf_printf(sb, "%s destroyed\n", gp->name); 903 sbuf_finish(sb); 904 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 905 sbuf_delete(sb); 906 } 907 return (0); 908} 909 910static int 911g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp) 912{ 913 struct g_geom *gp; 914 struct g_part_entry *entry; 915 struct g_part_table *table; 916 struct sbuf *sb; 917 int error; 918 919 gp = gpp->gpp_geom; 920 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 921 g_topology_assert(); 922 923 table = gp->softc; 924 925 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 926 if (entry->gpe_deleted || entry->gpe_internal) 927 continue; 928 if (entry->gpe_index == gpp->gpp_index) 929 break; 930 } 931 if (entry == NULL) { 932 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 933 return (ENOENT); 934 } 935 936 error = G_PART_MODIFY(table, entry, gpp); 937 if (error) { 938 gctl_error(req, "%d", error); 939 return (error); 940 } 941 942 if (!entry->gpe_created) 943 entry->gpe_modified = 1; 944 945 /* Provide feedback if so requested. */ 946 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 947 sb = sbuf_new_auto(); 948 G_PART_FULLNAME(table, entry, sb, gp->name); 949 sbuf_cat(sb, " modified\n"); 950 sbuf_finish(sb); 951 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 952 sbuf_delete(sb); 953 } 954 return (0); 955} 956 957static int 958g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) 959{ 960 gctl_error(req, "%d verb 'move'", ENOSYS); 961 return (ENOSYS); 962} 963 964static int 965g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) 966{ 967 gctl_error(req, "%d verb 'recover'", ENOSYS); 968 return (ENOSYS); 969} 970 971static int 972g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) 973{ 974 struct g_geom *gp; 975 struct g_provider *pp; 976 struct g_part_entry *pe, *entry; 977 struct g_part_table *table; 978 struct sbuf *sb; 979 quad_t end; 980 int error; 981 982 gp = gpp->gpp_geom; 983 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 984 g_topology_assert(); 985 table = gp->softc; 986 987 /* check gpp_index */ 988 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 989 if (entry->gpe_deleted || entry->gpe_internal) 990 continue; 991 if (entry->gpe_index == gpp->gpp_index) 992 break; 993 } 994 if (entry == NULL) { 995 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 996 return (ENOENT); 997 } 998 999 /* check gpp_size */ 1000 end = entry->gpe_start + gpp->gpp_size - 1; 1001 if (gpp->gpp_size < 1 || end > table->gpt_last) { 1002 gctl_error(req, "%d size '%jd'", EINVAL, 1003 (intmax_t)gpp->gpp_size); 1004 return (EINVAL); 1005 } 1006 1007 LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) { 1008 if (pe->gpe_deleted || pe->gpe_internal || pe == entry) 1009 continue; 1010 if (end >= pe->gpe_start && end <= pe->gpe_end) { 1011 gctl_error(req, "%d end '%jd'", ENOSPC, 1012 (intmax_t)end); 1013 return (ENOSPC); 1014 } 1015 if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) { 1016 gctl_error(req, "%d size '%jd'", ENOSPC, 1017 (intmax_t)gpp->gpp_size); 1018 return (ENOSPC); 1019 } 1020 } 1021 1022 pp = entry->gpe_pp; 1023 if ((g_debugflags & 16) == 0 && 1024 (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) { 1025 gctl_error(req, "%d", EBUSY); 1026 return (EBUSY); 1027 } 1028 1029 error = G_PART_RESIZE(table, entry, gpp); 1030 if (error) { 1031 gctl_error(req, "%d", error); 1032 return (error); 1033 } 1034 1035 if (!entry->gpe_created) 1036 entry->gpe_modified = 1; 1037 1038 /* update mediasize of changed provider */ 1039 pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 1040 pp->sectorsize; 1041 1042 /* Provide feedback if so requested. */ 1043 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1044 sb = sbuf_new_auto(); 1045 G_PART_FULLNAME(table, entry, sb, gp->name); 1046 sbuf_cat(sb, " resized\n"); 1047 sbuf_finish(sb); 1048 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1049 sbuf_delete(sb); 1050 } 1051 return (0); 1052} 1053 1054static int 1055g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, 1056 unsigned int set) 1057{ 1058 struct g_geom *gp; 1059 struct g_part_entry *entry; 1060 struct g_part_table *table; 1061 struct sbuf *sb; 1062 int error; 1063 1064 gp = gpp->gpp_geom; 1065 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1066 g_topology_assert(); 1067 1068 table = gp->softc; 1069 1070 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1071 if (entry->gpe_deleted || entry->gpe_internal) 1072 continue; 1073 if (entry->gpe_index == gpp->gpp_index) 1074 break; 1075 } 1076 if (entry == NULL) { 1077 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 1078 return (ENOENT); 1079 } 1080 1081 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set); 1082 if (error) { 1083 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib); 1084 return (error); 1085 } 1086 1087 /* Provide feedback if so requested. */ 1088 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 1089 sb = sbuf_new_auto(); 1090 G_PART_FULLNAME(table, entry, sb, gp->name); 1091 sbuf_printf(sb, " has %s %sset\n", gpp->gpp_attrib, 1092 (set) ? "" : "un"); 1093 sbuf_finish(sb); 1094 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 1095 sbuf_delete(sb); 1096 } 1097 return (0); 1098} 1099 1100static int 1101g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) 1102{ 1103 struct g_consumer *cp; 1104 struct g_provider *pp; 1105 struct g_geom *gp; 1106 struct g_part_entry *entry, *tmp; 1107 struct g_part_table *table; 1108 int error, reprobe; 1109 1110 gp = gpp->gpp_geom; 1111 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 1112 g_topology_assert(); 1113 1114 table = gp->softc; 1115 if (!table->gpt_opened) { 1116 gctl_error(req, "%d", EPERM); 1117 return (EPERM); 1118 } 1119 1120 cp = LIST_FIRST(&gp->consumer); 1121 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 1122 entry->gpe_modified = 0; 1123 if (entry->gpe_created) { 1124 pp = entry->gpe_pp; 1125 if (pp != NULL) { 1126 pp->private = NULL; 1127 entry->gpe_pp = NULL; 1128 g_wither_provider(pp, ENXIO); 1129 } 1130 entry->gpe_deleted = 1; 1131 } 1132 if (entry->gpe_deleted) { 1133 LIST_REMOVE(entry, gpe_entry); 1134 g_free(entry); 1135 } 1136 } 1137 1138 g_topology_unlock(); 1139 1140 reprobe = (table->gpt_scheme == &g_part_null_scheme || 1141 table->gpt_created) ? 1 : 0; 1142 1143 if (reprobe) { 1144 if (!LIST_EMPTY(&table->gpt_entry)) { 1145 error = EBUSY; 1146 goto fail; 1147 } 1148 error = g_part_probe(gp, cp, table->gpt_depth); 1149 if (error) { 1150 g_topology_lock(); 1151 g_access(cp, -1, -1, -1); 1152 g_part_wither(gp, error); 1153 return (0); 1154 } 1155 table = gp->softc; 1156 } 1157 1158 error = G_PART_READ(table, cp); 1159 if (error) 1160 goto fail; 1161 1162 g_topology_lock(); 1163 1164 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1165 if (!entry->gpe_internal) 1166 g_part_new_provider(gp, table, entry); 1167 } 1168 1169 table->gpt_opened = 0; 1170 g_access(cp, -1, -1, -1); 1171 return (0); 1172 1173fail: 1174 g_topology_lock(); 1175 gctl_error(req, "%d", error); 1176 return (error); 1177} 1178 1179static void 1180g_part_wither(struct g_geom *gp, int error) 1181{ 1182 struct g_part_entry *entry; 1183 struct g_part_table *table; 1184 1185 table = gp->softc; 1186 if (table != NULL) { 1187 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1188 LIST_REMOVE(entry, gpe_entry); 1189 g_free(entry); 1190 } 1191 if (gp->softc != NULL) { 1192 kobj_delete((kobj_t)gp->softc, M_GEOM); 1193 gp->softc = NULL; 1194 } 1195 } 1196 g_wither_geom(gp, error); 1197} 1198 1199/* 1200 * Class methods. 1201 */ 1202 1203static void 1204g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 1205{ 1206 struct g_part_parms gpp; 1207 struct g_part_table *table; 1208 struct gctl_req_arg *ap; 1209 const char *p; 1210 enum g_part_ctl ctlreq; 1211 unsigned int i, mparms, oparms, parm; 1212 int auto_commit, close_on_error; 1213 int error, len, modifies; 1214 1215 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1216 g_topology_assert(); 1217 1218 ctlreq = G_PART_CTL_NONE; 1219 modifies = 1; 1220 mparms = 0; 1221 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1222 switch (*verb) { 1223 case 'a': 1224 if (!strcmp(verb, "add")) { 1225 ctlreq = G_PART_CTL_ADD; 1226 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1227 G_PART_PARM_START | G_PART_PARM_TYPE; 1228 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1229 } 1230 break; 1231 case 'b': 1232 if (!strcmp(verb, "bootcode")) { 1233 ctlreq = G_PART_CTL_BOOTCODE; 1234 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; 1235 } 1236 break; 1237 case 'c': 1238 if (!strcmp(verb, "commit")) { 1239 ctlreq = G_PART_CTL_COMMIT; 1240 mparms |= G_PART_PARM_GEOM; 1241 modifies = 0; 1242 } else if (!strcmp(verb, "create")) { 1243 ctlreq = G_PART_CTL_CREATE; 1244 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1245 oparms |= G_PART_PARM_ENTRIES; 1246 } 1247 break; 1248 case 'd': 1249 if (!strcmp(verb, "delete")) { 1250 ctlreq = G_PART_CTL_DELETE; 1251 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1252 } else if (!strcmp(verb, "destroy")) { 1253 ctlreq = G_PART_CTL_DESTROY; 1254 mparms |= G_PART_PARM_GEOM; 1255 } 1256 break; 1257 case 'm': 1258 if (!strcmp(verb, "modify")) { 1259 ctlreq = G_PART_CTL_MODIFY; 1260 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1261 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1262 } else if (!strcmp(verb, "move")) { 1263 ctlreq = G_PART_CTL_MOVE; 1264 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1265 } 1266 break; 1267 case 'r': 1268 if (!strcmp(verb, "recover")) { 1269 ctlreq = G_PART_CTL_RECOVER; 1270 mparms |= G_PART_PARM_GEOM; 1271 } else if (!strcmp(verb, "resize")) { 1272 ctlreq = G_PART_CTL_RESIZE; 1273 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX | 1274 G_PART_PARM_SIZE; 1275 } 1276 break; 1277 case 's': 1278 if (!strcmp(verb, "set")) { 1279 ctlreq = G_PART_CTL_SET; 1280 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1281 G_PART_PARM_INDEX; 1282 } 1283 break; 1284 case 'u': 1285 if (!strcmp(verb, "undo")) { 1286 ctlreq = G_PART_CTL_UNDO; 1287 mparms |= G_PART_PARM_GEOM; 1288 modifies = 0; 1289 } else if (!strcmp(verb, "unset")) { 1290 ctlreq = G_PART_CTL_UNSET; 1291 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1292 G_PART_PARM_INDEX; 1293 } 1294 break; 1295 } 1296 if (ctlreq == G_PART_CTL_NONE) { 1297 gctl_error(req, "%d verb '%s'", EINVAL, verb); 1298 return; 1299 } 1300 1301 bzero(&gpp, sizeof(gpp)); 1302 for (i = 0; i < req->narg; i++) { 1303 ap = &req->arg[i]; 1304 parm = 0; 1305 switch (ap->name[0]) { 1306 case 'a': 1307 if (!strcmp(ap->name, "attrib")) 1308 parm = G_PART_PARM_ATTRIB; 1309 break; 1310 case 'b': 1311 if (!strcmp(ap->name, "bootcode")) 1312 parm = G_PART_PARM_BOOTCODE; 1313 break; 1314 case 'c': 1315 if (!strcmp(ap->name, "class")) 1316 continue; 1317 break; 1318 case 'e': 1319 if (!strcmp(ap->name, "entries")) 1320 parm = G_PART_PARM_ENTRIES; 1321 break; 1322 case 'f': 1323 if (!strcmp(ap->name, "flags")) 1324 parm = G_PART_PARM_FLAGS; 1325 break; 1326 case 'g': 1327 if (!strcmp(ap->name, "geom")) 1328 parm = G_PART_PARM_GEOM; 1329 break; 1330 case 'i': 1331 if (!strcmp(ap->name, "index")) 1332 parm = G_PART_PARM_INDEX; 1333 break; 1334 case 'l': 1335 if (!strcmp(ap->name, "label")) 1336 parm = G_PART_PARM_LABEL; 1337 break; 1338 case 'o': 1339 if (!strcmp(ap->name, "output")) 1340 parm = G_PART_PARM_OUTPUT; 1341 break; 1342 case 'p': 1343 if (!strcmp(ap->name, "provider")) 1344 parm = G_PART_PARM_PROVIDER; 1345 break; 1346 case 's': 1347 if (!strcmp(ap->name, "scheme")) 1348 parm = G_PART_PARM_SCHEME; 1349 else if (!strcmp(ap->name, "size")) 1350 parm = G_PART_PARM_SIZE; 1351 else if (!strcmp(ap->name, "start")) 1352 parm = G_PART_PARM_START; 1353 break; 1354 case 't': 1355 if (!strcmp(ap->name, "type")) 1356 parm = G_PART_PARM_TYPE; 1357 break; 1358 case 'v': 1359 if (!strcmp(ap->name, "verb")) 1360 continue; 1361 else if (!strcmp(ap->name, "version")) 1362 parm = G_PART_PARM_VERSION; 1363 break; 1364 } 1365 if ((parm & (mparms | oparms)) == 0) { 1366 gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1367 return; 1368 } 1369 if (parm == G_PART_PARM_BOOTCODE) 1370 p = gctl_get_param(req, ap->name, &len); 1371 else 1372 p = gctl_get_asciiparam(req, ap->name); 1373 if (p == NULL) { 1374 gctl_error(req, "%d param '%s'", ENOATTR, ap->name); 1375 return; 1376 } 1377 switch (parm) { 1378 case G_PART_PARM_ATTRIB: 1379 error = g_part_parm_str(p, &gpp.gpp_attrib); 1380 break; 1381 case G_PART_PARM_BOOTCODE: 1382 gpp.gpp_codeptr = p; 1383 gpp.gpp_codesize = len; 1384 error = 0; 1385 break; 1386 case G_PART_PARM_ENTRIES: 1387 error = g_part_parm_uint(p, &gpp.gpp_entries); 1388 break; 1389 case G_PART_PARM_FLAGS: 1390 if (p[0] == '\0') 1391 continue; 1392 error = g_part_parm_str(p, &gpp.gpp_flags); 1393 break; 1394 case G_PART_PARM_GEOM: 1395 error = g_part_parm_geom(p, &gpp.gpp_geom); 1396 break; 1397 case G_PART_PARM_INDEX: 1398 error = g_part_parm_uint(p, &gpp.gpp_index); 1399 break; 1400 case G_PART_PARM_LABEL: 1401 /* An empty label is always valid. */ 1402 gpp.gpp_label = p; 1403 error = 0; 1404 break; 1405 case G_PART_PARM_OUTPUT: 1406 error = 0; /* Write-only parameter */ 1407 break; 1408 case G_PART_PARM_PROVIDER: 1409 error = g_part_parm_provider(p, &gpp.gpp_provider); 1410 break; 1411 case G_PART_PARM_SCHEME: 1412 error = g_part_parm_scheme(p, &gpp.gpp_scheme); 1413 break; 1414 case G_PART_PARM_SIZE: 1415 error = g_part_parm_quad(p, &gpp.gpp_size); 1416 break; 1417 case G_PART_PARM_START: 1418 error = g_part_parm_quad(p, &gpp.gpp_start); 1419 break; 1420 case G_PART_PARM_TYPE: 1421 error = g_part_parm_str(p, &gpp.gpp_type); 1422 break; 1423 case G_PART_PARM_VERSION: 1424 error = g_part_parm_uint(p, &gpp.gpp_version); 1425 break; 1426 default: 1427 error = EDOOFUS; 1428 break; 1429 } 1430 if (error) { 1431 gctl_error(req, "%d %s '%s'", error, ap->name, p); 1432 return; 1433 } 1434 gpp.gpp_parms |= parm; 1435 } 1436 if ((gpp.gpp_parms & mparms) != mparms) { 1437 parm = mparms - (gpp.gpp_parms & mparms); 1438 gctl_error(req, "%d param '%x'", ENOATTR, parm); 1439 return; 1440 } 1441 1442 /* Obtain permissions if possible/necessary. */ 1443 close_on_error = 0; 1444 table = NULL; 1445 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1446 table = gpp.gpp_geom->softc; 1447 if (table != NULL && !table->gpt_opened) { 1448 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1449 1, 1, 1); 1450 if (error) { 1451 gctl_error(req, "%d geom '%s'", error, 1452 gpp.gpp_geom->name); 1453 return; 1454 } 1455 table->gpt_opened = 1; 1456 close_on_error = 1; 1457 } 1458 } 1459 1460 /* Allow the scheme to check or modify the parameters. */ 1461 if (table != NULL) { 1462 error = G_PART_PRECHECK(table, ctlreq, &gpp); 1463 if (error) { 1464 gctl_error(req, "%d pre-check failed", error); 1465 goto out; 1466 } 1467 } else 1468 error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1469 1470 switch (ctlreq) { 1471 case G_PART_CTL_NONE: 1472 panic("%s", __func__); 1473 case G_PART_CTL_ADD: 1474 error = g_part_ctl_add(req, &gpp); 1475 break; 1476 case G_PART_CTL_BOOTCODE: 1477 error = g_part_ctl_bootcode(req, &gpp); 1478 break; 1479 case G_PART_CTL_COMMIT: 1480 error = g_part_ctl_commit(req, &gpp); 1481 break; 1482 case G_PART_CTL_CREATE: 1483 error = g_part_ctl_create(req, &gpp); 1484 break; 1485 case G_PART_CTL_DELETE: 1486 error = g_part_ctl_delete(req, &gpp); 1487 break; 1488 case G_PART_CTL_DESTROY: 1489 error = g_part_ctl_destroy(req, &gpp); 1490 break; 1491 case G_PART_CTL_MODIFY: 1492 error = g_part_ctl_modify(req, &gpp); 1493 break; 1494 case G_PART_CTL_MOVE: 1495 error = g_part_ctl_move(req, &gpp); 1496 break; 1497 case G_PART_CTL_RECOVER: 1498 error = g_part_ctl_recover(req, &gpp); 1499 break; 1500 case G_PART_CTL_RESIZE: 1501 error = g_part_ctl_resize(req, &gpp); 1502 break; 1503 case G_PART_CTL_SET: 1504 error = g_part_ctl_setunset(req, &gpp, 1); 1505 break; 1506 case G_PART_CTL_UNDO: 1507 error = g_part_ctl_undo(req, &gpp); 1508 break; 1509 case G_PART_CTL_UNSET: 1510 error = g_part_ctl_setunset(req, &gpp, 0); 1511 break; 1512 } 1513 1514 /* Implement automatic commit. */ 1515 if (!error) { 1516 auto_commit = (modifies && 1517 (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1518 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1519 if (auto_commit) { 1520 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__)); 1521 error = g_part_ctl_commit(req, &gpp); 1522 } 1523 } 1524 1525 out: 1526 if (error && close_on_error) { 1527 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1528 table->gpt_opened = 0; 1529 } 1530} 1531 1532static int 1533g_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1534 struct g_geom *gp) 1535{ 1536 1537 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1538 g_topology_assert(); 1539 1540 g_part_wither(gp, EINVAL); 1541 return (0); 1542} 1543 1544static struct g_geom * 1545g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1546{ 1547 struct g_consumer *cp; 1548 struct g_geom *gp; 1549 struct g_part_entry *entry; 1550 struct g_part_table *table; 1551 struct root_hold_token *rht; 1552 int attr, depth; 1553 int error; 1554 1555 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1556 g_topology_assert(); 1557 1558 /* Skip providers that are already open for writing. */ 1559 if (pp->acw > 0) 1560 return (NULL); 1561 1562 /* 1563 * Create a GEOM with consumer and hook it up to the provider. 1564 * With that we become part of the topology. Optain read access 1565 * to the provider. 1566 */ 1567 gp = g_new_geomf(mp, "%s", pp->name); 1568 cp = g_new_consumer(gp); 1569 error = g_attach(cp, pp); 1570 if (error == 0) 1571 error = g_access(cp, 1, 0, 0); 1572 if (error != 0) { 1573 g_part_wither(gp, error); 1574 return (NULL); 1575 } 1576 1577 rht = root_mount_hold(mp->name); 1578 g_topology_unlock(); 1579 1580 /* 1581 * Short-circuit the whole probing galore when there's no 1582 * media present. 1583 */ 1584 if (pp->mediasize == 0 || pp->sectorsize == 0) { 1585 error = ENODEV; 1586 goto fail; 1587 } 1588 1589 /* Make sure we can nest and if so, determine our depth. */ 1590 error = g_getattr("PART::isleaf", cp, &attr); 1591 if (!error && attr) { 1592 error = ENODEV; 1593 goto fail; 1594 } 1595 error = g_getattr("PART::depth", cp, &attr); 1596 depth = (!error) ? attr + 1 : 0; 1597 1598 error = g_part_probe(gp, cp, depth); 1599 if (error) 1600 goto fail; 1601 1602 table = gp->softc; 1603 1604 /* 1605 * Synthesize a disk geometry. Some partitioning schemes 1606 * depend on it and since some file systems need it even 1607 * when the partitition scheme doesn't, we do it here in 1608 * scheme-independent code. 1609 */ 1610 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1611 1612 error = G_PART_READ(table, cp); 1613 if (error) 1614 goto fail; 1615 1616 g_topology_lock(); 1617 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1618 if (!entry->gpe_internal) 1619 g_part_new_provider(gp, table, entry); 1620 } 1621 1622 root_mount_rel(rht); 1623 g_access(cp, -1, 0, 0); 1624 return (gp); 1625 1626 fail: 1627 g_topology_lock(); 1628 root_mount_rel(rht); 1629 g_access(cp, -1, 0, 0); 1630 g_part_wither(gp, error); 1631 return (NULL); 1632} 1633 1634/* 1635 * Geom methods. 1636 */ 1637 1638static int 1639g_part_access(struct g_provider *pp, int dr, int dw, int de) 1640{ 1641 struct g_consumer *cp; 1642 1643 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1644 dw, de)); 1645 1646 cp = LIST_FIRST(&pp->geom->consumer); 1647 1648 /* We always gain write-exclusive access. */ 1649 return (g_access(cp, dr, dw, dw + de)); 1650} 1651 1652static void 1653g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1654 struct g_consumer *cp, struct g_provider *pp) 1655{ 1656 char buf[64]; 1657 struct g_part_entry *entry; 1658 struct g_part_table *table; 1659 1660 KASSERT(sb != NULL && gp != NULL, (__func__)); 1661 table = gp->softc; 1662 1663 if (indent == NULL) { 1664 KASSERT(cp == NULL && pp != NULL, (__func__)); 1665 entry = pp->private; 1666 if (entry == NULL) 1667 return; 1668 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 1669 (uintmax_t)entry->gpe_offset, 1670 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1671 /* 1672 * libdisk compatibility quirk - the scheme dumps the 1673 * slicer name and partition type in a way that is 1674 * compatible with libdisk. When libdisk is not used 1675 * anymore, this should go away. 1676 */ 1677 G_PART_DUMPCONF(table, entry, sb, indent); 1678 } else if (cp != NULL) { /* Consumer configuration. */ 1679 KASSERT(pp == NULL, (__func__)); 1680 /* none */ 1681 } else if (pp != NULL) { /* Provider configuration. */ 1682 entry = pp->private; 1683 if (entry == NULL) 1684 return; 1685 sbuf_printf(sb, "%s<start>%ju</start>\n", indent, 1686 (uintmax_t)entry->gpe_start); 1687 sbuf_printf(sb, "%s<end>%ju</end>\n", indent, 1688 (uintmax_t)entry->gpe_end); 1689 sbuf_printf(sb, "%s<index>%u</index>\n", indent, 1690 entry->gpe_index); 1691 sbuf_printf(sb, "%s<type>%s</type>\n", indent, 1692 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1693 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 1694 (uintmax_t)entry->gpe_offset); 1695 sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 1696 (uintmax_t)pp->mediasize); 1697 G_PART_DUMPCONF(table, entry, sb, indent); 1698 } else { /* Geom configuration. */ 1699 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 1700 table->gpt_scheme->name); 1701 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 1702 table->gpt_entries); 1703 sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 1704 (uintmax_t)table->gpt_first); 1705 sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 1706 (uintmax_t)table->gpt_last); 1707 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 1708 table->gpt_sectors); 1709 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 1710 table->gpt_heads); 1711 G_PART_DUMPCONF(table, NULL, sb, indent); 1712 } 1713} 1714 1715static void 1716g_part_orphan(struct g_consumer *cp) 1717{ 1718 struct g_provider *pp; 1719 1720 pp = cp->provider; 1721 KASSERT(pp != NULL, (__func__)); 1722 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 1723 g_topology_assert(); 1724 1725 KASSERT(pp->error != 0, (__func__)); 1726 g_part_wither(cp->geom, pp->error); 1727} 1728 1729static void 1730g_part_spoiled(struct g_consumer *cp) 1731{ 1732 1733 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 1734 g_topology_assert(); 1735 1736 g_part_wither(cp->geom, ENXIO); 1737} 1738 1739static void 1740g_part_start(struct bio *bp) 1741{ 1742 struct bio *bp2; 1743 struct g_consumer *cp; 1744 struct g_geom *gp; 1745 struct g_part_entry *entry; 1746 struct g_part_table *table; 1747 struct g_kerneldump *gkd; 1748 struct g_provider *pp; 1749 1750 pp = bp->bio_to; 1751 gp = pp->geom; 1752 table = gp->softc; 1753 cp = LIST_FIRST(&gp->consumer); 1754 1755 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 1756 pp->name)); 1757 1758 entry = pp->private; 1759 if (entry == NULL) { 1760 g_io_deliver(bp, ENXIO); 1761 return; 1762 } 1763 1764 switch(bp->bio_cmd) { 1765 case BIO_DELETE: 1766 case BIO_READ: 1767 case BIO_WRITE: 1768 if (bp->bio_offset >= pp->mediasize) { 1769 g_io_deliver(bp, EIO); 1770 return; 1771 } 1772 bp2 = g_clone_bio(bp); 1773 if (bp2 == NULL) { 1774 g_io_deliver(bp, ENOMEM); 1775 return; 1776 } 1777 if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 1778 bp2->bio_length = pp->mediasize - bp2->bio_offset; 1779 bp2->bio_done = g_std_done; 1780 bp2->bio_offset += entry->gpe_offset; 1781 g_io_request(bp2, cp); 1782 return; 1783 case BIO_FLUSH: 1784 break; 1785 case BIO_GETATTR: 1786 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 1787 return; 1788 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 1789 return; 1790 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 1791 return; 1792 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 1793 return; 1794 if (g_handleattr_str(bp, "PART::scheme", 1795 table->gpt_scheme->name)) 1796 return; 1797 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 1798 /* 1799 * Check that the partition is suitable for kernel 1800 * dumps. Typically only swap partitions should be 1801 * used. 1802 */ 1803 if (!G_PART_DUMPTO(table, entry)) { 1804 g_io_deliver(bp, ENODEV); 1805 printf("GEOM_PART: Partition '%s' not suitable" 1806 " for kernel dumps (wrong type?)\n", 1807 pp->name); 1808 return; 1809 } 1810 gkd = (struct g_kerneldump *)bp->bio_data; 1811 if (gkd->offset >= pp->mediasize) { 1812 g_io_deliver(bp, EIO); 1813 return; 1814 } 1815 if (gkd->offset + gkd->length > pp->mediasize) 1816 gkd->length = pp->mediasize - gkd->offset; 1817 gkd->offset += entry->gpe_offset; 1818 } 1819 break; 1820 default: 1821 g_io_deliver(bp, EOPNOTSUPP); 1822 return; 1823 } 1824 1825 bp2 = g_clone_bio(bp); 1826 if (bp2 == NULL) { 1827 g_io_deliver(bp, ENOMEM); 1828 return; 1829 } 1830 bp2->bio_done = g_std_done; 1831 g_io_request(bp2, cp); 1832} 1833 1834static void 1835g_part_init(struct g_class *mp) 1836{ 1837 1838 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list); 1839} 1840 1841static void 1842g_part_fini(struct g_class *mp) 1843{ 1844 1845 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list); 1846} 1847 1848static void 1849g_part_unload_event(void *arg, int flag) 1850{ 1851 struct g_consumer *cp; 1852 struct g_geom *gp; 1853 struct g_provider *pp; 1854 struct g_part_scheme *scheme; 1855 struct g_part_table *table; 1856 uintptr_t *xchg; 1857 int acc, error; 1858 1859 if (flag == EV_CANCEL) 1860 return; 1861 1862 xchg = arg; 1863 error = 0; 1864 scheme = (void *)(*xchg); 1865 1866 g_topology_assert(); 1867 1868 LIST_FOREACH(gp, &g_part_class.geom, geom) { 1869 table = gp->softc; 1870 if (table->gpt_scheme != scheme) 1871 continue; 1872 1873 acc = 0; 1874 LIST_FOREACH(pp, &gp->provider, provider) 1875 acc += pp->acr + pp->acw + pp->ace; 1876 LIST_FOREACH(cp, &gp->consumer, consumer) 1877 acc += cp->acr + cp->acw + cp->ace; 1878 1879 if (!acc) 1880 g_part_wither(gp, ENOSYS); 1881 else 1882 error = EBUSY; 1883 } 1884 1885 if (!error) 1886 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 1887 1888 *xchg = error; 1889} 1890 1891int 1892g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) 1893{ 1894 uintptr_t arg; 1895 int error; 1896 1897 switch (type) { 1898 case MOD_LOAD: 1899 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list); 1900 1901 error = g_retaste(&g_part_class); 1902 if (error) 1903 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 1904 break; 1905 case MOD_UNLOAD: 1906 arg = (uintptr_t)scheme; 1907 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, 1908 NULL); 1909 if (!error) 1910 error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg; 1911 break; 1912 default: 1913 error = EOPNOTSUPP; 1914 break; 1915 } 1916 1917 return (error); 1918} 1919