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