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