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