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