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