g_part.c revision 172857
198944Sobrien/*- 298944Sobrien * Copyright (c) 2002, 2005, 2006, 2007 Marcel Moolenaar 398944Sobrien * All rights reserved. 498944Sobrien * 598944Sobrien * Redistribution and use in source and binary forms, with or without 698944Sobrien * modification, are permitted provided that the following conditions 798944Sobrien * are met: 898944Sobrien * 998944Sobrien * 1. Redistributions of source code must retain the above copyright 1098944Sobrien * notice, this list of conditions and the following disclaimer. 1198944Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1298944Sobrien * notice, this list of conditions and the following disclaimer in the 1398944Sobrien * documentation and/or other materials provided with the distribution. 1498944Sobrien * 1598944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1698944Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1798944Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1898944Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1998944Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2098944Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2198944Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2298944Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2398944Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2498944Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25130803Smarcel */ 26130803Smarcel 2798944Sobrien#include <sys/cdefs.h> 2898944Sobrien__FBSDID("$FreeBSD: head/sys/geom/part/g_part.c 172857 2007-10-21 20:02:57Z marcel $"); 2998944Sobrien 3098944Sobrien#include <sys/param.h> 3198944Sobrien#include <sys/bio.h> 3298944Sobrien#include <sys/diskmbr.h> 3398944Sobrien#include <sys/endian.h> 3498944Sobrien#include <sys/kernel.h> 3598944Sobrien#include <sys/kobj.h> 3698944Sobrien#include <sys/limits.h> 3798944Sobrien#include <sys/lock.h> 3898944Sobrien#include <sys/malloc.h> 3998944Sobrien#include <sys/mutex.h> 4098944Sobrien#include <sys/queue.h> 4198944Sobrien#include <sys/sbuf.h> 4298944Sobrien#include <sys/systm.h> 4398944Sobrien#include <sys/uuid.h> 4498944Sobrien#include <geom/geom.h> 4598944Sobrien#include <geom/geom_ctl.h> 4698944Sobrien#include <geom/part/g_part.h> 4798944Sobrien 4898944Sobrien#include "g_part_if.h" 4998944Sobrien 5098944Sobrienstatic kobj_method_t g_part_null_methods[] = { 5198944Sobrien { 0, 0 } 5298944Sobrien}; 5398944Sobrien 5498944Sobrienstatic struct g_part_scheme g_part_null_scheme = { 5598944Sobrien "n/a", 5698944Sobrien g_part_null_methods, 5798944Sobrien sizeof(struct g_part_table), 5898944Sobrien}; 5998944SobrienG_PART_SCHEME_DECLARE(g_part_null_scheme); 6098944Sobrien 6198944SobrienSET_DECLARE(g_part_scheme_set, struct g_part_scheme); 6298944Sobrien 63struct g_part_alias_list { 64 const char *lexeme; 65 enum g_part_alias alias; 66} g_part_alias_list[G_PART_ALIAS_COUNT] = { 67 { "efi", G_PART_ALIAS_EFI }, 68 { "freebsd", G_PART_ALIAS_FREEBSD }, 69 { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP }, 70 { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS }, 71 { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM }, 72 { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS }, 73 { "mbr", G_PART_ALIAS_MBR } 74}; 75 76/* 77 * The GEOM partitioning class. 78 */ 79static g_ctl_req_t g_part_ctlreq; 80static g_ctl_destroy_geom_t g_part_destroy_geom; 81static g_taste_t g_part_taste; 82 83static g_access_t g_part_access; 84static g_dumpconf_t g_part_dumpconf; 85static g_orphan_t g_part_orphan; 86static g_spoiled_t g_part_spoiled; 87static g_start_t g_part_start; 88 89static struct g_class g_part_class = { 90 .name = "PART", 91 .version = G_VERSION, 92 /* Class methods. */ 93 .ctlreq = g_part_ctlreq, 94 .destroy_geom = g_part_destroy_geom, 95 .taste = g_part_taste, 96 /* Geom methods. */ 97 .access = g_part_access, 98 .dumpconf = g_part_dumpconf, 99 .orphan = g_part_orphan, 100 .spoiled = g_part_spoiled, 101 .start = g_part_start, 102}; 103 104DECLARE_GEOM_CLASS(g_part_class, g_part); 105 106enum g_part_ctl { 107 G_PART_CTL_NONE, 108 G_PART_CTL_ADD, 109 G_PART_CTL_COMMIT, 110 G_PART_CTL_CREATE, 111 G_PART_CTL_DELETE, 112 G_PART_CTL_DESTROY, 113 G_PART_CTL_MODIFY, 114 G_PART_CTL_MOVE, 115 G_PART_CTL_RECOVER, 116 G_PART_CTL_RESIZE, 117 G_PART_CTL_UNDO 118}; 119 120/* 121 * Support functions. 122 */ 123 124static void g_part_wither(struct g_geom *, int); 125 126const char * 127g_part_alias_name(enum g_part_alias alias) 128{ 129 int i; 130 131 for (i = 0; i < G_PART_ALIAS_COUNT; i++) { 132 if (g_part_alias_list[i].alias != alias) 133 continue; 134 return (g_part_alias_list[i].lexeme); 135 } 136 137 return (NULL); 138} 139 140void 141g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs, 142 u_int *bestheads) 143{ 144 static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 }; 145 off_t chs, cylinders; 146 u_int heads; 147 int idx; 148 149 *bestchs = 0; 150 *bestheads = 0; 151 for (idx = 0; candidate_heads[idx] != 0; idx++) { 152 heads = candidate_heads[idx]; 153 cylinders = blocks / heads / sectors; 154 if (cylinders < heads || cylinders < sectors) 155 break; 156 if (cylinders > 1023) 157 continue; 158 chs = cylinders * heads * sectors; 159 if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) { 160 *bestchs = chs; 161 *bestheads = heads; 162 } 163 } 164} 165 166static void 167g_part_geometry(struct g_part_table *table, struct g_consumer *cp, 168 off_t blocks) 169{ 170 static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 }; 171 off_t chs, bestchs; 172 u_int heads, sectors; 173 int idx; 174 175 if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || 176 sectors < 1 || sectors > 63 || 177 g_getattr("GEOM::fwheads", cp, &heads) != 0 || 178 heads < 1 || heads > 255) { 179 table->gpt_fixgeom = 0; 180 table->gpt_heads = 0; 181 table->gpt_sectors = 0; 182 bestchs = 0; 183 for (idx = 0; candidate_sectors[idx] != 0; idx++) { 184 sectors = candidate_sectors[idx]; 185 g_part_geometry_heads(blocks, sectors, &chs, &heads); 186 if (chs == 0) 187 continue; 188 /* 189 * Prefer a geometry with sectors > 1, but only if 190 * it doesn't bump down the numbver of heads to 1. 191 */ 192 if (chs > bestchs || (chs == bestchs && heads > 1 && 193 table->gpt_sectors == 1)) { 194 bestchs = chs; 195 table->gpt_heads = heads; 196 table->gpt_sectors = sectors; 197 } 198 } 199 /* 200 * If we didn't find a geometry at all, then the disk is 201 * too big. This means we can use the maximum number of 202 * heads and sectors. 203 */ 204 if (bestchs == 0) { 205 table->gpt_heads = 255; 206 table->gpt_sectors = 63; 207 } 208 } else { 209 table->gpt_fixgeom = 1; 210 table->gpt_heads = heads; 211 table->gpt_sectors = sectors; 212 } 213} 214 215struct g_part_entry * 216g_part_new_entry(struct g_part_table *table, int index, quad_t start, 217 quad_t end) 218{ 219 struct g_part_entry *entry, *last; 220 221 last = NULL; 222 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 223 if (entry->gpe_index == index) 224 break; 225 if (entry->gpe_index > index) { 226 entry = NULL; 227 break; 228 } 229 last = entry; 230 } 231 if (entry == NULL) { 232 entry = g_malloc(table->gpt_scheme->gps_entrysz, 233 M_WAITOK | M_ZERO); 234 entry->gpe_index = index; 235 if (last == NULL) 236 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 237 else 238 LIST_INSERT_AFTER(last, entry, gpe_entry); 239 } 240 entry->gpe_start = start; 241 entry->gpe_end = end; 242 return (entry); 243} 244 245static void 246g_part_new_provider(struct g_geom *gp, struct g_part_table *table, 247 struct g_part_entry *entry) 248{ 249 char buf[32]; 250 struct g_consumer *cp; 251 struct g_provider *pp; 252 253 cp = LIST_FIRST(&gp->consumer); 254 pp = cp->provider; 255 256 entry->gpe_offset = entry->gpe_start * pp->sectorsize; 257 258 if (entry->gpe_pp == NULL) { 259 entry->gpe_pp = g_new_providerf(gp, "%s%s", gp->name, 260 G_PART_NAME(table, entry, buf, sizeof(buf))); 261 entry->gpe_pp->private = entry; /* Close the circle. */ 262 } 263 entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */ 264 entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * 265 pp->sectorsize; 266 entry->gpe_pp->sectorsize = pp->sectorsize; 267 entry->gpe_pp->flags = pp->flags & G_PF_CANDELETE; 268 if (pp->stripesize > 0) { 269 entry->gpe_pp->stripesize = pp->stripesize; 270 entry->gpe_pp->stripeoffset = (pp->stripeoffset + 271 entry->gpe_offset) % pp->stripesize; 272 } 273 g_error_provider(entry->gpe_pp, 0); 274} 275 276static int 277g_part_parm_geom(const char *p, struct g_geom **v) 278{ 279 struct g_geom *gp; 280 281 LIST_FOREACH(gp, &g_part_class.geom, geom) { 282 if (!strcmp(p, gp->name)) 283 break; 284 } 285 if (gp == NULL) 286 return (EINVAL); 287 *v = gp; 288 return (0); 289} 290 291static int 292g_part_parm_provider(const char *p, struct g_provider **v) 293{ 294 struct g_provider *pp; 295 296 pp = g_provider_by_name(p); 297 if (pp == NULL) 298 return (EINVAL); 299 *v = pp; 300 return (0); 301} 302 303static int 304g_part_parm_quad(const char *p, quad_t *v) 305{ 306 char *x; 307 quad_t q; 308 309 q = strtoq(p, &x, 0); 310 if (*x != '\0' || q < 0) 311 return (EINVAL); 312 *v = q; 313 return (0); 314} 315 316static int 317g_part_parm_scheme(const char *p, struct g_part_scheme **v) 318{ 319 struct g_part_scheme **iter, *s; 320 321 s = NULL; 322 SET_FOREACH(iter, g_part_scheme_set) { 323 if ((*iter)->name == NULL) 324 continue; 325 if (!strcasecmp((*iter)->name, p)) { 326 s = *iter; 327 break; 328 } 329 } 330 if (s == NULL) 331 return (EINVAL); 332 *v = s; 333 return (0); 334} 335 336static int 337g_part_parm_str(const char *p, const char **v) 338{ 339 340 if (p[0] == '\0') 341 return (EINVAL); 342 *v = p; 343 return (0); 344} 345 346static int 347g_part_parm_uint(const char *p, u_int *v) 348{ 349 char *x; 350 long l; 351 352 l = strtol(p, &x, 0); 353 if (*x != '\0' || l < 0 || l > INT_MAX) 354 return (EINVAL); 355 *v = (unsigned int)l; 356 return (0); 357} 358 359static int 360g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth) 361{ 362 struct g_part_scheme **iter, *scheme; 363 struct g_part_table *table; 364 int pri, probe; 365 366 table = gp->softc; 367 scheme = (table != NULL) ? table->gpt_scheme : &g_part_null_scheme; 368 pri = (scheme != &g_part_null_scheme) ? G_PART_PROBE(table, cp) : 369 INT_MIN; 370 if (pri == 0) 371 goto done; 372 if (pri > 0) { /* error */ 373 scheme = &g_part_null_scheme; 374 pri = INT_MIN; 375 } 376 377 SET_FOREACH(iter, g_part_scheme_set) { 378 if ((*iter) == &g_part_null_scheme) 379 continue; 380 table = (void *)kobj_create((kobj_class_t)(*iter), M_GEOM, 381 M_WAITOK); 382 table->gpt_gp = gp; 383 table->gpt_scheme = *iter; 384 table->gpt_depth = depth; 385 probe = G_PART_PROBE(table, cp); 386 if (probe <= 0 && probe > pri) { 387 pri = probe; 388 scheme = *iter; 389 if (gp->softc != NULL) 390 kobj_delete((kobj_t)gp->softc, M_GEOM); 391 gp->softc = table; 392 if (pri == 0) 393 goto done; 394 } else 395 kobj_delete((kobj_t)table, M_GEOM); 396 } 397 398done: 399 return ((scheme == &g_part_null_scheme) ? ENXIO : 0); 400} 401 402/* 403 * Control request functions. 404 */ 405 406static int 407g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) 408{ 409 char buf[32]; 410 struct g_geom *gp; 411 struct g_provider *pp; 412 struct g_part_entry *delent, *last, *entry; 413 struct g_part_table *table; 414 struct sbuf *sb; 415 quad_t end; 416 unsigned int index; 417 int error; 418 419 gp = gpp->gpp_geom; 420 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 421 g_topology_assert(); 422 423 pp = LIST_FIRST(&gp->consumer)->provider; 424 table = gp->softc; 425 end = gpp->gpp_start + gpp->gpp_size - 1; 426 427 if (gpp->gpp_start < table->gpt_first || 428 gpp->gpp_start > table->gpt_last) { 429 gctl_error(req, "%d start '%jd'", EINVAL, 430 (intmax_t)gpp->gpp_start); 431 return (EINVAL); 432 } 433 if (end < gpp->gpp_start || end > table->gpt_last) { 434 gctl_error(req, "%d size '%jd'", EINVAL, 435 (intmax_t)gpp->gpp_size); 436 return (EINVAL); 437 } 438 if (gpp->gpp_index > table->gpt_entries) { 439 gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index); 440 return (EINVAL); 441 } 442 443 delent = last = NULL; 444 index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1; 445 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 446 if (entry->gpe_deleted) { 447 if (entry->gpe_index == index) 448 delent = entry; 449 continue; 450 } 451 if (entry->gpe_index == index) { 452 index = entry->gpe_index + 1; 453 last = entry; 454 } 455 if (gpp->gpp_start >= entry->gpe_start && 456 gpp->gpp_start <= entry->gpe_end) { 457 gctl_error(req, "%d start '%jd'", ENOSPC, 458 (intmax_t)gpp->gpp_start); 459 return (ENOSPC); 460 } 461 if (end >= entry->gpe_start && end <= entry->gpe_end) { 462 gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end); 463 return (ENOSPC); 464 } 465 if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) { 466 gctl_error(req, "%d size '%jd'", ENOSPC, 467 (intmax_t)gpp->gpp_size); 468 return (ENOSPC); 469 } 470 } 471 if (gpp->gpp_index > 0 && index != gpp->gpp_index) { 472 gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index); 473 return (EEXIST); 474 } 475 476 entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz, 477 M_WAITOK | M_ZERO) : delent; 478 entry->gpe_index = index; 479 entry->gpe_start = gpp->gpp_start; 480 entry->gpe_end = end; 481 error = G_PART_ADD(table, entry, gpp); 482 if (error) { 483 gctl_error(req, "%d", error); 484 if (delent == NULL) 485 g_free(entry); 486 return (error); 487 } 488 if (delent == NULL) { 489 if (last == NULL) 490 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry); 491 else 492 LIST_INSERT_AFTER(last, entry, gpe_entry); 493 entry->gpe_created = 1; 494 } else { 495 entry->gpe_deleted = 0; 496 entry->gpe_modified = 1; 497 } 498 g_part_new_provider(gp, table, entry); 499 500 /* Provide feedback if so requested. */ 501 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 502 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 503 sbuf_printf(sb, "%s%s added\n", gp->name, 504 G_PART_NAME(table, entry, buf, sizeof(buf))); 505 sbuf_finish(sb); 506 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 507 sbuf_delete(sb); 508 } 509 return (0); 510} 511 512static int 513g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp) 514{ 515 struct g_consumer *cp; 516 struct g_geom *gp; 517 struct g_provider *pp; 518 struct g_part_entry *entry, *tmp; 519 struct g_part_table *table; 520 char *buf; 521 int error, i; 522 523 gp = gpp->gpp_geom; 524 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 525 g_topology_assert(); 526 527 table = gp->softc; 528 if (!table->gpt_opened) { 529 gctl_error(req, "%d", EPERM); 530 return (EPERM); 531 } 532 533 cp = LIST_FIRST(&gp->consumer); 534 if ((table->gpt_smhead | table->gpt_smtail) != 0) { 535 pp = cp->provider; 536 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 537 while (table->gpt_smhead != 0) { 538 i = ffs(table->gpt_smhead) - 1; 539 error = g_write_data(cp, i * pp->sectorsize, buf, 540 pp->sectorsize); 541 if (error) { 542 g_free(buf); 543 goto fail; 544 } 545 table->gpt_smhead &= ~(1 << i); 546 } 547 while (table->gpt_smtail != 0) { 548 i = ffs(table->gpt_smtail) - 1; 549 error = g_write_data(cp, pp->mediasize - (i + 1) * 550 pp->sectorsize, buf, pp->sectorsize); 551 if (error) { 552 g_free(buf); 553 goto fail; 554 } 555 table->gpt_smtail &= ~(1 << i); 556 } 557 g_free(buf); 558 } 559 560 if (table->gpt_scheme == &g_part_null_scheme) { 561 g_access(cp, -1, -1, -1); 562 g_part_wither(gp, ENXIO); 563 return (0); 564 } 565 566 error = G_PART_WRITE(table, cp); 567 if (error) 568 goto fail; 569 570 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 571 if (!entry->gpe_deleted) { 572 entry->gpe_created = 0; 573 entry->gpe_modified = 0; 574 continue; 575 } 576 LIST_REMOVE(entry, gpe_entry); 577 g_free(entry); 578 } 579 table->gpt_created = 0; 580 table->gpt_opened = 0; 581 g_access(cp, -1, -1, -1); 582 return (0); 583 584fail: 585 gctl_error(req, "%d", error); 586 return (error); 587} 588 589static int 590g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) 591{ 592 struct g_consumer *cp; 593 struct g_geom *gp; 594 struct g_provider *pp; 595 struct g_part_scheme *scheme; 596 struct g_part_table *null, *table; 597 struct sbuf *sb; 598 int attr, error; 599 600 pp = gpp->gpp_provider; 601 scheme = gpp->gpp_scheme; 602 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 603 g_topology_assert(); 604 605 /* Check that there isn't already a g_part geom on the provider. */ 606 error = g_part_parm_geom(pp->name, &gp); 607 if (!error) { 608 null = gp->softc; 609 if (null->gpt_scheme != &g_part_null_scheme) { 610 gctl_error(req, "%d geom '%s'", EEXIST, pp->name); 611 return (EEXIST); 612 } 613 } else 614 null = NULL; 615 616 if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) && 617 (gpp->gpp_entries < scheme->gps_minent || 618 gpp->gpp_entries > scheme->gps_maxent)) { 619 gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries); 620 return (EINVAL); 621 } 622 623 if (null == NULL) 624 gp = g_new_geomf(&g_part_class, "%s", pp->name); 625 gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM, 626 M_WAITOK); 627 table = gp->softc; 628 table->gpt_gp = gp; 629 table->gpt_scheme = gpp->gpp_scheme; 630 table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ? 631 gpp->gpp_entries : scheme->gps_minent; 632 LIST_INIT(&table->gpt_entry); 633 if (null == NULL) { 634 cp = g_new_consumer(gp); 635 error = g_attach(cp, pp); 636 if (error == 0) 637 error = g_access(cp, 1, 1, 1); 638 if (error != 0) { 639 g_part_wither(gp, error); 640 gctl_error(req, "%d geom '%s'", error, pp->name); 641 return (error); 642 } 643 table->gpt_opened = 1; 644 } else { 645 cp = LIST_FIRST(&gp->consumer); 646 table->gpt_opened = null->gpt_opened; 647 table->gpt_smhead = null->gpt_smhead; 648 table->gpt_smtail = null->gpt_smtail; 649 } 650 651 g_topology_unlock(); 652 653 /* Make sure the provider has media. */ 654 if (pp->mediasize == 0 || pp->sectorsize == 0) { 655 error = ENODEV; 656 goto fail; 657 } 658 659 /* Make sure we can nest and if so, determine our depth. */ 660 error = g_getattr("PART::isleaf", cp, &attr); 661 if (!error && attr) { 662 error = ENODEV; 663 goto fail; 664 } 665 error = g_getattr("PART::depth", cp, &attr); 666 table->gpt_depth = (!error) ? attr + 1 : 0; 667 668 /* 669 * Synthesize a disk geometry. Some partitioning schemes 670 * depend on it and since some file systems need it even 671 * when the partitition scheme doesn't, we do it here in 672 * scheme-independent code. 673 */ 674 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 675 676 error = G_PART_CREATE(table, gpp); 677 if (error) 678 goto fail; 679 680 g_topology_lock(); 681 682 table->gpt_created = 1; 683 if (null != NULL) 684 kobj_delete((kobj_t)null, M_GEOM); 685 686 /* 687 * Support automatic commit by filling in the gpp_geom 688 * parameter. 689 */ 690 gpp->gpp_parms |= G_PART_PARM_GEOM; 691 gpp->gpp_geom = gp; 692 693 /* Provide feedback if so requested. */ 694 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 695 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 696 sbuf_printf(sb, "%s created\n", gp->name); 697 sbuf_finish(sb); 698 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 699 sbuf_delete(sb); 700 } 701 return (0); 702 703fail: 704 g_topology_lock(); 705 if (null == NULL) { 706 g_access(cp, -1, -1, -1); 707 g_part_wither(gp, error); 708 } else { 709 kobj_delete((kobj_t)gp->softc, M_GEOM); 710 gp->softc = null; 711 } 712 gctl_error(req, "%d provider", error); 713 return (error); 714} 715 716static int 717g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp) 718{ 719 char buf[32]; 720 struct g_geom *gp; 721 struct g_provider *pp; 722 struct g_part_entry *entry; 723 struct g_part_table *table; 724 struct sbuf *sb; 725 726 gp = gpp->gpp_geom; 727 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 728 g_topology_assert(); 729 730 table = gp->softc; 731 732 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 733 if (entry->gpe_deleted) 734 continue; 735 if (entry->gpe_index == gpp->gpp_index) 736 break; 737 } 738 if (entry == NULL) { 739 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 740 return (ENOENT); 741 } 742 743 pp = entry->gpe_pp; 744 if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) { 745 gctl_error(req, "%d", EBUSY); 746 return (EBUSY); 747 } 748 749 pp->private = NULL; 750 entry->gpe_pp = NULL; 751 if (entry->gpe_created) { 752 LIST_REMOVE(entry, gpe_entry); 753 g_free(entry); 754 } else { 755 entry->gpe_modified = 0; 756 entry->gpe_deleted = 1; 757 } 758 g_wither_provider(pp, ENXIO); 759 760 /* Provide feedback if so requested. */ 761 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 762 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 763 sbuf_printf(sb, "%s%s deleted\n", gp->name, 764 G_PART_NAME(table, entry, buf, sizeof(buf))); 765 sbuf_finish(sb); 766 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 767 sbuf_delete(sb); 768 } 769 return (0); 770} 771 772static int 773g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp) 774{ 775 struct g_geom *gp; 776 struct g_part_entry *entry; 777 struct g_part_table *null, *table; 778 struct sbuf *sb; 779 int error; 780 781 gp = gpp->gpp_geom; 782 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 783 g_topology_assert(); 784 785 table = gp->softc; 786 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 787 if (entry->gpe_deleted) 788 continue; 789 gctl_error(req, "%d", EBUSY); 790 return (EBUSY); 791 } 792 793 error = G_PART_DESTROY(table, gpp); 794 if (error) { 795 gctl_error(req, "%d", error); 796 return (error); 797 } 798 799 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM, 800 M_WAITOK); 801 null = gp->softc; 802 null->gpt_gp = gp; 803 null->gpt_scheme = &g_part_null_scheme; 804 LIST_INIT(&null->gpt_entry); 805 null->gpt_depth = table->gpt_depth; 806 null->gpt_opened = table->gpt_opened; 807 null->gpt_smhead = table->gpt_smhead; 808 null->gpt_smtail = table->gpt_smtail; 809 810 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 811 LIST_REMOVE(entry, gpe_entry); 812 g_free(entry); 813 } 814 kobj_delete((kobj_t)table, M_GEOM); 815 816 /* Provide feedback if so requested. */ 817 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 818 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 819 sbuf_printf(sb, "%s destroyed\n", gp->name); 820 sbuf_finish(sb); 821 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 822 sbuf_delete(sb); 823 } 824 return (0); 825} 826 827static int 828g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp) 829{ 830 char buf[32]; 831 struct g_geom *gp; 832 struct g_part_entry *entry; 833 struct g_part_table *table; 834 struct sbuf *sb; 835 int error; 836 837 gp = gpp->gpp_geom; 838 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 839 g_topology_assert(); 840 841 table = gp->softc; 842 843 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { 844 if (entry->gpe_deleted) 845 continue; 846 if (entry->gpe_index == gpp->gpp_index) 847 break; 848 } 849 if (entry == NULL) { 850 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); 851 return (ENOENT); 852 } 853 854 error = G_PART_MODIFY(table, entry, gpp); 855 if (error) { 856 gctl_error(req, "%d", error); 857 return (error); 858 } 859 860 if (!entry->gpe_created) 861 entry->gpe_modified = 1; 862 863 /* Provide feedback if so requested. */ 864 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { 865 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 866 sbuf_printf(sb, "%s%s modified\n", gp->name, 867 G_PART_NAME(table, entry, buf, sizeof(buf))); 868 sbuf_finish(sb); 869 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); 870 sbuf_delete(sb); 871 } 872 return (0); 873} 874 875static int 876g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) 877{ 878 gctl_error(req, "%d verb 'move'", ENOSYS); 879 return (ENOSYS); 880} 881 882static int 883g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) 884{ 885 gctl_error(req, "%d verb 'recover'", ENOSYS); 886 return (ENOSYS); 887} 888 889static int 890g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) 891{ 892 gctl_error(req, "%d verb 'resize'", ENOSYS); 893 return (ENOSYS); 894} 895 896static int 897g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) 898{ 899 struct g_consumer *cp; 900 struct g_provider *pp; 901 struct g_geom *gp; 902 struct g_part_entry *entry, *tmp; 903 struct g_part_table *table; 904 int error, reprobe; 905 906 gp = gpp->gpp_geom; 907 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); 908 g_topology_assert(); 909 910 table = gp->softc; 911 if (!table->gpt_opened) { 912 gctl_error(req, "%d", EPERM); 913 return (EPERM); 914 } 915 916 cp = LIST_FIRST(&gp->consumer); 917 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) { 918 entry->gpe_modified = 0; 919 if (entry->gpe_created) { 920 pp = entry->gpe_pp; 921 pp->private = NULL; 922 entry->gpe_pp = NULL; 923 g_wither_provider(pp, ENXIO); 924 entry->gpe_deleted = 1; 925 } 926 if (entry->gpe_deleted) { 927 LIST_REMOVE(entry, gpe_entry); 928 g_free(entry); 929 } 930 } 931 932 g_topology_unlock(); 933 934 reprobe = (table->gpt_scheme == &g_part_null_scheme || 935 table->gpt_created) ? 1 : 0; 936 937 if (reprobe) { 938 if (!LIST_EMPTY(&table->gpt_entry)) { 939 error = EBUSY; 940 goto fail; 941 } 942 error = g_part_probe(gp, cp, table->gpt_depth); 943 if (error) { 944 g_topology_lock(); 945 g_access(cp, -1, -1, -1); 946 g_part_wither(gp, error); 947 return (0); 948 } 949 table = gp->softc; 950 } 951 952 error = G_PART_READ(table, cp); 953 if (error) 954 goto fail; 955 956 g_topology_lock(); 957 958 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) 959 g_part_new_provider(gp, table, entry); 960 961 table->gpt_opened = 0; 962 g_access(cp, -1, -1, -1); 963 return (0); 964 965fail: 966 g_topology_lock(); 967 gctl_error(req, "%d", error); 968 return (error); 969} 970 971static void 972g_part_wither(struct g_geom *gp, int error) 973{ 974 struct g_part_entry *entry; 975 struct g_part_table *table; 976 977 table = gp->softc; 978 if (table != NULL) { 979 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { 980 LIST_REMOVE(entry, gpe_entry); 981 g_free(entry); 982 } 983 if (gp->softc != NULL) { 984 kobj_delete((kobj_t)gp->softc, M_GEOM); 985 gp->softc = NULL; 986 } 987 } 988 g_wither_geom(gp, error); 989} 990 991/* 992 * Class methods. 993 */ 994 995static void 996g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) 997{ 998 struct g_part_parms gpp; 999 struct g_part_table *table; 1000 struct gctl_req_arg *ap; 1001 const char *p; 1002 enum g_part_ctl ctlreq; 1003 unsigned int i, mparms, oparms, parm; 1004 int auto_commit, close_on_error; 1005 int error, modifies; 1006 1007 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); 1008 g_topology_assert(); 1009 1010 ctlreq = G_PART_CTL_NONE; 1011 modifies = 1; 1012 mparms = 0; 1013 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION; 1014 switch (*verb) { 1015 case 'a': 1016 if (!strcmp(verb, "add")) { 1017 ctlreq = G_PART_CTL_ADD; 1018 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE | 1019 G_PART_PARM_START | G_PART_PARM_TYPE; 1020 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; 1021 } 1022 break; 1023 case 'c': 1024 if (!strcmp(verb, "commit")) { 1025 ctlreq = G_PART_CTL_COMMIT; 1026 mparms |= G_PART_PARM_GEOM; 1027 modifies = 0; 1028 } else if (!strcmp(verb, "create")) { 1029 ctlreq = G_PART_CTL_CREATE; 1030 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME; 1031 oparms |= G_PART_PARM_ENTRIES; 1032 } 1033 break; 1034 case 'd': 1035 if (!strcmp(verb, "delete")) { 1036 ctlreq = G_PART_CTL_DELETE; 1037 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1038 } else if (!strcmp(verb, "destroy")) { 1039 ctlreq = G_PART_CTL_DESTROY; 1040 mparms |= G_PART_PARM_GEOM; 1041 } 1042 break; 1043 case 'm': 1044 if (!strcmp(verb, "modify")) { 1045 ctlreq = G_PART_CTL_MODIFY; 1046 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1047 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE; 1048 } else if (!strcmp(verb, "move")) { 1049 ctlreq = G_PART_CTL_MOVE; 1050 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1051 } 1052 break; 1053 case 'r': 1054 if (!strcmp(verb, "recover")) { 1055 ctlreq = G_PART_CTL_RECOVER; 1056 mparms |= G_PART_PARM_GEOM; 1057 } else if (!strcmp(verb, "resize")) { 1058 ctlreq = G_PART_CTL_RESIZE; 1059 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; 1060 } 1061 break; 1062 case 'u': 1063 if (!strcmp(verb, "undo")) { 1064 ctlreq = G_PART_CTL_UNDO; 1065 mparms |= G_PART_PARM_GEOM; 1066 modifies = 0; 1067 } 1068 break; 1069 } 1070 if (ctlreq == G_PART_CTL_NONE) { 1071 gctl_error(req, "%d verb '%s'", EINVAL, verb); 1072 return; 1073 } 1074 1075 bzero(&gpp, sizeof(gpp)); 1076 for (i = 0; i < req->narg; i++) { 1077 ap = &req->arg[i]; 1078 parm = 0; 1079 switch (ap->name[0]) { 1080 case 'c': 1081 if (!strcmp(ap->name, "class")) 1082 continue; 1083 break; 1084 case 'e': 1085 if (!strcmp(ap->name, "entries")) 1086 parm = G_PART_PARM_ENTRIES; 1087 break; 1088 case 'f': 1089 if (!strcmp(ap->name, "flags")) 1090 parm = G_PART_PARM_FLAGS; 1091 break; 1092 case 'g': 1093 if (!strcmp(ap->name, "geom")) 1094 parm = G_PART_PARM_GEOM; 1095 break; 1096 case 'i': 1097 if (!strcmp(ap->name, "index")) 1098 parm = G_PART_PARM_INDEX; 1099 break; 1100 case 'l': 1101 if (!strcmp(ap->name, "label")) 1102 parm = G_PART_PARM_LABEL; 1103 break; 1104 case 'o': 1105 if (!strcmp(ap->name, "output")) 1106 parm = G_PART_PARM_OUTPUT; 1107 break; 1108 case 'p': 1109 if (!strcmp(ap->name, "provider")) 1110 parm = G_PART_PARM_PROVIDER; 1111 break; 1112 case 's': 1113 if (!strcmp(ap->name, "scheme")) 1114 parm = G_PART_PARM_SCHEME; 1115 else if (!strcmp(ap->name, "size")) 1116 parm = G_PART_PARM_SIZE; 1117 else if (!strcmp(ap->name, "start")) 1118 parm = G_PART_PARM_START; 1119 break; 1120 case 't': 1121 if (!strcmp(ap->name, "type")) 1122 parm = G_PART_PARM_TYPE; 1123 break; 1124 case 'v': 1125 if (!strcmp(ap->name, "verb")) 1126 continue; 1127 else if (!strcmp(ap->name, "version")) 1128 parm = G_PART_PARM_VERSION; 1129 break; 1130 } 1131 if ((parm & (mparms | oparms)) == 0) { 1132 gctl_error(req, "%d param '%s'", EINVAL, ap->name); 1133 return; 1134 } 1135 p = gctl_get_asciiparam(req, ap->name); 1136 if (p == NULL) { 1137 gctl_error(req, "%d param '%s'", ENOATTR, ap->name); 1138 return; 1139 } 1140 switch (parm) { 1141 case G_PART_PARM_ENTRIES: 1142 error = g_part_parm_uint(p, &gpp.gpp_entries); 1143 break; 1144 case G_PART_PARM_FLAGS: 1145 if (p[0] == '\0') 1146 continue; 1147 error = g_part_parm_str(p, &gpp.gpp_flags); 1148 break; 1149 case G_PART_PARM_GEOM: 1150 error = g_part_parm_geom(p, &gpp.gpp_geom); 1151 break; 1152 case G_PART_PARM_INDEX: 1153 error = g_part_parm_uint(p, &gpp.gpp_index); 1154 break; 1155 case G_PART_PARM_LABEL: 1156 /* An empty label is always valid. */ 1157 gpp.gpp_label = p; 1158 error = 0; 1159 break; 1160 case G_PART_PARM_OUTPUT: 1161 error = 0; /* Write-only parameter */ 1162 break; 1163 case G_PART_PARM_PROVIDER: 1164 error = g_part_parm_provider(p, &gpp.gpp_provider); 1165 break; 1166 case G_PART_PARM_SCHEME: 1167 error = g_part_parm_scheme(p, &gpp.gpp_scheme); 1168 break; 1169 case G_PART_PARM_SIZE: 1170 error = g_part_parm_quad(p, &gpp.gpp_size); 1171 break; 1172 case G_PART_PARM_START: 1173 error = g_part_parm_quad(p, &gpp.gpp_start); 1174 break; 1175 case G_PART_PARM_TYPE: 1176 error = g_part_parm_str(p, &gpp.gpp_type); 1177 break; 1178 case G_PART_PARM_VERSION: 1179 error = g_part_parm_uint(p, &gpp.gpp_version); 1180 break; 1181 default: 1182 error = EDOOFUS; 1183 break; 1184 } 1185 if (error) { 1186 gctl_error(req, "%d %s '%s'", error, ap->name, p); 1187 return; 1188 } 1189 gpp.gpp_parms |= parm; 1190 } 1191 if ((gpp.gpp_parms & mparms) != mparms) { 1192 parm = mparms - (gpp.gpp_parms & mparms); 1193 gctl_error(req, "%d param '%x'", ENOATTR, parm); 1194 return; 1195 } 1196 1197 /* Obtain permissions if possible/necessary. */ 1198 close_on_error = 0; 1199 table = NULL; /* Suppress uninit. warning. */ 1200 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) { 1201 table = gpp.gpp_geom->softc; 1202 if (table != NULL && !table->gpt_opened) { 1203 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer), 1204 1, 1, 1); 1205 if (error) { 1206 gctl_error(req, "%d geom '%s'", error, 1207 gpp.gpp_geom->name); 1208 return; 1209 } 1210 table->gpt_opened = 1; 1211 close_on_error = 1; 1212 } 1213 } 1214 1215 error = EDOOFUS; /* Prevent bogus uninit. warning. */ 1216 switch (ctlreq) { 1217 case G_PART_CTL_NONE: 1218 panic("%s", __func__); 1219 case G_PART_CTL_ADD: 1220 error = g_part_ctl_add(req, &gpp); 1221 break; 1222 case G_PART_CTL_COMMIT: 1223 error = g_part_ctl_commit(req, &gpp); 1224 break; 1225 case G_PART_CTL_CREATE: 1226 error = g_part_ctl_create(req, &gpp); 1227 break; 1228 case G_PART_CTL_DELETE: 1229 error = g_part_ctl_delete(req, &gpp); 1230 break; 1231 case G_PART_CTL_DESTROY: 1232 error = g_part_ctl_destroy(req, &gpp); 1233 break; 1234 case G_PART_CTL_MODIFY: 1235 error = g_part_ctl_modify(req, &gpp); 1236 break; 1237 case G_PART_CTL_MOVE: 1238 error = g_part_ctl_move(req, &gpp); 1239 break; 1240 case G_PART_CTL_RECOVER: 1241 error = g_part_ctl_recover(req, &gpp); 1242 break; 1243 case G_PART_CTL_RESIZE: 1244 error = g_part_ctl_resize(req, &gpp); 1245 break; 1246 case G_PART_CTL_UNDO: 1247 error = g_part_ctl_undo(req, &gpp); 1248 break; 1249 } 1250 1251 /* Implement automatic commit. */ 1252 if (!error) { 1253 auto_commit = (modifies && 1254 (gpp.gpp_parms & G_PART_PARM_FLAGS) && 1255 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; 1256 if (auto_commit) { 1257 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__)); 1258 error = g_part_ctl_commit(req, &gpp); 1259 } 1260 } 1261 1262 if (error && close_on_error) { 1263 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1); 1264 table->gpt_opened = 0; 1265 } 1266} 1267 1268static int 1269g_part_destroy_geom(struct gctl_req *req, struct g_class *mp, 1270 struct g_geom *gp) 1271{ 1272 1273 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); 1274 g_topology_assert(); 1275 1276 g_part_wither(gp, EINVAL); 1277 return (0); 1278} 1279 1280static struct g_geom * 1281g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 1282{ 1283 struct g_consumer *cp; 1284 struct g_geom *gp; 1285 struct g_part_entry *entry; 1286 struct g_part_table *table; 1287 int attr, depth; 1288 int error; 1289 1290 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); 1291 g_topology_assert(); 1292 1293 /* 1294 * Create a GEOM with consumer and hook it up to the provider. 1295 * With that we become part of the topology. Optain read access 1296 * to the provider. 1297 */ 1298 gp = g_new_geomf(mp, "%s", pp->name); 1299 cp = g_new_consumer(gp); 1300 error = g_attach(cp, pp); 1301 if (error == 0) 1302 error = g_access(cp, 1, 0, 0); 1303 if (error != 0) { 1304 g_part_wither(gp, error); 1305 return (NULL); 1306 } 1307 1308 g_topology_unlock(); 1309 1310 /* 1311 * Short-circuit the whole probing galore when there's no 1312 * media present. 1313 */ 1314 if (pp->mediasize == 0 || pp->sectorsize == 0) { 1315 error = ENODEV; 1316 goto fail; 1317 } 1318 1319 /* Make sure we can nest and if so, determine our depth. */ 1320 error = g_getattr("PART::isleaf", cp, &attr); 1321 if (!error && attr) { 1322 error = ENODEV; 1323 goto fail; 1324 } 1325 error = g_getattr("PART::depth", cp, &attr); 1326 depth = (!error) ? attr + 1 : 0; 1327 1328 error = g_part_probe(gp, cp, depth); 1329 if (error) 1330 goto fail; 1331 1332 table = gp->softc; 1333 1334 /* 1335 * Synthesize a disk geometry. Some partitioning schemes 1336 * depend on it and since some file systems need it even 1337 * when the partitition scheme doesn't, we do it here in 1338 * scheme-independent code. 1339 */ 1340 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); 1341 1342 error = G_PART_READ(table, cp); 1343 if (error) 1344 goto fail; 1345 1346 g_topology_lock(); 1347 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) 1348 g_part_new_provider(gp, table, entry); 1349 1350 g_access(cp, -1, 0, 0); 1351 return (gp); 1352 1353 fail: 1354 g_topology_lock(); 1355 g_access(cp, -1, 0, 0); 1356 g_part_wither(gp, error); 1357 return (NULL); 1358} 1359 1360/* 1361 * Geom methods. 1362 */ 1363 1364static int 1365g_part_access(struct g_provider *pp, int dr, int dw, int de) 1366{ 1367 struct g_consumer *cp; 1368 1369 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, 1370 dw, de)); 1371 1372 cp = LIST_FIRST(&pp->geom->consumer); 1373 1374 /* We always gain write-exclusive access. */ 1375 return (g_access(cp, dr, dw, dw + de)); 1376} 1377 1378static void 1379g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1380 struct g_consumer *cp, struct g_provider *pp) 1381{ 1382 char buf[64]; 1383 struct g_part_entry *entry; 1384 struct g_part_table *table; 1385 1386 KASSERT(sb != NULL && gp != NULL, (__func__)); 1387 table = gp->softc; 1388 1389 if (indent == NULL) { 1390 KASSERT(cp == NULL && pp != NULL, (__func__)); 1391 entry = pp->private; 1392 if (entry == NULL) 1393 return; 1394 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index, 1395 (uintmax_t)entry->gpe_offset, 1396 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1397 } else if (cp != NULL) { /* Consumer configuration. */ 1398 KASSERT(pp == NULL, (__func__)); 1399 /* none */ 1400 } else if (pp != NULL) { /* Provider configuration. */ 1401 entry = pp->private; 1402 if (entry == NULL) 1403 return; 1404 sbuf_printf(sb, "%s<index>%u</index>\n", indent, 1405 entry->gpe_index); 1406 sbuf_printf(sb, "%s<type>%s</type>\n", indent, 1407 G_PART_TYPE(table, entry, buf, sizeof(buf))); 1408 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 1409 (uintmax_t)entry->gpe_offset); 1410 sbuf_printf(sb, "%s<length>%ju</length>\n", indent, 1411 (uintmax_t)pp->mediasize); 1412 G_PART_DUMPCONF(table, entry, sb, indent); 1413 } else { /* Geom configuration. */ 1414 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent, 1415 table->gpt_scheme->name); 1416 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent, 1417 table->gpt_entries); 1418 sbuf_printf(sb, "%s<first>%ju</first>\n", indent, 1419 (uintmax_t)table->gpt_first); 1420 sbuf_printf(sb, "%s<last>%ju</last>\n", indent, 1421 (uintmax_t)table->gpt_last); 1422 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent, 1423 table->gpt_sectors); 1424 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent, 1425 table->gpt_heads); 1426 G_PART_DUMPCONF(table, NULL, sb, indent); 1427 } 1428} 1429 1430static void 1431g_part_orphan(struct g_consumer *cp) 1432{ 1433 struct g_provider *pp; 1434 1435 pp = cp->provider; 1436 KASSERT(pp != NULL, (__func__)); 1437 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); 1438 g_topology_assert(); 1439 1440 KASSERT(pp->error != 0, (__func__)); 1441 g_part_wither(cp->geom, pp->error); 1442} 1443 1444static void 1445g_part_spoiled(struct g_consumer *cp) 1446{ 1447 1448 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); 1449 g_topology_assert(); 1450 1451 g_part_wither(cp->geom, ENXIO); 1452} 1453 1454static void 1455g_part_start(struct bio *bp) 1456{ 1457 struct bio *bp2; 1458 struct g_consumer *cp; 1459 struct g_geom *gp; 1460 struct g_part_entry *entry; 1461 struct g_part_table *table; 1462 struct g_kerneldump *gkd; 1463 struct g_provider *pp; 1464 1465 pp = bp->bio_to; 1466 gp = pp->geom; 1467 table = gp->softc; 1468 cp = LIST_FIRST(&gp->consumer); 1469 1470 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd, 1471 pp->name)); 1472 1473 entry = pp->private; 1474 if (entry == NULL) { 1475 g_io_deliver(bp, ENXIO); 1476 return; 1477 } 1478 1479 switch(bp->bio_cmd) { 1480 case BIO_DELETE: 1481 case BIO_READ: 1482 case BIO_WRITE: 1483 if (bp->bio_offset >= pp->mediasize) { 1484 g_io_deliver(bp, EIO); 1485 return; 1486 } 1487 bp2 = g_clone_bio(bp); 1488 if (bp2 == NULL) { 1489 g_io_deliver(bp, ENOMEM); 1490 return; 1491 } 1492 if (bp2->bio_offset + bp2->bio_length > pp->mediasize) 1493 bp2->bio_length = pp->mediasize - bp2->bio_offset; 1494 bp2->bio_done = g_std_done; 1495 bp2->bio_offset += entry->gpe_offset; 1496 g_io_request(bp2, cp); 1497 return; 1498 case BIO_FLUSH: 1499 break; 1500 case BIO_GETATTR: 1501 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads)) 1502 return; 1503 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors)) 1504 return; 1505 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf)) 1506 return; 1507 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth)) 1508 return; 1509 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 1510 /* 1511 * Check that the partition is suitable for kernel 1512 * dumps. Typically only swap partitions should be 1513 * used. 1514 */ 1515 if (!G_PART_DUMPTO(table, entry)) { 1516 g_io_deliver(bp, ENXIO); 1517 return; 1518 } 1519 gkd = (struct g_kerneldump *)bp->bio_data; 1520 if (gkd->offset >= pp->mediasize) { 1521 g_io_deliver(bp, EIO); 1522 return; 1523 } 1524 if (gkd->offset + gkd->length > pp->mediasize) 1525 gkd->length = pp->mediasize - gkd->offset; 1526 gkd->offset += entry->gpe_offset; 1527 } 1528 break; 1529 default: 1530 g_io_deliver(bp, EOPNOTSUPP); 1531 return; 1532 } 1533 1534 bp2 = g_clone_bio(bp); 1535 if (bp2 == NULL) { 1536 g_io_deliver(bp, ENOMEM); 1537 return; 1538 } 1539 bp2->bio_done = g_std_done; 1540 g_io_request(bp2, cp); 1541} 1542