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