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 #include <sys/param.h> 29 #include <sys/bio.h> 30 #include <sys/gsb_crc32.h> 31 #include <sys/disklabel.h> 32 #include <sys/endian.h> 33 #include <sys/gpt.h> 34 #include <sys/kernel.h> 35 #include <sys/kobj.h> 36 #include <sys/limits.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/mutex.h> 40 #include <sys/queue.h> 41 #include <sys/sbuf.h> 42 #include <sys/systm.h> 43 #include <sys/sysctl.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 50 FEATURE(geom_part_bsd64, "GEOM partitioning class for 64-bit BSD disklabels"); 51 52 /* XXX: move this to sys/disklabel64.h */ 53 #define DISKMAGIC64 ((uint32_t)0xc4464c59) 54 #define MAXPARTITIONS64 16 55 #define RESPARTITIONS64 32 56 57 struct disklabel64 { 58 char d_reserved0[512]; /* reserved or unused */ 59 uint32_t d_magic; /* the magic number */ 60 uint32_t d_crc; /* crc32() d_magic through last part */ 61 uint32_t d_align; /* partition alignment requirement */ 62 uint32_t d_npartitions; /* number of partitions */ 63 struct uuid d_stor_uuid; /* unique uuid for label */ 64 65 uint64_t d_total_size; /* total size incl everything (bytes) */ 66 uint64_t d_bbase; /* boot area base offset (bytes) */ 67 /* boot area is pbase - bbase */ 68 uint64_t d_pbase; /* first allocatable offset (bytes) */ 69 uint64_t d_pstop; /* last allocatable offset+1 (bytes) */ 70 uint64_t d_abase; /* location of backup copy if not 0 */ 71 72 u_char d_packname[64]; 73 u_char d_reserved[64]; 74 75 /* 76 * Note: offsets are relative to the base of the slice, NOT to 77 * d_pbase. Unlike 32 bit disklabels the on-disk format for 78 * a 64 bit disklabel remains slice-relative. 79 * 80 * An uninitialized partition has a p_boffset and p_bsize of 0. 81 * 82 * If p_fstype is not supported for a live partition it is set 83 * to FS_OTHER. This is typically the case when the filesystem 84 * is identified by its uuid. 85 */ 86 struct partition64 { /* the partition table */ 87 uint64_t p_boffset; /* slice relative offset, in bytes */ 88 uint64_t p_bsize; /* size of partition, in bytes */ 89 uint8_t p_fstype; 90 uint8_t p_unused01; /* reserved, must be 0 */ 91 uint8_t p_unused02; /* reserved, must be 0 */ 92 uint8_t p_unused03; /* reserved, must be 0 */ 93 uint32_t p_unused04; /* reserved, must be 0 */ 94 uint32_t p_unused05; /* reserved, must be 0 */ 95 uint32_t p_unused06; /* reserved, must be 0 */ 96 struct uuid p_type_uuid;/* mount type as UUID */ 97 struct uuid p_stor_uuid;/* unique uuid for storage */ 98 } d_partitions[MAXPARTITIONS64];/* actually may be more */ 99 }; 100 101 struct g_part_bsd64_table { 102 struct g_part_table base; 103 104 uint32_t d_align; 105 uint64_t d_bbase; 106 uint64_t d_abase; 107 struct uuid d_stor_uuid; 108 char d_reserved0[512]; 109 u_char d_packname[64]; 110 u_char d_reserved[64]; 111 }; 112 113 struct g_part_bsd64_entry { 114 struct g_part_entry base; 115 116 uint8_t fstype; 117 struct uuid type_uuid; 118 struct uuid stor_uuid; 119 }; 120 121 static int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *, 122 struct g_part_parms *); 123 static int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *); 124 static int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *); 125 static int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *); 126 static void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *, 127 struct sbuf *, const char *); 128 static int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *); 129 static int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *, 130 struct g_part_parms *); 131 static const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *, 132 char *, size_t); 133 static int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *); 134 static int g_part_bsd64_read(struct g_part_table *, struct g_consumer *); 135 static const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *, 136 char *, size_t); 137 static int g_part_bsd64_write(struct g_part_table *, struct g_consumer *); 138 static int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *, 139 struct g_part_parms *); 140 141 static kobj_method_t g_part_bsd64_methods[] = { 142 KOBJMETHOD(g_part_add, g_part_bsd64_add), 143 KOBJMETHOD(g_part_bootcode, g_part_bsd64_bootcode), 144 KOBJMETHOD(g_part_create, g_part_bsd64_create), 145 KOBJMETHOD(g_part_destroy, g_part_bsd64_destroy), 146 KOBJMETHOD(g_part_dumpconf, g_part_bsd64_dumpconf), 147 KOBJMETHOD(g_part_dumpto, g_part_bsd64_dumpto), 148 KOBJMETHOD(g_part_modify, g_part_bsd64_modify), 149 KOBJMETHOD(g_part_resize, g_part_bsd64_resize), 150 KOBJMETHOD(g_part_name, g_part_bsd64_name), 151 KOBJMETHOD(g_part_probe, g_part_bsd64_probe), 152 KOBJMETHOD(g_part_read, g_part_bsd64_read), 153 KOBJMETHOD(g_part_type, g_part_bsd64_type), 154 KOBJMETHOD(g_part_write, g_part_bsd64_write), 155 { 0, 0 } 156 }; 157 158 static struct g_part_scheme g_part_bsd64_scheme = { 159 "BSD64", 160 g_part_bsd64_methods, 161 sizeof(struct g_part_bsd64_table), 162 .gps_entrysz = sizeof(struct g_part_bsd64_entry), 163 .gps_minent = MAXPARTITIONS64, 164 .gps_maxent = MAXPARTITIONS64 165 }; 166 G_PART_SCHEME_DECLARE(g_part_bsd64); 167 MODULE_VERSION(geom_part_bsd64, 0); 168 169 #define EQUUID(a, b) (memcmp(a, b, sizeof(struct uuid)) == 0) 170 static struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED; 171 static struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP; 172 static struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1; 173 static struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM; 174 static struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD; 175 static struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY; 176 static struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER; 177 static struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2; 178 static struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 179 static struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; 180 static struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 181 static struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 182 static struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 183 static struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 184 185 struct bsd64_uuid_alias { 186 struct uuid *uuid; 187 uint8_t fstype; 188 int alias; 189 }; 190 static 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 }; 200 static 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 210 static int 211 bsd64_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 270 static int 271 g_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 286 static int 287 g_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) 298 static int 299 g_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 355 static int 356 g_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 368 static void 369 g_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_cat(sb, "</type_uuid>\n"); 388 } 389 sbuf_printf(sb, "%s<stor_uuid>", indent); 390 sbuf_printf_uuid(sb, &entry->stor_uuid); 391 sbuf_cat(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_cat(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_cat_escaped(sb, buf); 407 sbuf_cat(sb, "</label>\n"); 408 } 409 } 410 411 static int 412 g_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 425 static int 426 g_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 440 static int 441 g_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 = 451 rounddown2(pp->mediasize - table->d_bbase * pp->sectorsize, 452 table->d_align) / 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 460 static const char * 461 g_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 469 static int 470 g_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 = rounddown2(pp->sectorsize + offsetof(struct disklabel64, d_magic), 481 pp->sectorsize); 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 490 static int 491 g_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 = roundup2(sizeof(struct disklabel64), pp->sectorsize); 506 buf = g_read_data(cp, 0, v32, &error); 507 if (buf == NULL) 508 return (error); 509 510 dlp = (struct disklabel64 *)buf; 511 basetable->gpt_entries = le32toh(dlp->d_npartitions); 512 if (basetable->gpt_entries > MAXPARTITIONS64 || 513 basetable->gpt_entries < 1) 514 goto invalid_label; 515 v32 = le32toh(dlp->d_crc); 516 dlp->d_crc = 0; 517 if (crc32(&dlp->d_magic, offsetof(struct disklabel64, 518 d_partitions[basetable->gpt_entries]) - 519 offsetof(struct disklabel64, d_magic)) != v32) 520 goto invalid_label; 521 table->d_align = le32toh(dlp->d_align); 522 if (table->d_align == 0 || (table->d_align & (pp->sectorsize - 1))) 523 goto invalid_label; 524 if (le64toh(dlp->d_total_size) > pp->mediasize) 525 goto invalid_label; 526 v64 = le64toh(dlp->d_pbase); 527 if (v64 % pp->sectorsize) 528 goto invalid_label; 529 basetable->gpt_first = v64 / pp->sectorsize; 530 v64 = le64toh(dlp->d_pstop); 531 if (v64 % pp->sectorsize) 532 goto invalid_label; 533 basetable->gpt_last = v64 / pp->sectorsize; 534 basetable->gpt_isleaf = 1; 535 v64 = le64toh(dlp->d_bbase); 536 if (v64 % pp->sectorsize) 537 goto invalid_label; 538 table->d_bbase = v64 / pp->sectorsize; 539 v64 = le64toh(dlp->d_abase); 540 if (v64 % pp->sectorsize) 541 goto invalid_label; 542 table->d_abase = v64 / pp->sectorsize; 543 le_uuid_dec(&dlp->d_stor_uuid, &table->d_stor_uuid); 544 for (index = basetable->gpt_entries - 1; index >= 0; index--) { 545 if (index == RAW_PART) { 546 /* Skip 'c' partition. */ 547 baseentry = g_part_new_entry(basetable, 548 index + 1, 0, 0); 549 baseentry->gpe_internal = 1; 550 continue; 551 } 552 v64 = le64toh(dlp->d_partitions[index].p_boffset); 553 sz = le64toh(dlp->d_partitions[index].p_bsize); 554 if (sz == 0 && v64 == 0) 555 continue; 556 if (sz == 0 || (v64 % pp->sectorsize) || (sz % pp->sectorsize)) 557 goto invalid_label; 558 baseentry = g_part_new_entry(basetable, index + 1, 559 v64 / pp->sectorsize, (v64 + sz) / pp->sectorsize - 1); 560 entry = (struct g_part_bsd64_entry *)baseentry; 561 le_uuid_dec(&dlp->d_partitions[index].p_type_uuid, 562 &entry->type_uuid); 563 le_uuid_dec(&dlp->d_partitions[index].p_stor_uuid, 564 &entry->stor_uuid); 565 entry->fstype = dlp->d_partitions[index].p_fstype; 566 } 567 bcopy(dlp->d_reserved0, table->d_reserved0, 568 sizeof(table->d_reserved0)); 569 bcopy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 570 bcopy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 571 g_free(buf); 572 return (0); 573 574 invalid_label: 575 g_free(buf); 576 return (EINVAL); 577 } 578 579 static const char * 580 g_part_bsd64_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 581 char *buf, size_t bufsz) 582 { 583 struct g_part_bsd64_entry *entry; 584 struct bsd64_uuid_alias *uap; 585 586 entry = (struct g_part_bsd64_entry *)baseentry; 587 if (entry->fstype != FS_OTHER) { 588 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) 589 if (uap->fstype == entry->fstype) 590 return (g_part_alias_name(uap->alias)); 591 } else { 592 for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) 593 if (EQUUID(uap->uuid, &entry->type_uuid)) 594 return (g_part_alias_name(uap->alias)); 595 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) 596 if (EQUUID(uap->uuid, &entry->type_uuid)) 597 return (g_part_alias_name(uap->alias)); 598 } 599 if (EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) 600 snprintf(buf, bufsz, "!%d", entry->fstype); 601 else { 602 buf[0] = '!'; 603 snprintf_uuid(buf + 1, bufsz - 1, &entry->type_uuid); 604 } 605 return (buf); 606 } 607 608 static int 609 g_part_bsd64_write(struct g_part_table *basetable, struct g_consumer *cp) 610 { 611 struct g_provider *pp; 612 struct g_part_entry *baseentry; 613 struct g_part_bsd64_entry *entry; 614 struct g_part_bsd64_table *table; 615 struct disklabel64 *dlp; 616 uint32_t v, sz; 617 int error, index; 618 619 pp = cp->provider; 620 table = (struct g_part_bsd64_table *)basetable; 621 sz = roundup2(sizeof(struct disklabel64), pp->sectorsize); 622 dlp = g_malloc(sz, M_WAITOK | M_ZERO); 623 624 memcpy(dlp->d_reserved0, table->d_reserved0, 625 sizeof(table->d_reserved0)); 626 memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 627 memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 628 le32enc(&dlp->d_magic, DISKMAGIC64); 629 le32enc(&dlp->d_align, table->d_align); 630 le32enc(&dlp->d_npartitions, basetable->gpt_entries); 631 le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid); 632 le64enc(&dlp->d_total_size, pp->mediasize); 633 le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize); 634 le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize); 635 le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize); 636 le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize); 637 638 LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 639 if (baseentry->gpe_deleted) 640 continue; 641 index = baseentry->gpe_index - 1; 642 entry = (struct g_part_bsd64_entry *)baseentry; 643 if (index == RAW_PART) 644 continue; 645 le64enc(&dlp->d_partitions[index].p_boffset, 646 baseentry->gpe_start * pp->sectorsize); 647 le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize * 648 (baseentry->gpe_end - baseentry->gpe_start + 1)); 649 dlp->d_partitions[index].p_fstype = entry->fstype; 650 le_uuid_enc(&dlp->d_partitions[index].p_type_uuid, 651 &entry->type_uuid); 652 le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid, 653 &entry->stor_uuid); 654 } 655 /* Calculate checksum. */ 656 v = offsetof(struct disklabel64, 657 d_partitions[basetable->gpt_entries]) - 658 offsetof(struct disklabel64, d_magic); 659 le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v)); 660 error = g_write_data(cp, 0, dlp, sz); 661 g_free(dlp); 662 return (error); 663 } 664