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