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