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