1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 Marcel Moolenaar 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/bio.h> 34#include <sys/endian.h> 35#include <sys/kernel.h> 36#include <sys/kobj.h> 37#include <sys/limits.h> 38#include <sys/lock.h> 39#include <sys/malloc.h> 40#include <sys/mutex.h> 41#include <sys/queue.h> 42#include <sys/sbuf.h> 43#include <sys/systm.h> 44#include <sys/sysctl.h> 45#include <sys/vtoc.h> 46#include <geom/geom.h> 47#include <geom/geom_int.h> 48#include <geom/part/g_part.h> 49 50#include "g_part_if.h" 51 52FEATURE(geom_part_vtoc8, "GEOM partitioning class for SMI VTOC8 disk labels"); 53 54struct g_part_vtoc8_table { 55 struct g_part_table base; 56 struct vtoc8 vtoc; 57 uint32_t secpercyl; 58}; 59 60static int g_part_vtoc8_add(struct g_part_table *, struct g_part_entry *, 61 struct g_part_parms *); 62static int g_part_vtoc8_create(struct g_part_table *, struct g_part_parms *); 63static int g_part_vtoc8_destroy(struct g_part_table *, struct g_part_parms *); 64static void g_part_vtoc8_dumpconf(struct g_part_table *, 65 struct g_part_entry *, struct sbuf *, const char *); 66static int g_part_vtoc8_dumpto(struct g_part_table *, struct g_part_entry *); 67static int g_part_vtoc8_modify(struct g_part_table *, struct g_part_entry *, 68 struct g_part_parms *); 69static const char *g_part_vtoc8_name(struct g_part_table *, 70 struct g_part_entry *, char *, size_t); 71static int g_part_vtoc8_probe(struct g_part_table *, struct g_consumer *); 72static int g_part_vtoc8_read(struct g_part_table *, struct g_consumer *); 73static const char *g_part_vtoc8_type(struct g_part_table *, 74 struct g_part_entry *, char *, size_t); 75static int g_part_vtoc8_write(struct g_part_table *, struct g_consumer *); 76static int g_part_vtoc8_resize(struct g_part_table *, struct g_part_entry *, 77 struct g_part_parms *); 78 79static kobj_method_t g_part_vtoc8_methods[] = { 80 KOBJMETHOD(g_part_add, g_part_vtoc8_add), 81 KOBJMETHOD(g_part_create, g_part_vtoc8_create), 82 KOBJMETHOD(g_part_destroy, g_part_vtoc8_destroy), 83 KOBJMETHOD(g_part_dumpconf, g_part_vtoc8_dumpconf), 84 KOBJMETHOD(g_part_dumpto, g_part_vtoc8_dumpto), 85 KOBJMETHOD(g_part_modify, g_part_vtoc8_modify), 86 KOBJMETHOD(g_part_resize, g_part_vtoc8_resize), 87 KOBJMETHOD(g_part_name, g_part_vtoc8_name), 88 KOBJMETHOD(g_part_probe, g_part_vtoc8_probe), 89 KOBJMETHOD(g_part_read, g_part_vtoc8_read), 90 KOBJMETHOD(g_part_type, g_part_vtoc8_type), 91 KOBJMETHOD(g_part_write, g_part_vtoc8_write), 92 { 0, 0 } 93}; 94 95static struct g_part_scheme g_part_vtoc8_scheme = { 96 "VTOC8", 97 g_part_vtoc8_methods, 98 sizeof(struct g_part_vtoc8_table), 99 .gps_entrysz = sizeof(struct g_part_entry), 100 .gps_minent = VTOC8_NPARTS, 101 .gps_maxent = VTOC8_NPARTS, 102}; 103G_PART_SCHEME_DECLARE(g_part_vtoc8); 104MODULE_VERSION(geom_part_vtoc8, 0); 105 106static int 107vtoc8_parse_type(const char *type, uint16_t *tag) 108{ 109 const char *alias; 110 char *endp; 111 long lt; 112 113 if (type[0] == '!') { 114 lt = strtol(type + 1, &endp, 0); 115 if (type[1] == '\0' || *endp != '\0' || lt <= 0 || 116 lt >= 65536) 117 return (EINVAL); 118 *tag = (uint16_t)lt; 119 return (0); 120 } 121 alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS); 122 if (!strcasecmp(type, alias)) { 123 *tag = VTOC_TAG_FREEBSD_NANDFS; 124 return (0); 125 } 126 alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP); 127 if (!strcasecmp(type, alias)) { 128 *tag = VTOC_TAG_FREEBSD_SWAP; 129 return (0); 130 } 131 alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS); 132 if (!strcasecmp(type, alias)) { 133 *tag = VTOC_TAG_FREEBSD_UFS; 134 return (0); 135 } 136 alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM); 137 if (!strcasecmp(type, alias)) { 138 *tag = VTOC_TAG_FREEBSD_VINUM; 139 return (0); 140 } 141 alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS); 142 if (!strcasecmp(type, alias)) { 143 *tag = VTOC_TAG_FREEBSD_ZFS; 144 return (0); 145 } 146 return (EINVAL); 147} 148 149static int 150vtoc8_align(struct g_part_vtoc8_table *table, uint64_t *start, uint64_t *size) 151{ 152 153 if (*size < table->secpercyl) 154 return (EINVAL); 155 if (start != NULL && (*start % table->secpercyl)) { 156 *size += (*start % table->secpercyl) - table->secpercyl; 157 *start -= (*start % table->secpercyl) - table->secpercyl; 158 } 159 if (*size % table->secpercyl) 160 *size -= (*size % table->secpercyl); 161 if (*size < table->secpercyl) 162 return (EINVAL); 163 return (0); 164} 165 166static int 167g_part_vtoc8_add(struct g_part_table *basetable, struct g_part_entry *entry, 168 struct g_part_parms *gpp) 169{ 170 struct g_part_vtoc8_table *table; 171 int error, index; 172 uint64_t start, size; 173 uint16_t tag; 174 175 if (gpp->gpp_parms & G_PART_PARM_LABEL) 176 return (EINVAL); 177 178 error = vtoc8_parse_type(gpp->gpp_type, &tag); 179 if (error) 180 return (error); 181 182 table = (struct g_part_vtoc8_table *)basetable; 183 index = entry->gpe_index - 1; 184 start = gpp->gpp_start; 185 size = gpp->gpp_size; 186 if (vtoc8_align(table, &start, &size) != 0) 187 return (EINVAL); 188 189 KASSERT(entry->gpe_start <= start, (__func__)); 190 KASSERT(entry->gpe_end >= start + size - 1, (__func__)); 191 entry->gpe_start = start; 192 entry->gpe_end = start + size - 1; 193 194 be16enc(&table->vtoc.part[index].tag, tag); 195 be16enc(&table->vtoc.part[index].flag, 0); 196 be32enc(&table->vtoc.timestamp[index], 0); 197 be32enc(&table->vtoc.map[index].cyl, start / table->secpercyl); 198 be32enc(&table->vtoc.map[index].nblks, size); 199 return (0); 200} 201 202static int 203g_part_vtoc8_create(struct g_part_table *basetable, struct g_part_parms *gpp) 204{ 205 struct g_provider *pp; 206 struct g_part_entry *entry; 207 struct g_part_vtoc8_table *table; 208 uint64_t msize; 209 uint32_t acyls, ncyls, pcyls; 210 211 pp = gpp->gpp_provider; 212 213 if (pp->sectorsize < sizeof(struct vtoc8)) 214 return (ENOSPC); 215 if (pp->sectorsize > sizeof(struct vtoc8)) 216 return (ENXIO); 217 218 table = (struct g_part_vtoc8_table *)basetable; 219 220 msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 221 table->secpercyl = basetable->gpt_sectors * basetable->gpt_heads; 222 pcyls = msize / table->secpercyl; 223 acyls = 2; 224 ncyls = pcyls - acyls; 225 msize = ncyls * table->secpercyl; 226 227 sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u", 228 (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads, 229 basetable->gpt_sectors); 230 be32enc(&table->vtoc.version, VTOC_VERSION); 231 be16enc(&table->vtoc.nparts, VTOC8_NPARTS); 232 be32enc(&table->vtoc.sanity, VTOC_SANITY); 233 be16enc(&table->vtoc.rpm, 3600); 234 be16enc(&table->vtoc.physcyls, pcyls); 235 be16enc(&table->vtoc.ncyls, ncyls); 236 be16enc(&table->vtoc.altcyls, acyls); 237 be16enc(&table->vtoc.nheads, basetable->gpt_heads); 238 be16enc(&table->vtoc.nsecs, basetable->gpt_sectors); 239 be16enc(&table->vtoc.magic, VTOC_MAGIC); 240 241 basetable->gpt_first = 0; 242 basetable->gpt_last = msize - 1; 243 basetable->gpt_isleaf = 1; 244 245 entry = g_part_new_entry(basetable, VTOC_RAW_PART + 1, 246 basetable->gpt_first, basetable->gpt_last); 247 entry->gpe_internal = 1; 248 be16enc(&table->vtoc.part[VTOC_RAW_PART].tag, VTOC_TAG_BACKUP); 249 be32enc(&table->vtoc.map[VTOC_RAW_PART].nblks, msize); 250 return (0); 251} 252 253static int 254g_part_vtoc8_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 255{ 256 257 /* Wipe the first sector to clear the partitioning. */ 258 basetable->gpt_smhead |= 1; 259 return (0); 260} 261 262static void 263g_part_vtoc8_dumpconf(struct g_part_table *basetable, 264 struct g_part_entry *entry, struct sbuf *sb, const char *indent) 265{ 266 struct g_part_vtoc8_table *table; 267 268 table = (struct g_part_vtoc8_table *)basetable; 269 if (indent == NULL) { 270 /* conftxt: libdisk compatibility */ 271 sbuf_printf(sb, " xs SUN sc %u hd %u alt %u", 272 be16dec(&table->vtoc.nsecs), be16dec(&table->vtoc.nheads), 273 be16dec(&table->vtoc.altcyls)); 274 } else if (entry != NULL) { 275 /* confxml: partition entry information */ 276 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 277 be16dec(&table->vtoc.part[entry->gpe_index - 1].tag)); 278 } else { 279 /* confxml: scheme information */ 280 } 281} 282 283static int 284g_part_vtoc8_dumpto(struct g_part_table *basetable, 285 struct g_part_entry *entry) 286{ 287 struct g_part_vtoc8_table *table; 288 uint16_t tag; 289 290 /* 291 * Allow dumping to a swap partition or a partition that 292 * has no type. 293 */ 294 table = (struct g_part_vtoc8_table *)basetable; 295 tag = be16dec(&table->vtoc.part[entry->gpe_index - 1].tag); 296 return ((tag == 0 || tag == VTOC_TAG_FREEBSD_SWAP || 297 tag == VTOC_TAG_SWAP) ? 1 : 0); 298} 299 300static int 301g_part_vtoc8_modify(struct g_part_table *basetable, 302 struct g_part_entry *entry, struct g_part_parms *gpp) 303{ 304 struct g_part_vtoc8_table *table; 305 int error; 306 uint16_t tag; 307 308 if (gpp->gpp_parms & G_PART_PARM_LABEL) 309 return (EINVAL); 310 311 table = (struct g_part_vtoc8_table *)basetable; 312 if (gpp->gpp_parms & G_PART_PARM_TYPE) { 313 error = vtoc8_parse_type(gpp->gpp_type, &tag); 314 if (error) 315 return(error); 316 317 be16enc(&table->vtoc.part[entry->gpe_index - 1].tag, tag); 318 } 319 return (0); 320} 321 322static int 323vtoc8_set_rawsize(struct g_part_table *basetable, struct g_provider *pp) 324{ 325 struct g_part_vtoc8_table *table; 326 struct g_part_entry *baseentry; 327 off_t msize; 328 uint32_t acyls, ncyls, pcyls; 329 330 table = (struct g_part_vtoc8_table *)basetable; 331 msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 332 pcyls = msize / table->secpercyl; 333 if (pcyls > UINT16_MAX) 334 return (ERANGE); 335 acyls = be16dec(&table->vtoc.altcyls); 336 ncyls = pcyls - acyls; 337 msize = ncyls * table->secpercyl; 338 basetable->gpt_last = msize - 1; 339 340 bzero(table->vtoc.ascii, sizeof(table->vtoc.ascii)); 341 sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u", 342 (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads, 343 basetable->gpt_sectors); 344 be16enc(&table->vtoc.physcyls, pcyls); 345 be16enc(&table->vtoc.ncyls, ncyls); 346 be32enc(&table->vtoc.map[VTOC_RAW_PART].nblks, msize); 347 if (be32dec(&table->vtoc.sanity) == VTOC_SANITY) 348 be16enc(&table->vtoc.part[VTOC_RAW_PART].tag, VTOC_TAG_BACKUP); 349 LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 350 if (baseentry->gpe_index == VTOC_RAW_PART + 1) { 351 baseentry->gpe_end = basetable->gpt_last; 352 return (0); 353 } 354 } 355 return (ENXIO); 356} 357 358static int 359g_part_vtoc8_resize(struct g_part_table *basetable, 360 struct g_part_entry *entry, struct g_part_parms *gpp) 361{ 362 struct g_part_vtoc8_table *table; 363 struct g_provider *pp; 364 uint64_t size; 365 366 if (entry == NULL) { 367 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 368 return (vtoc8_set_rawsize(basetable, pp)); 369 } 370 table = (struct g_part_vtoc8_table *)basetable; 371 size = gpp->gpp_size; 372 if (vtoc8_align(table, NULL, &size) != 0) 373 return (EINVAL); 374 /* XXX: prevent unexpected shrinking. */ 375 pp = entry->gpe_pp; 376 if ((g_debugflags & G_F_FOOTSHOOTING) == 0 && size < gpp->gpp_size && 377 pp->mediasize / pp->sectorsize > size) 378 return (EBUSY); 379 entry->gpe_end = entry->gpe_start + size - 1; 380 be32enc(&table->vtoc.map[entry->gpe_index - 1].nblks, size); 381 382 return (0); 383} 384 385static const char * 386g_part_vtoc8_name(struct g_part_table *table, struct g_part_entry *baseentry, 387 char *buf, size_t bufsz) 388{ 389 390 snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); 391 return (buf); 392} 393 394static int 395g_part_vtoc8_probe(struct g_part_table *table, struct g_consumer *cp) 396{ 397 struct g_provider *pp; 398 u_char *buf; 399 int error, ofs, res; 400 uint16_t cksum, magic; 401 402 pp = cp->provider; 403 404 /* Sanity-check the provider. */ 405 if (pp->sectorsize != sizeof(struct vtoc8)) 406 return (ENOSPC); 407 408 /* Check that there's a disklabel. */ 409 buf = g_read_data(cp, 0, pp->sectorsize, &error); 410 if (buf == NULL) 411 return (error); 412 413 res = ENXIO; /* Assume mismatch */ 414 415 /* Check the magic */ 416 magic = be16dec(buf + offsetof(struct vtoc8, magic)); 417 if (magic != VTOC_MAGIC) 418 goto out; 419 420 /* Check the sum */ 421 cksum = 0; 422 for (ofs = 0; ofs < sizeof(struct vtoc8); ofs += 2) 423 cksum ^= be16dec(buf + ofs); 424 if (cksum != 0) 425 goto out; 426 427 res = G_PART_PROBE_PRI_NORM; 428 429 out: 430 g_free(buf); 431 return (res); 432} 433 434static int 435g_part_vtoc8_read(struct g_part_table *basetable, struct g_consumer *cp) 436{ 437 struct g_provider *pp; 438 struct g_part_vtoc8_table *table; 439 struct g_part_entry *entry; 440 u_char *buf; 441 off_t chs, msize; 442 uint64_t offset, size; 443 u_int cyls, heads, sectors; 444 int error, index, withtags; 445 uint16_t tag; 446 447 pp = cp->provider; 448 buf = g_read_data(cp, 0, pp->sectorsize, &error); 449 if (buf == NULL) 450 return (error); 451 452 table = (struct g_part_vtoc8_table *)basetable; 453 bcopy(buf, &table->vtoc, sizeof(table->vtoc)); 454 g_free(buf); 455 456 msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 457 sectors = be16dec(&table->vtoc.nsecs); 458 if (sectors < 1) 459 goto invalid_label; 460 if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) { 461 g_part_geometry_heads(msize, sectors, &chs, &heads); 462 if (chs != 0) { 463 basetable->gpt_sectors = sectors; 464 basetable->gpt_heads = heads; 465 } 466 } 467 468 heads = be16dec(&table->vtoc.nheads); 469 if (heads < 1) 470 goto invalid_label; 471 if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom) 472 basetable->gpt_heads = heads; 473 /* 474 * Except for ATA disks > 32GB, Solaris uses the native geometry 475 * as reported by the target for the labels while da(4) typically 476 * uses a synthetic one so we don't complain too loudly if these 477 * geometries don't match. 478 */ 479 if (bootverbose && (sectors != basetable->gpt_sectors || 480 heads != basetable->gpt_heads)) 481 printf("GEOM: %s: geometry does not match VTOC8 label " 482 "(label: %uh,%us GEOM: %uh,%us).\n", pp->name, heads, 483 sectors, basetable->gpt_heads, basetable->gpt_sectors); 484 485 table->secpercyl = heads * sectors; 486 cyls = be16dec(&table->vtoc.ncyls); 487 chs = cyls * table->secpercyl; 488 if (chs < 1 || chs > msize) 489 goto invalid_label; 490 491 basetable->gpt_first = 0; 492 basetable->gpt_last = chs - 1; 493 basetable->gpt_isleaf = 1; 494 495 withtags = (be32dec(&table->vtoc.sanity) == VTOC_SANITY) ? 1 : 0; 496 if (!withtags) { 497 printf("GEOM: %s: adding VTOC8 information.\n", pp->name); 498 be32enc(&table->vtoc.version, VTOC_VERSION); 499 bzero(&table->vtoc.volume, VTOC_VOLUME_LEN); 500 be16enc(&table->vtoc.nparts, VTOC8_NPARTS); 501 bzero(&table->vtoc.part, sizeof(table->vtoc.part)); 502 be32enc(&table->vtoc.sanity, VTOC_SANITY); 503 } 504 505 basetable->gpt_entries = be16dec(&table->vtoc.nparts); 506 if (basetable->gpt_entries < g_part_vtoc8_scheme.gps_minent || 507 basetable->gpt_entries > g_part_vtoc8_scheme.gps_maxent) 508 goto invalid_label; 509 510 for (index = basetable->gpt_entries - 1; index >= 0; index--) { 511 offset = be32dec(&table->vtoc.map[index].cyl) * 512 table->secpercyl; 513 size = be32dec(&table->vtoc.map[index].nblks); 514 if (size == 0) 515 continue; 516 if (withtags) 517 tag = be16dec(&table->vtoc.part[index].tag); 518 else 519 tag = (index == VTOC_RAW_PART) 520 ? VTOC_TAG_BACKUP 521 : VTOC_TAG_UNASSIGNED; 522 523 if (index == VTOC_RAW_PART && tag != VTOC_TAG_BACKUP) 524 continue; 525 if (index != VTOC_RAW_PART && tag == VTOC_TAG_BACKUP) 526 continue; 527 entry = g_part_new_entry(basetable, index + 1, offset, 528 offset + size - 1); 529 if (tag == VTOC_TAG_BACKUP) 530 entry->gpe_internal = 1; 531 532 if (!withtags) 533 be16enc(&table->vtoc.part[index].tag, tag); 534 } 535 536 return (0); 537 538 invalid_label: 539 printf("GEOM: %s: invalid VTOC8 label.\n", pp->name); 540 return (EINVAL); 541} 542 543static const char * 544g_part_vtoc8_type(struct g_part_table *basetable, struct g_part_entry *entry, 545 char *buf, size_t bufsz) 546{ 547 struct g_part_vtoc8_table *table; 548 uint16_t tag; 549 550 table = (struct g_part_vtoc8_table *)basetable; 551 tag = be16dec(&table->vtoc.part[entry->gpe_index - 1].tag); 552 if (tag == VTOC_TAG_FREEBSD_NANDFS) 553 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS)); 554 if (tag == VTOC_TAG_FREEBSD_SWAP) 555 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)); 556 if (tag == VTOC_TAG_FREEBSD_UFS) 557 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)); 558 if (tag == VTOC_TAG_FREEBSD_VINUM) 559 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)); 560 if (tag == VTOC_TAG_FREEBSD_ZFS) 561 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS)); 562 snprintf(buf, bufsz, "!%d", tag); 563 return (buf); 564} 565 566static int 567g_part_vtoc8_write(struct g_part_table *basetable, struct g_consumer *cp) 568{ 569 struct g_provider *pp; 570 struct g_part_entry *entry; 571 struct g_part_vtoc8_table *table; 572 uint16_t sum; 573 u_char *p; 574 int error, index, match, offset; 575 576 pp = cp->provider; 577 table = (struct g_part_vtoc8_table *)basetable; 578 entry = LIST_FIRST(&basetable->gpt_entry); 579 for (index = 0; index < basetable->gpt_entries; index++) { 580 match = (entry != NULL && index == entry->gpe_index - 1) 581 ? 1 : 0; 582 if (match) { 583 if (entry->gpe_deleted) { 584 be16enc(&table->vtoc.part[index].tag, 0); 585 be16enc(&table->vtoc.part[index].flag, 0); 586 be32enc(&table->vtoc.map[index].cyl, 0); 587 be32enc(&table->vtoc.map[index].nblks, 0); 588 } 589 entry = LIST_NEXT(entry, gpe_entry); 590 } 591 } 592 593 /* Calculate checksum. */ 594 sum = 0; 595 p = (void *)&table->vtoc; 596 for (offset = 0; offset < sizeof(table->vtoc) - 2; offset += 2) 597 sum ^= be16dec(p + offset); 598 be16enc(&table->vtoc.cksum, sum); 599 600 error = g_write_data(cp, 0, p, pp->sectorsize); 601 return (error); 602} 603