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