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