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