g_part.c revision 207178
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 207178 2010-04-25 00:54:11Z 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_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 917static int 918g_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 964static int 965g_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 971static int 972g_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 978static int 979g_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 1061static int 1062g_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 1107static int 1108g_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 error = G_PART_READ(table, cp); 1172 if (error) 1173 goto fail; 1174 1175 g_topology_lock(); 1176 1177 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1178 if (!entry->gpe_internal) 1179 g_part_new_provider(gp, table, entry); 1180 } 1181 1182 table->gpt_opened = 0; 1183 g_access(cp, -1, -1, -1); 1184 return (0); 1185 1186fail: 1187 g_topology_lock(); 1188 gctl_error(req, "%d", error); 1189 return (error); 1190} 1191 1192static void 1193g_part_wither(struct g_geom *gp, int error) 1194{ 1195 struct g_part_entry *entry; 1196 struct g_part_table *table; 1197 1198 table = gp->softc; 1199 if (table != NULL) { 1200 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 1201 LIST_REMOVE(entry, gpe_entry); 1202 g_free(entry); 1203 } 1204 if (gp->softc != NULL) { 1205 kobj_delete((kobj_t)gp->softc, M_GEOM); 1206 gp->softc = NULL; 1207 } 1208 } 1209 g_wither_geom(gp, error); 1210} 1211 1212/* 1213 * Class methods. 1214 */ 1215 1216static void 1217g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 1218{ 1219 struct g_part_parms gpp; 1220 struct g_part_table *table; 1221 struct gctl_req_arg *ap; 1222 const char *p; 1223 enum g_part_ctl ctlreq; 1224 unsigned int i, mparms, oparms, parm; 1225 int auto_commit, close_on_error; 1226 int error, len, modifies; 1227 1228 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1229 g_topology_assert(); 1230 1231 ctlreq = G_PART_CTL_NONE; 1232 modifies = 1; 1233 mparms = 0; 1234 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1235 switch (*verb) { 1236 case 'a': 1237 if (!strcmp(verb, "add")) { 1238 ctlreq = G_PART_CTL_ADD; 1239 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1240 G_PART_PARM_START | G_PART_PARM_TYPE; 1241 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1242 } 1243 break; 1244 case 'b': 1245 if (!strcmp(verb, "bootcode")) { 1246 ctlreq = G_PART_CTL_BOOTCODE; 1247 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; 1248 } 1249 break; 1250 case 'c': 1251 if (!strcmp(verb, "commit")) { 1252 ctlreq = G_PART_CTL_COMMIT; 1253 mparms |= G_PART_PARM_GEOM; 1254 modifies = 0; 1255 } else if (!strcmp(verb, "create")) { 1256 ctlreq = G_PART_CTL_CREATE; 1257 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1258 oparms |= G_PART_PARM_ENTRIES; 1259 } 1260 break; 1261 case 'd': 1262 if (!strcmp(verb, "delete")) { 1263 ctlreq = G_PART_CTL_DELETE; 1264 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1265 } else if (!strcmp(verb, "destroy")) { 1266 ctlreq = G_PART_CTL_DESTROY; 1267 mparms |= G_PART_PARM_GEOM; 1268 } 1269 break; 1270 case 'm': 1271 if (!strcmp(verb, "modify")) { 1272 ctlreq = G_PART_CTL_MODIFY; 1273 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1274 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1275 } else if (!strcmp(verb, "move")) { 1276 ctlreq = G_PART_CTL_MOVE; 1277 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1278 } 1279 break; 1280 case 'r': 1281 if (!strcmp(verb, "recover")) { 1282 ctlreq = G_PART_CTL_RECOVER; 1283 mparms |= G_PART_PARM_GEOM; 1284 } else if (!strcmp(verb, "resize")) { 1285 ctlreq = G_PART_CTL_RESIZE; 1286 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX | 1287 G_PART_PARM_SIZE; 1288 } 1289 break; 1290 case 's': 1291 if (!strcmp(verb, "set")) { 1292 ctlreq = G_PART_CTL_SET; 1293 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1294 G_PART_PARM_INDEX; 1295 } 1296 break; 1297 case 'u': 1298 if (!strcmp(verb, "undo")) { 1299 ctlreq = G_PART_CTL_UNDO; 1300 mparms |= G_PART_PARM_GEOM; 1301 modifies = 0; 1302 } else if (!strcmp(verb, "unset")) { 1303 ctlreq = G_PART_CTL_UNSET; 1304 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM | 1305 G_PART_PARM_INDEX; 1306 } 1307 break; 1308 } 1309 if (ctlreq == G_PART_CTL_NONE) { 1310 gctl_error(req, "%d verb '%s'", EINVAL, verb); 1311 return; 1312 } 1313 1314 bzero(&gpp, sizeof(gpp)); 1315 for (i = 0; i < req->narg; i++) { 1316 ap = &req->arg[i]; 1317 parm = 0; 1318 switch (ap->name[0]) { 1319 case 'a': 1320 if (!strcmp(ap->name, "attrib")) 1321 parm = G_PART_PARM_ATTRIB; 1322 break; 1323 case 'b': 1324 if (!strcmp(ap->name, "bootcode")) 1325 parm = G_PART_PARM_BOOTCODE; 1326 break; 1327 case 'c': 1328 if (!strcmp(ap->name, "class")) 1329 continue; 1330 break; 1331 case 'e': 1332 if (!strcmp(ap->name, "entries")) 1333 parm = G_PART_PARM_ENTRIES; 1334 break; 1335 case 'f': 1336 if (!strcmp(ap->name, "flags")) 1337 parm = G_PART_PARM_FLAGS; 1338 break; 1339 case 'g': 1340 if (!strcmp(ap->name, "geom")) 1341 parm = G_PART_PARM_GEOM; 1342 break; 1343 case 'i': 1344 if (!strcmp(ap->name, "index")) 1345 parm = G_PART_PARM_INDEX; 1346 break; 1347 case 'l': 1348 if (!strcmp(ap->name, "label")) 1349 parm = G_PART_PARM_LABEL; 1350 break; 1351 case 'o': 1352 if (!strcmp(ap->name, "output")) 1353 parm = G_PART_PARM_OUTPUT; 1354 break; 1355 case 'p': 1356 if (!strcmp(ap->name, "provider")) 1357 parm = G_PART_PARM_PROVIDER; 1358 break; 1359 case 's': 1360 if (!strcmp(ap->name, "scheme")) 1361 parm = G_PART_PARM_SCHEME; 1362 else if (!strcmp(ap->name, "size")) 1363 parm = G_PART_PARM_SIZE; 1364 else if (!strcmp(ap->name, "start")) 1365 parm = G_PART_PARM_START; 1366 break; 1367 case 't': 1368 if (!strcmp(ap->name, "type")) 1369 parm = G_PART_PARM_TYPE; 1370 break; 1371 case 'v': 1372 if (!strcmp(ap->name, "verb")) 1373 continue; 1374 else if (!strcmp(ap->name, "version")) 1375 parm = G_PART_PARM_VERSION; 1376 break; 1377 } 1378 if ((parm & (mparms | oparms)) == 0) { 1379 gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1380 return; 1381 } 1382 if (parm == G_PART_PARM_BOOTCODE) 1383 p = gctl_get_param(req, ap->name, &len); 1384 else 1385 p = gctl_get_asciiparam(req, ap->name); 1386 if (p == NULL) { 1387 gctl_error(req, "%d param '%s'", ENOATTR, ap->name); 1388 return; 1389 } 1390 switch (parm) { 1391 case G_PART_PARM_ATTRIB: 1392 error = g_part_parm_str(p, &gpp.gpp_attrib); 1393 break; 1394 case G_PART_PARM_BOOTCODE: 1395 gpp.gpp_codeptr = p; 1396 gpp.gpp_codesize = len; 1397 error = 0; 1398 break; 1399 case G_PART_PARM_ENTRIES: 1400 error = g_part_parm_uint(p, &gpp.gpp_entries); 1401 break; 1402 case G_PART_PARM_FLAGS: 1403 if (p[0] == '\0') 1404 continue; 1405 error = g_part_parm_str(p, &gpp.gpp_flags); 1406 break; 1407 case G_PART_PARM_GEOM: 1408 error = g_part_parm_geom(p, &gpp.gpp_geom); 1409 break; 1410 case G_PART_PARM_INDEX: 1411 error = g_part_parm_uint(p, &gpp.gpp_index); 1412 break; 1413 case G_PART_PARM_LABEL: 1414 /* An empty label is always valid. */ 1415 gpp.gpp_label = p; 1416 error = 0; 1417 break; 1418 case G_PART_PARM_OUTPUT: 1419 error = 0; /* Write-only parameter */ 1420 break; 1421 case G_PART_PARM_PROVIDER: 1422 error = g_part_parm_provider(p, &gpp.gpp_provider); 1423 break; 1424 case G_PART_PARM_SCHEME: 1425 error = g_part_parm_scheme(p, &gpp.gpp_scheme); 1426 break; 1427 case G_PART_PARM_SIZE: 1428 error = g_part_parm_quad(p, &gpp.gpp_size); 1429 break; 1430 case G_PART_PARM_START: 1431 error = g_part_parm_quad(p, &gpp.gpp_start); 1432 break; 1433 case G_PART_PARM_TYPE: 1434 error = g_part_parm_str(p, &gpp.gpp_type); 1435 break; 1436 case G_PART_PARM_VERSION: 1437 error = g_part_parm_uint(p, &gpp.gpp_version); 1438 break; 1439 default: 1440 error = EDOOFUS; 1441 break; 1442 } 1443 if (error) { 1444 gctl_error(req, "%d %s '%s'", error, ap->name, p); 1445 return; 1446 } 1447 gpp.gpp_parms |= parm; 1448 } 1449 if ((gpp.gpp_parms & mparms) != mparms) { 1450 parm = mparms - (gpp.gpp_parms & mparms); 1451 gctl_error(req, "%d param '%x'", ENOATTR, parm); 1452 return; 1453 } 1454 1455 /* Obtain permissions if possible/necessary. */ 1456 close_on_error = 0; 1457 table = NULL; 1458 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1459 table = gpp.gpp_geom->softc; 1460 if (table != NULL && !table->gpt_opened) { 1461 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1462 1, 1, 1); 1463 if (error) { 1464 gctl_error(req, "%d geom '%s'", error, 1465 gpp.gpp_geom->name); 1466 return; 1467 } 1468 table->gpt_opened = 1; 1469 close_on_error = 1; 1470 } 1471 } 1472 1473 /* Allow the scheme to check or modify the parameters. */ 1474 if (table != NULL) { 1475 error = G_PART_PRECHECK(table, ctlreq, &gpp); 1476 if (error) { 1477 gctl_error(req, "%d pre-check failed", error); 1478 goto out; 1479 } 1480 } else 1481 error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1482 1483 switch (ctlreq) { 1484 case G_PART_CTL_NONE: 1485 panic("%s", __func__); 1486 case G_PART_CTL_ADD: 1487 error = g_part_ctl_add(req, &gpp); 1488 break; 1489 case G_PART_CTL_BOOTCODE: 1490 error = g_part_ctl_bootcode(req, &gpp); 1491 break; 1492 case G_PART_CTL_COMMIT: 1493 error = g_part_ctl_commit(req, &gpp); 1494 break; 1495 case G_PART_CTL_CREATE: 1496 error = g_part_ctl_create(req, &gpp); 1497 break; 1498 case G_PART_CTL_DELETE: 1499 error = g_part_ctl_delete(req, &gpp); 1500 break; 1501 case G_PART_CTL_DESTROY: 1502 error = g_part_ctl_destroy(req, &gpp); 1503 break; 1504 case G_PART_CTL_MODIFY: 1505 error = g_part_ctl_modify(req, &gpp); 1506 break; 1507 case G_PART_CTL_MOVE: 1508 error = g_part_ctl_move(req, &gpp); 1509 break; 1510 case G_PART_CTL_RECOVER: 1511 error = g_part_ctl_recover(req, &gpp); 1512 break; 1513 case G_PART_CTL_RESIZE: 1514 error = g_part_ctl_resize(req, &gpp); 1515 break; 1516 case G_PART_CTL_SET: 1517 error = g_part_ctl_setunset(req, &gpp, 1); 1518 break; 1519 case G_PART_CTL_UNDO: 1520 error = g_part_ctl_undo(req, &gpp); 1521 break; 1522 case G_PART_CTL_UNSET: 1523 error = g_part_ctl_setunset(req, &gpp, 0); 1524 break; 1525 } 1526 1527 /* Implement automatic commit. */ 1528 if (!error) { 1529 auto_commit = (modifies && 1530 (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1531 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1532 if (auto_commit) { 1533 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__)); 1534 error = g_part_ctl_commit(req, &gpp); 1535 } 1536 } 1537 1538 out: 1539 if (error && close_on_error) { 1540 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1541 table->gpt_opened = 0; 1542 } 1543} 1544 1545static int 1546g_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1547 struct g_geom *gp) 1548{ 1549 1550 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1551 g_topology_assert(); 1552 1553 g_part_wither(gp, EINVAL); 1554 return (0); 1555} 1556 1557static struct g_geom * 1558g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1559{ 1560 struct g_consumer *cp; 1561 struct g_geom *gp; 1562 struct g_part_entry *entry; 1563 struct g_part_table *table; 1564 struct root_hold_token *rht; 1565 int attr, depth; 1566 int error; 1567 1568 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1569 g_topology_assert(); 1570 1571 /* Skip providers that are already open for writing. */ 1572 if (pp->acw > 0) 1573 return (NULL); 1574 1575 /* 1576 * Create a GEOM with consumer and hook it up to the provider. 1577 * With that we become part of the topology. Optain read access 1578 * to the provider. 1579 */ 1580 gp = g_new_geomf(mp, "%s", pp->name); 1581 cp = g_new_consumer(gp); 1582 error = g_attach(cp, pp); 1583 if (error == 0) 1584 error = g_access(cp, 1, 0, 0); 1585 if (error != 0) { 1586 g_part_wither(gp, error); 1587 return (NULL); 1588 } 1589 1590 rht = root_mount_hold(mp->name); 1591 g_topology_unlock(); 1592 1593 /* 1594 * Short-circuit the whole probing galore when there's no 1595 * media present. 1596 */ 1597 if (pp->mediasize == 0 || pp->sectorsize == 0) { 1598 error = ENODEV; 1599 goto fail; 1600 } 1601 1602 /* Make sure we can nest and if so, determine our depth. */ 1603 error = g_getattr("PART::isleaf", cp, &attr); 1604 if (!error && attr) { 1605 error = ENODEV; 1606 goto fail; 1607 } 1608 error = g_getattr("PART::depth", cp, &attr); 1609 depth = (!error) ? attr + 1 : 0; 1610 1611 error = g_part_probe(gp, cp, depth); 1612 if (error) 1613 goto fail; 1614 1615 table = gp->softc; 1616 1617 /* 1618 * Synthesize a disk geometry. Some partitioning schemes 1619 * depend on it and since some file systems need it even 1620 * when the partitition scheme doesn't, we do it here in 1621 * scheme-independent code. 1622 */ 1623 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1624 1625 error = G_PART_READ(table, cp); 1626 if (error) 1627 goto fail; 1628 1629 g_topology_lock(); 1630 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 1631 if (!entry->gpe_internal) 1632 g_part_new_provider(gp, table, entry); 1633 } 1634 1635 root_mount_rel(rht); 1636 g_access(cp, -1, 0, 0); 1637 return (gp); 1638 1639 fail: 1640 g_topology_lock(); 1641 root_mount_rel(rht); 1642 g_access(cp, -1, 0, 0); 1643 g_part_wither(gp, error); 1644 return (NULL); 1645} 1646 1647/* 1648 * Geom methods. 1649 */ 1650 1651static int 1652g_part_access(struct g_provider *pp, int dr, int dw, int de) 1653{ 1654 struct g_consumer *cp; 1655 1656 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1657 dw, de)); 1658 1659 cp = LIST_FIRST(&pp->geom->consumer); 1660 1661 /* We always gain write-exclusive access. */ 1662 return (g_access(cp, dr, dw, dw + de)); 1663} 1664 1665static void 1666g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1667 struct g_consumer *cp, struct g_provider *pp) 1668{ 1669 char buf[64]; 1670 struct g_part_entry *entry; 1671 struct g_part_table *table; 1672 1673 KASSERT(sb != NULL && gp != NULL, (__func__)); 1674 table = gp->softc; 1675 1676 if (indent == NULL) { 1677 KASSERT(cp == NULL && pp != NULL, (__func__)); 1678 entry = pp->private; 1679 if (entry == NULL) 1680 return; 1681 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 1682 (uintmax_t)entry->gpe_offset, 1683 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1684 /* 1685 * libdisk compatibility quirk - the scheme dumps the 1686 * slicer name and partition type in a way that is 1687 * compatible with libdisk. When libdisk is not used 1688 * anymore, this should go away. 1689 */ 1690 G_PART_DUMPCONF(table, entry, sb, indent); 1691 } else if (cp != NULL) { /* Consumer configuration. */ 1692 KASSERT(pp == NULL, (__func__)); 1693 /* none */ 1694 } else if (pp != NULL) { /* Provider configuration. */ 1695 entry = pp->private; 1696 if (entry == NULL) 1697 return; 1698 sbuf_printf(sb, "%s<start>%ju</start>\n", indent, 1699 (uintmax_t)entry->gpe_start); 1700 sbuf_printf(sb, "%s<end>%ju</end>\n", indent, 1701 (uintmax_t)entry->gpe_end); 1702 sbuf_printf(sb, "%s<index>%u</index>\n", indent, 1703 entry->gpe_index); 1704 sbuf_printf(sb, "%s<type>%s</type>\n", indent, 1705 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1706 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 1707 (uintmax_t)entry->gpe_offset); 1708 sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 1709 (uintmax_t)pp->mediasize); 1710 G_PART_DUMPCONF(table, entry, sb, indent); 1711 } else { /* Geom configuration. */ 1712 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 1713 table->gpt_scheme->name); 1714 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 1715 table->gpt_entries); 1716 sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 1717 (uintmax_t)table->gpt_first); 1718 sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 1719 (uintmax_t)table->gpt_last); 1720 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 1721 table->gpt_sectors); 1722 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 1723 table->gpt_heads); 1724 G_PART_DUMPCONF(table, NULL, sb, indent); 1725 } 1726} 1727 1728static void 1729g_part_orphan(struct g_consumer *cp) 1730{ 1731 struct g_provider *pp; 1732 1733 pp = cp->provider; 1734 KASSERT(pp != NULL, (__func__)); 1735 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 1736 g_topology_assert(); 1737 1738 KASSERT(pp->error != 0, (__func__)); 1739 g_part_wither(cp->geom, pp->error); 1740} 1741 1742static void 1743g_part_spoiled(struct g_consumer *cp) 1744{ 1745 1746 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 1747 g_topology_assert(); 1748 1749 g_part_wither(cp->geom, ENXIO); 1750} 1751 1752static void 1753g_part_start(struct bio *bp) 1754{ 1755 struct bio *bp2; 1756 struct g_consumer *cp; 1757 struct g_geom *gp; 1758 struct g_part_entry *entry; 1759 struct g_part_table *table; 1760 struct g_kerneldump *gkd; 1761 struct g_provider *pp; 1762 1763 pp = bp->bio_to; 1764 gp = pp->geom; 1765 table = gp->softc; 1766 cp = LIST_FIRST(&gp->consumer); 1767 1768 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 1769 pp->name)); 1770 1771 entry = pp->private; 1772 if (entry == NULL) { 1773 g_io_deliver(bp, ENXIO); 1774 return; 1775 } 1776 1777 switch(bp->bio_cmd) { 1778 case BIO_DELETE: 1779 case BIO_READ: 1780 case BIO_WRITE: 1781 if (bp->bio_offset >= pp->mediasize) { 1782 g_io_deliver(bp, EIO); 1783 return; 1784 } 1785 bp2 = g_clone_bio(bp); 1786 if (bp2 == NULL) { 1787 g_io_deliver(bp, ENOMEM); 1788 return; 1789 } 1790 if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 1791 bp2->bio_length = pp->mediasize - bp2->bio_offset; 1792 bp2->bio_done = g_std_done; 1793 bp2->bio_offset += entry->gpe_offset; 1794 g_io_request(bp2, cp); 1795 return; 1796 case BIO_FLUSH: 1797 break; 1798 case BIO_GETATTR: 1799 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 1800 return; 1801 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 1802 return; 1803 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 1804 return; 1805 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 1806 return; 1807 if (g_handleattr_str(bp, "PART::scheme", 1808 table->gpt_scheme->name)) 1809 return; 1810 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 1811 /* 1812 * Check that the partition is suitable for kernel 1813 * dumps. Typically only swap partitions should be 1814 * used. 1815 */ 1816 if (!G_PART_DUMPTO(table, entry)) { 1817 g_io_deliver(bp, ENODEV); 1818 printf("GEOM_PART: Partition '%s' not suitable" 1819 " for kernel dumps (wrong type?)\n", 1820 pp->name); 1821 return; 1822 } 1823 gkd = (struct g_kerneldump *)bp->bio_data; 1824 if (gkd->offset >= pp->mediasize) { 1825 g_io_deliver(bp, EIO); 1826 return; 1827 } 1828 if (gkd->offset + gkd->length > pp->mediasize) 1829 gkd->length = pp->mediasize - gkd->offset; 1830 gkd->offset += entry->gpe_offset; 1831 } 1832 break; 1833 default: 1834 g_io_deliver(bp, EOPNOTSUPP); 1835 return; 1836 } 1837 1838 bp2 = g_clone_bio(bp); 1839 if (bp2 == NULL) { 1840 g_io_deliver(bp, ENOMEM); 1841 return; 1842 } 1843 bp2->bio_done = g_std_done; 1844 g_io_request(bp2, cp); 1845} 1846 1847static void 1848g_part_init(struct g_class *mp) 1849{ 1850 1851 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list); 1852} 1853 1854static void 1855g_part_fini(struct g_class *mp) 1856{ 1857 1858 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list); 1859} 1860 1861static void 1862g_part_unload_event(void *arg, int flag) 1863{ 1864 struct g_consumer *cp; 1865 struct g_geom *gp; 1866 struct g_provider *pp; 1867 struct g_part_scheme *scheme; 1868 struct g_part_table *table; 1869 uintptr_t *xchg; 1870 int acc, error; 1871 1872 if (flag == EV_CANCEL) 1873 return; 1874 1875 xchg = arg; 1876 error = 0; 1877 scheme = (void *)(*xchg); 1878 1879 g_topology_assert(); 1880 1881 LIST_FOREACH(gp, &g_part_class.geom, geom) { 1882 table = gp->softc; 1883 if (table->gpt_scheme != scheme) 1884 continue; 1885 1886 acc = 0; 1887 LIST_FOREACH(pp, &gp->provider, provider) 1888 acc += pp->acr + pp->acw + pp->ace; 1889 LIST_FOREACH(cp, &gp->consumer, consumer) 1890 acc += cp->acr + cp->acw + cp->ace; 1891 1892 if (!acc) 1893 g_part_wither(gp, ENOSYS); 1894 else 1895 error = EBUSY; 1896 } 1897 1898 if (!error) 1899 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 1900 1901 *xchg = error; 1902} 1903 1904int 1905g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) 1906{ 1907 uintptr_t arg; 1908 int error; 1909 1910 switch (type) { 1911 case MOD_LOAD: 1912 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list); 1913 1914 error = g_retaste(&g_part_class); 1915 if (error) 1916 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); 1917 break; 1918 case MOD_UNLOAD: 1919 arg = (uintptr_t)scheme; 1920 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, 1921 NULL); 1922 if (!error) 1923 error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg; 1924 break; 1925 default: 1926 error = EOPNOTSUPP; 1927 break; 1928 } 1929 1930 return (error); 1931} 1932