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