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