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