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