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