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