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