g_part_bsd64.c revision 299629
1/*- 2 * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org> 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/10/sys/geom/part/g_part_bsd64.c 299629 2016-05-13 08:54:08Z ngie $"); 29 30#include <sys/param.h> 31#include <sys/bio.h> 32#include <sys/disklabel.h> 33#include <sys/endian.h> 34#include <sys/gpt.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 <geom/geom.h> 46#include <geom/geom_int.h> 47#include <geom/part/g_part.h> 48 49#include "g_part_if.h" 50 51FEATURE(geom_part_bsd64, "GEOM partitioning class for 64-bit BSD disklabels"); 52 53/* XXX: move this to sys/disklabel64.h */ 54#define DISKMAGIC64 ((uint32_t)0xc4464c59) 55#define MAXPARTITIONS64 16 56#define RESPARTITIONS64 32 57 58struct disklabel64 { 59 char d_reserved0[512]; /* reserved or unused */ 60 u_int32_t d_magic; /* the magic number */ 61 u_int32_t d_crc; /* crc32() d_magic thru last part */ 62 u_int32_t d_align; /* partition alignment requirement */ 63 u_int32_t d_npartitions; /* number of partitions */ 64 struct uuid d_stor_uuid; /* unique uuid for label */ 65 66 u_int64_t d_total_size; /* total size incl everything (bytes) */ 67 u_int64_t d_bbase; /* boot area base offset (bytes) */ 68 /* boot area is pbase - bbase */ 69 u_int64_t d_pbase; /* first allocatable offset (bytes) */ 70 u_int64_t d_pstop; /* last allocatable offset+1 (bytes) */ 71 u_int64_t d_abase; /* location of backup copy if not 0 */ 72 73 u_char d_packname[64]; 74 u_char d_reserved[64]; 75 76 /* 77 * Note: offsets are relative to the base of the slice, NOT to 78 * d_pbase. Unlike 32 bit disklabels the on-disk format for 79 * a 64 bit disklabel remains slice-relative. 80 * 81 * An uninitialized partition has a p_boffset and p_bsize of 0. 82 * 83 * If p_fstype is not supported for a live partition it is set 84 * to FS_OTHER. This is typically the case when the filesystem 85 * is identified by its uuid. 86 */ 87 struct partition64 { /* the partition table */ 88 u_int64_t p_boffset; /* slice relative offset, in bytes */ 89 u_int64_t p_bsize; /* size of partition, in bytes */ 90 u_int8_t p_fstype; 91 u_int8_t p_unused01; /* reserved, must be 0 */ 92 u_int8_t p_unused02; /* reserved, must be 0 */ 93 u_int8_t p_unused03; /* reserved, must be 0 */ 94 u_int32_t p_unused04; /* reserved, must be 0 */ 95 u_int32_t p_unused05; /* reserved, must be 0 */ 96 u_int32_t p_unused06; /* reserved, must be 0 */ 97 struct uuid p_type_uuid;/* mount type as UUID */ 98 struct uuid p_stor_uuid;/* unique uuid for storage */ 99 } d_partitions[MAXPARTITIONS64];/* actually may be more */ 100}; 101 102struct g_part_bsd64_table { 103 struct g_part_table base; 104 105 uint32_t d_align; 106 uint64_t d_bbase; 107 uint64_t d_abase; 108 struct uuid d_stor_uuid; 109 char d_reserved0[512]; 110 u_char d_packname[64]; 111 u_char d_reserved[64]; 112}; 113 114struct g_part_bsd64_entry { 115 struct g_part_entry base; 116 117 uint8_t fstype; 118 struct uuid type_uuid; 119 struct uuid stor_uuid; 120}; 121 122static int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *, 123 struct g_part_parms *); 124static int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *); 125static int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *); 126static int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *); 127static void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *, 128 struct sbuf *, const char *); 129static int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *); 130static int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *, 131 struct g_part_parms *); 132static const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *, 133 char *, size_t); 134static int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *); 135static int g_part_bsd64_read(struct g_part_table *, struct g_consumer *); 136static const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *, 137 char *, size_t); 138static int g_part_bsd64_write(struct g_part_table *, struct g_consumer *); 139static int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *, 140 struct g_part_parms *); 141 142static kobj_method_t g_part_bsd64_methods[] = { 143 KOBJMETHOD(g_part_add, g_part_bsd64_add), 144 KOBJMETHOD(g_part_bootcode, g_part_bsd64_bootcode), 145 KOBJMETHOD(g_part_create, g_part_bsd64_create), 146 KOBJMETHOD(g_part_destroy, g_part_bsd64_destroy), 147 KOBJMETHOD(g_part_dumpconf, g_part_bsd64_dumpconf), 148 KOBJMETHOD(g_part_dumpto, g_part_bsd64_dumpto), 149 KOBJMETHOD(g_part_modify, g_part_bsd64_modify), 150 KOBJMETHOD(g_part_resize, g_part_bsd64_resize), 151 KOBJMETHOD(g_part_name, g_part_bsd64_name), 152 KOBJMETHOD(g_part_probe, g_part_bsd64_probe), 153 KOBJMETHOD(g_part_read, g_part_bsd64_read), 154 KOBJMETHOD(g_part_type, g_part_bsd64_type), 155 KOBJMETHOD(g_part_write, g_part_bsd64_write), 156 { 0, 0 } 157}; 158 159static struct g_part_scheme g_part_bsd64_scheme = { 160 "BSD64", 161 g_part_bsd64_methods, 162 sizeof(struct g_part_bsd64_table), 163 .gps_entrysz = sizeof(struct g_part_bsd64_entry), 164 .gps_minent = MAXPARTITIONS64, 165 .gps_maxent = MAXPARTITIONS64 166}; 167G_PART_SCHEME_DECLARE(g_part_bsd64); 168 169#define EQUUID(a, b) (memcmp(a, b, sizeof(struct uuid)) == 0) 170static struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED; 171static struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP; 172static struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1; 173static struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM; 174static struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD; 175static struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY; 176static struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER; 177static struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2; 178static struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 179static struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; 180static struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 181static struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 182static struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 183static struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 184 185struct bsd64_uuid_alias { 186 struct uuid *uuid; 187 uint8_t fstype; 188 int alias; 189}; 190static struct bsd64_uuid_alias dfbsd_alias_match[] = { 191 { &bsd64_uuid_dfbsd_swap, FS_SWAP, G_PART_ALIAS_DFBSD_SWAP }, 192 { &bsd64_uuid_dfbsd_ufs1, FS_BSDFFS, G_PART_ALIAS_DFBSD_UFS }, 193 { &bsd64_uuid_dfbsd_vinum, FS_VINUM, G_PART_ALIAS_DFBSD_VINUM }, 194 { &bsd64_uuid_dfbsd_ccd, FS_CCD, G_PART_ALIAS_DFBSD_CCD }, 195 { &bsd64_uuid_dfbsd_legacy, FS_OTHER, G_PART_ALIAS_DFBSD_LEGACY }, 196 { &bsd64_uuid_dfbsd_hammer, FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER }, 197 { &bsd64_uuid_dfbsd_hammer2, FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 }, 198 { NULL, 0, 0} 199}; 200static struct bsd64_uuid_alias fbsd_alias_match[] = { 201 { &bsd64_uuid_freebsd_boot, FS_OTHER, G_PART_ALIAS_FREEBSD_BOOT }, 202 { &bsd64_uuid_freebsd_swap, FS_OTHER, G_PART_ALIAS_FREEBSD_SWAP }, 203 { &bsd64_uuid_freebsd_ufs, FS_OTHER, G_PART_ALIAS_FREEBSD_UFS }, 204 { &bsd64_uuid_freebsd_zfs, FS_OTHER, G_PART_ALIAS_FREEBSD_ZFS }, 205 { &bsd64_uuid_freebsd_vinum, FS_OTHER, G_PART_ALIAS_FREEBSD_VINUM }, 206 { &bsd64_uuid_freebsd_nandfs, FS_OTHER, G_PART_ALIAS_FREEBSD_NANDFS }, 207 { NULL, 0, 0} 208}; 209 210static int 211bsd64_parse_type(const char *type, struct g_part_bsd64_entry *entry) 212{ 213 struct uuid tmp; 214 const struct bsd64_uuid_alias *uap; 215 const char *alias; 216 char *p; 217 long lt; 218 int error; 219 220 if (type[0] == '!') { 221 if (type[1] == '\0') 222 return (EINVAL); 223 lt = strtol(type + 1, &p, 0); 224 /* The type specified as number */ 225 if (*p == '\0') { 226 if (lt <= 0 || lt > 255) 227 return (EINVAL); 228 entry->fstype = lt; 229 entry->type_uuid = bsd64_uuid_unused; 230 return (0); 231 } 232 /* The type specified as uuid */ 233 error = parse_uuid(type + 1, &tmp); 234 if (error != 0) 235 return (error); 236 if (EQUUID(&tmp, &bsd64_uuid_unused)) 237 return (EINVAL); 238 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) { 239 if (EQUUID(&tmp, uap->uuid)) { 240 /* Prefer fstype for known uuids */ 241 entry->type_uuid = bsd64_uuid_unused; 242 entry->fstype = uap->fstype; 243 return (0); 244 } 245 } 246 entry->type_uuid = tmp; 247 entry->fstype = FS_OTHER; 248 return (0); 249 } 250 /* The type specified as symbolic alias name */ 251 for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) { 252 alias = g_part_alias_name(uap->alias); 253 if (!strcasecmp(type, alias)) { 254 entry->type_uuid = *uap->uuid; 255 entry->fstype = uap->fstype; 256 return (0); 257 } 258 } 259 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) { 260 alias = g_part_alias_name(uap->alias); 261 if (!strcasecmp(type, alias)) { 262 entry->type_uuid = bsd64_uuid_unused; 263 entry->fstype = uap->fstype; 264 return (0); 265 } 266 } 267 return (EINVAL); 268} 269 270static int 271g_part_bsd64_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 272 struct g_part_parms *gpp) 273{ 274 struct g_part_bsd64_entry *entry; 275 276 if (gpp->gpp_parms & G_PART_PARM_LABEL) 277 return (EINVAL); 278 279 entry = (struct g_part_bsd64_entry *)baseentry; 280 if (bsd64_parse_type(gpp->gpp_type, entry) != 0) 281 return (EINVAL); 282 kern_uuidgen(&entry->stor_uuid, 1); 283 return (0); 284} 285 286static int 287g_part_bsd64_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 288{ 289 290 return (EOPNOTSUPP); 291} 292 293#define PALIGN_SIZE (1024 * 1024) 294#define PALIGN_MASK (PALIGN_SIZE - 1) 295#define BLKSIZE (4 * 1024) 296#define BOOTSIZE (32 * 1024) 297#define DALIGN_SIZE (32 * 1024) 298static int 299g_part_bsd64_create(struct g_part_table *basetable, struct g_part_parms *gpp) 300{ 301 struct g_part_bsd64_table *table; 302 struct g_part_entry *baseentry; 303 struct g_provider *pp; 304 uint64_t blkmask, pbase; 305 uint32_t blksize, ressize; 306 307 pp = gpp->gpp_provider; 308 if (pp->mediasize < 2* PALIGN_SIZE) 309 return (ENOSPC); 310 311 /* 312 * Use at least 4KB block size. Blksize is stored in the d_align. 313 * XXX: Actually it is used just for calculate d_bbase and used 314 * for better alignment in bsdlabel64(8). 315 */ 316 blksize = pp->sectorsize < BLKSIZE ? BLKSIZE: pp->sectorsize; 317 blkmask = blksize - 1; 318 /* Reserve enough space for RESPARTITIONS64 partitions. */ 319 ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]); 320 ressize = (ressize + blkmask) & ~blkmask; 321 /* 322 * Reserve enough space for bootcode and align first allocatable 323 * offset to PALIGN_SIZE. 324 * XXX: Currently DragonFlyBSD has 32KB bootcode, but the size could 325 * be bigger, because it is possible change it (it is equal pbase-bbase) 326 * in the bsdlabel64(8). 327 */ 328 pbase = ressize + ((BOOTSIZE + blkmask) & ~blkmask); 329 pbase = (pbase + PALIGN_MASK) & ~PALIGN_MASK; 330 /* 331 * Take physical offset into account and make first allocatable 332 * offset 32KB aligned to the start of the physical disk. 333 * XXX: Actually there are no such restrictions, this is how 334 * DragonFlyBSD behaves. 335 */ 336 pbase += DALIGN_SIZE - pp->stripeoffset % DALIGN_SIZE; 337 338 table = (struct g_part_bsd64_table *)basetable; 339 table->d_align = blksize; 340 table->d_bbase = ressize / pp->sectorsize; 341 table->d_abase = ((pp->mediasize - ressize) & 342 ~blkmask) / pp->sectorsize; 343 kern_uuidgen(&table->d_stor_uuid, 1); 344 basetable->gpt_first = pbase / pp->sectorsize; 345 basetable->gpt_last = table->d_abase - 1; /* XXX */ 346 /* 347 * Create 'c' partition and make it internal, so user will not be 348 * able use it. 349 */ 350 baseentry = g_part_new_entry(basetable, RAW_PART + 1, 0, 0); 351 baseentry->gpe_internal = 1; 352 return (0); 353} 354 355static int 356g_part_bsd64_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 357{ 358 struct g_provider *pp; 359 360 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 361 if (pp->sectorsize > offsetof(struct disklabel64, d_magic)) 362 basetable->gpt_smhead |= 1; 363 else 364 basetable->gpt_smhead |= 3; 365 return (0); 366} 367 368static void 369g_part_bsd64_dumpconf(struct g_part_table *basetable, 370 struct g_part_entry *baseentry, struct sbuf *sb, const char *indent) 371{ 372 struct g_part_bsd64_table *table; 373 struct g_part_bsd64_entry *entry; 374 char buf[sizeof(table->d_packname)]; 375 376 entry = (struct g_part_bsd64_entry *)baseentry; 377 if (indent == NULL) { 378 /* conftxt: libdisk compatibility */ 379 sbuf_printf(sb, " xs BSD64 xt %u", entry->fstype); 380 } else if (entry != NULL) { 381 /* confxml: partition entry information */ 382 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 383 entry->fstype); 384 if (!EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) { 385 sbuf_printf(sb, "%s<type_uuid>", indent); 386 sbuf_printf_uuid(sb, &entry->type_uuid); 387 sbuf_printf(sb, "</type_uuid>\n"); 388 } 389 sbuf_printf(sb, "%s<stor_uuid>", indent); 390 sbuf_printf_uuid(sb, &entry->stor_uuid); 391 sbuf_printf(sb, "</stor_uuid>\n"); 392 } else { 393 /* confxml: scheme information */ 394 table = (struct g_part_bsd64_table *)basetable; 395 sbuf_printf(sb, "%s<bootbase>%ju</bootbase>\n", indent, 396 (uintmax_t)table->d_bbase); 397 if (table->d_abase) 398 sbuf_printf(sb, "%s<backupbase>%ju</backupbase>\n", 399 indent, (uintmax_t)table->d_abase); 400 sbuf_printf(sb, "%s<stor_uuid>", indent); 401 sbuf_printf_uuid(sb, &table->d_stor_uuid); 402 sbuf_printf(sb, "</stor_uuid>\n"); 403 sbuf_printf(sb, "%s<label>", indent); 404 strncpy(buf, table->d_packname, sizeof(buf) - 1); 405 buf[sizeof(buf) - 1] = '\0'; 406 g_conf_printf_escaped(sb, "%s", buf); 407 sbuf_printf(sb, "</label>\n"); 408 } 409} 410 411static int 412g_part_bsd64_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 413{ 414 struct g_part_bsd64_entry *entry; 415 416 /* Allow dumping to a swap partition. */ 417 entry = (struct g_part_bsd64_entry *)baseentry; 418 if (entry->fstype == FS_SWAP || 419 EQUUID(&entry->type_uuid, &bsd64_uuid_dfbsd_swap) || 420 EQUUID(&entry->type_uuid, &bsd64_uuid_freebsd_swap)) 421 return (1); 422 return (0); 423} 424 425static int 426g_part_bsd64_modify(struct g_part_table *basetable, 427 struct g_part_entry *baseentry, struct g_part_parms *gpp) 428{ 429 struct g_part_bsd64_entry *entry; 430 431 if (gpp->gpp_parms & G_PART_PARM_LABEL) 432 return (EINVAL); 433 434 entry = (struct g_part_bsd64_entry *)baseentry; 435 if (gpp->gpp_parms & G_PART_PARM_TYPE) 436 return (bsd64_parse_type(gpp->gpp_type, entry)); 437 return (0); 438} 439 440static int 441g_part_bsd64_resize(struct g_part_table *basetable, 442 struct g_part_entry *baseentry, struct g_part_parms *gpp) 443{ 444 struct g_part_bsd64_table *table; 445 struct g_provider *pp; 446 447 if (baseentry == NULL) { 448 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 449 table = (struct g_part_bsd64_table *)basetable; 450 table->d_abase = ((pp->mediasize - 451 table->d_bbase * pp->sectorsize) & ~(table->d_align - 1)) / 452 pp->sectorsize; 453 basetable->gpt_last = table->d_abase - 1; 454 return (0); 455 } 456 baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 457 return (0); 458} 459 460static const char * 461g_part_bsd64_name(struct g_part_table *table, struct g_part_entry *baseentry, 462 char *buf, size_t bufsz) 463{ 464 465 snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); 466 return (buf); 467} 468 469static int 470g_part_bsd64_probe(struct g_part_table *table, struct g_consumer *cp) 471{ 472 struct g_provider *pp; 473 uint32_t v; 474 int error; 475 u_char *buf; 476 477 pp = cp->provider; 478 if (pp->mediasize < 2 * PALIGN_SIZE) 479 return (ENOSPC); 480 v = (pp->sectorsize + 481 offsetof(struct disklabel64, d_magic)) & ~(pp->sectorsize - 1); 482 buf = g_read_data(cp, 0, v, &error); 483 if (buf == NULL) 484 return (error); 485 v = le32dec(buf + offsetof(struct disklabel64, d_magic)); 486 g_free(buf); 487 return (v == DISKMAGIC64 ? G_PART_PROBE_PRI_HIGH: ENXIO); 488} 489 490static int 491g_part_bsd64_read(struct g_part_table *basetable, struct g_consumer *cp) 492{ 493 struct g_part_bsd64_table *table; 494 struct g_part_bsd64_entry *entry; 495 struct g_part_entry *baseentry; 496 struct g_provider *pp; 497 struct disklabel64 *dlp; 498 uint64_t v64, sz; 499 uint32_t v32; 500 int error, index; 501 u_char *buf; 502 503 pp = cp->provider; 504 table = (struct g_part_bsd64_table *)basetable; 505 v32 = (pp->sectorsize + 506 sizeof(struct disklabel64) - 1) & ~(pp->sectorsize - 1); 507 buf = g_read_data(cp, 0, v32, &error); 508 if (buf == NULL) 509 return (error); 510 511 dlp = (struct disklabel64 *)buf; 512 basetable->gpt_entries = le32toh(dlp->d_npartitions); 513 if (basetable->gpt_entries > MAXPARTITIONS64 || 514 basetable->gpt_entries < 1) 515 goto invalid_label; 516 v32 = le32toh(dlp->d_crc); 517 dlp->d_crc = 0; 518 if (crc32(&dlp->d_magic, offsetof(struct disklabel64, 519 d_partitions[basetable->gpt_entries]) - 520 offsetof(struct disklabel64, d_magic)) != v32) 521 goto invalid_label; 522 table->d_align = le32toh(dlp->d_align); 523 if (table->d_align == 0 || (table->d_align & (pp->sectorsize - 1))) 524 goto invalid_label; 525 if (le64toh(dlp->d_total_size) > pp->mediasize) 526 goto invalid_label; 527 v64 = le64toh(dlp->d_pbase); 528 if (v64 % pp->sectorsize) 529 goto invalid_label; 530 basetable->gpt_first = v64 / pp->sectorsize; 531 v64 = le64toh(dlp->d_pstop); 532 if (v64 % pp->sectorsize) 533 goto invalid_label; 534 basetable->gpt_last = v64 / pp->sectorsize; 535 basetable->gpt_isleaf = 1; 536 v64 = le64toh(dlp->d_bbase); 537 if (v64 % pp->sectorsize) 538 goto invalid_label; 539 table->d_bbase = v64 / pp->sectorsize; 540 v64 = le64toh(dlp->d_abase); 541 if (v64 % pp->sectorsize) 542 goto invalid_label; 543 table->d_abase = v64 / pp->sectorsize; 544 le_uuid_dec(&dlp->d_stor_uuid, &table->d_stor_uuid); 545 for (index = basetable->gpt_entries - 1; index >= 0; index--) { 546 if (index == RAW_PART) { 547 /* Skip 'c' partition. */ 548 baseentry = g_part_new_entry(basetable, 549 index + 1, 0, 0); 550 baseentry->gpe_internal = 1; 551 continue; 552 } 553 v64 = le64toh(dlp->d_partitions[index].p_boffset); 554 sz = le64toh(dlp->d_partitions[index].p_bsize); 555 if (sz == 0 && v64 == 0) 556 continue; 557 if (sz == 0 || (v64 % pp->sectorsize) || (sz % pp->sectorsize)) 558 goto invalid_label; 559 baseentry = g_part_new_entry(basetable, index + 1, 560 v64 / pp->sectorsize, (v64 + sz) / pp->sectorsize - 1); 561 entry = (struct g_part_bsd64_entry *)baseentry; 562 le_uuid_dec(&dlp->d_partitions[index].p_type_uuid, 563 &entry->type_uuid); 564 le_uuid_dec(&dlp->d_partitions[index].p_stor_uuid, 565 &entry->stor_uuid); 566 entry->fstype = dlp->d_partitions[index].p_fstype; 567 } 568 bcopy(dlp->d_reserved0, table->d_reserved0, 569 sizeof(table->d_reserved0)); 570 bcopy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 571 bcopy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 572 g_free(buf); 573 return (0); 574 575invalid_label: 576 g_free(buf); 577 return (EINVAL); 578} 579 580static const char * 581g_part_bsd64_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 582 char *buf, size_t bufsz) 583{ 584 struct g_part_bsd64_entry *entry; 585 struct bsd64_uuid_alias *uap; 586 587 entry = (struct g_part_bsd64_entry *)baseentry; 588 if (entry->fstype != FS_OTHER) { 589 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) 590 if (uap->fstype == entry->fstype) 591 return (g_part_alias_name(uap->alias)); 592 } else { 593 for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) 594 if (EQUUID(uap->uuid, &entry->type_uuid)) 595 return (g_part_alias_name(uap->alias)); 596 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) 597 if (EQUUID(uap->uuid, &entry->type_uuid)) 598 return (g_part_alias_name(uap->alias)); 599 } 600 if (EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) 601 snprintf(buf, bufsz, "!%d", entry->fstype); 602 else { 603 buf[0] = '!'; 604 snprintf_uuid(buf + 1, bufsz - 1, &entry->type_uuid); 605 } 606 return (buf); 607} 608 609static int 610g_part_bsd64_write(struct g_part_table *basetable, struct g_consumer *cp) 611{ 612 struct g_provider *pp; 613 struct g_part_entry *baseentry; 614 struct g_part_bsd64_entry *entry; 615 struct g_part_bsd64_table *table; 616 struct disklabel64 *dlp; 617 uint32_t v, sz; 618 int error, index; 619 620 pp = cp->provider; 621 table = (struct g_part_bsd64_table *)basetable; 622 sz = (pp->sectorsize + 623 sizeof(struct disklabel64) - 1) & ~(pp->sectorsize - 1); 624 dlp = g_malloc(sz, M_WAITOK | M_ZERO); 625 626 memcpy(dlp->d_reserved0, table->d_reserved0, 627 sizeof(table->d_reserved0)); 628 memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 629 memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 630 le32enc(&dlp->d_magic, DISKMAGIC64); 631 le32enc(&dlp->d_align, table->d_align); 632 le32enc(&dlp->d_npartitions, basetable->gpt_entries); 633 le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid); 634 le64enc(&dlp->d_total_size, pp->mediasize); 635 le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize); 636 le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize); 637 le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize); 638 le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize); 639 640 LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 641 if (baseentry->gpe_deleted) 642 continue; 643 index = baseentry->gpe_index - 1; 644 entry = (struct g_part_bsd64_entry *)baseentry; 645 if (index == RAW_PART) 646 continue; 647 le64enc(&dlp->d_partitions[index].p_boffset, 648 baseentry->gpe_start * pp->sectorsize); 649 le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize * 650 (baseentry->gpe_end - baseentry->gpe_start + 1)); 651 dlp->d_partitions[index].p_fstype = entry->fstype; 652 le_uuid_enc(&dlp->d_partitions[index].p_type_uuid, 653 &entry->type_uuid); 654 le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid, 655 &entry->stor_uuid); 656 } 657 /* Calculate checksum. */ 658 v = offsetof(struct disklabel64, 659 d_partitions[basetable->gpt_entries]) - 660 offsetof(struct disklabel64, d_magic); 661 le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v)); 662 error = g_write_data(cp, 0, dlp, sz); 663 g_free(dlp); 664 return (error); 665} 666 667