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