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/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 51 FEATURE(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 58 struct 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 through 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 102 struct 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 114 struct 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 122 static int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *, 123 struct g_part_parms *); 124 static int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *); 125 static int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *); 126 static int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *); 127 static void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *, 128 struct sbuf *, const char *); 129 static int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *); 130 static int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *, 131 struct g_part_parms *); 132 static const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *, 133 char *, size_t); 134 static int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *); 135 static int g_part_bsd64_read(struct g_part_table *, struct g_consumer *); 136 static const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *, 137 char *, size_t); 138 static int g_part_bsd64_write(struct g_part_table *, struct g_consumer *); 139 static int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *, 140 struct g_part_parms *); 141 142 static 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 159 static 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 }; 167 G_PART_SCHEME_DECLARE(g_part_bsd64); 168 MODULE_VERSION(geom_part_bsd64, 0); 169 170 #define EQUUID(a, b) (memcmp(a, b, sizeof(struct uuid)) == 0) 171 static struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED; 172 static struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP; 173 static struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1; 174 static struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM; 175 static struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD; 176 static struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY; 177 static struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER; 178 static struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2; 179 static struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 180 static struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; 181 static struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 182 static struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 183 static struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 184 static struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 185 186 struct bsd64_uuid_alias { 187 struct uuid *uuid; 188 uint8_t fstype; 189 int alias; 190 }; 191 static struct bsd64_uuid_alias dfbsd_alias_match[] = { 192 { &bsd64_uuid_dfbsd_swap, FS_SWAP, G_PART_ALIAS_DFBSD_SWAP }, 193 { &bsd64_uuid_dfbsd_ufs1, FS_BSDFFS, G_PART_ALIAS_DFBSD_UFS }, 194 { &bsd64_uuid_dfbsd_vinum, FS_VINUM, G_PART_ALIAS_DFBSD_VINUM }, 195 { &bsd64_uuid_dfbsd_ccd, FS_CCD, G_PART_ALIAS_DFBSD_CCD }, 196 { &bsd64_uuid_dfbsd_legacy, FS_OTHER, G_PART_ALIAS_DFBSD_LEGACY }, 197 { &bsd64_uuid_dfbsd_hammer, FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER }, 198 { &bsd64_uuid_dfbsd_hammer2, FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 }, 199 { NULL, 0, 0} 200 }; 201 static struct bsd64_uuid_alias fbsd_alias_match[] = { 202 { &bsd64_uuid_freebsd_boot, FS_OTHER, G_PART_ALIAS_FREEBSD_BOOT }, 203 { &bsd64_uuid_freebsd_swap, FS_OTHER, G_PART_ALIAS_FREEBSD_SWAP }, 204 { &bsd64_uuid_freebsd_ufs, FS_OTHER, G_PART_ALIAS_FREEBSD_UFS }, 205 { &bsd64_uuid_freebsd_zfs, FS_OTHER, G_PART_ALIAS_FREEBSD_ZFS }, 206 { &bsd64_uuid_freebsd_vinum, FS_OTHER, G_PART_ALIAS_FREEBSD_VINUM }, 207 { &bsd64_uuid_freebsd_nandfs, FS_OTHER, G_PART_ALIAS_FREEBSD_NANDFS }, 208 { NULL, 0, 0} 209 }; 210 211 static int 212 bsd64_parse_type(const char *type, struct g_part_bsd64_entry *entry) 213 { 214 struct uuid tmp; 215 const struct bsd64_uuid_alias *uap; 216 const char *alias; 217 char *p; 218 long lt; 219 int error; 220 221 if (type[0] == '!') { 222 if (type[1] == '\0') 223 return (EINVAL); 224 lt = strtol(type + 1, &p, 0); 225 /* The type specified as number */ 226 if (*p == '\0') { 227 if (lt <= 0 || lt > 255) 228 return (EINVAL); 229 entry->fstype = lt; 230 entry->type_uuid = bsd64_uuid_unused; 231 return (0); 232 } 233 /* The type specified as uuid */ 234 error = parse_uuid(type + 1, &tmp); 235 if (error != 0) 236 return (error); 237 if (EQUUID(&tmp, &bsd64_uuid_unused)) 238 return (EINVAL); 239 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) { 240 if (EQUUID(&tmp, uap->uuid)) { 241 /* Prefer fstype for known uuids */ 242 entry->type_uuid = bsd64_uuid_unused; 243 entry->fstype = uap->fstype; 244 return (0); 245 } 246 } 247 entry->type_uuid = tmp; 248 entry->fstype = FS_OTHER; 249 return (0); 250 } 251 /* The type specified as symbolic alias name */ 252 for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) { 253 alias = g_part_alias_name(uap->alias); 254 if (!strcasecmp(type, alias)) { 255 entry->type_uuid = *uap->uuid; 256 entry->fstype = uap->fstype; 257 return (0); 258 } 259 } 260 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) { 261 alias = g_part_alias_name(uap->alias); 262 if (!strcasecmp(type, alias)) { 263 entry->type_uuid = bsd64_uuid_unused; 264 entry->fstype = uap->fstype; 265 return (0); 266 } 267 } 268 return (EINVAL); 269 } 270 271 static int 272 g_part_bsd64_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 273 struct g_part_parms *gpp) 274 { 275 struct g_part_bsd64_entry *entry; 276 277 if (gpp->gpp_parms & G_PART_PARM_LABEL) 278 return (EINVAL); 279 280 entry = (struct g_part_bsd64_entry *)baseentry; 281 if (bsd64_parse_type(gpp->gpp_type, entry) != 0) 282 return (EINVAL); 283 kern_uuidgen(&entry->stor_uuid, 1); 284 return (0); 285 } 286 287 static int 288 g_part_bsd64_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 289 { 290 291 return (EOPNOTSUPP); 292 } 293 294 #define PALIGN_SIZE (1024 * 1024) 295 #define PALIGN_MASK (PALIGN_SIZE - 1) 296 #define BLKSIZE (4 * 1024) 297 #define BOOTSIZE (32 * 1024) 298 #define DALIGN_SIZE (32 * 1024) 299 static int 300 g_part_bsd64_create(struct g_part_table *basetable, struct g_part_parms *gpp) 301 { 302 struct g_part_bsd64_table *table; 303 struct g_part_entry *baseentry; 304 struct g_provider *pp; 305 uint64_t blkmask, pbase; 306 uint32_t blksize, ressize; 307 308 pp = gpp->gpp_provider; 309 if (pp->mediasize < 2* PALIGN_SIZE) 310 return (ENOSPC); 311 312 /* 313 * Use at least 4KB block size. Blksize is stored in the d_align. 314 * XXX: Actually it is used just for calculate d_bbase and used 315 * for better alignment in bsdlabel64(8). 316 */ 317 blksize = pp->sectorsize < BLKSIZE ? BLKSIZE: pp->sectorsize; 318 blkmask = blksize - 1; 319 /* Reserve enough space for RESPARTITIONS64 partitions. */ 320 ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]); 321 ressize = (ressize + blkmask) & ~blkmask; 322 /* 323 * Reserve enough space for bootcode and align first allocatable 324 * offset to PALIGN_SIZE. 325 * XXX: Currently DragonFlyBSD has 32KB bootcode, but the size could 326 * be bigger, because it is possible change it (it is equal pbase-bbase) 327 * in the bsdlabel64(8). 328 */ 329 pbase = ressize + ((BOOTSIZE + blkmask) & ~blkmask); 330 pbase = (pbase + PALIGN_MASK) & ~PALIGN_MASK; 331 /* 332 * Take physical offset into account and make first allocatable 333 * offset 32KB aligned to the start of the physical disk. 334 * XXX: Actually there are no such restrictions, this is how 335 * DragonFlyBSD behaves. 336 */ 337 pbase += DALIGN_SIZE - pp->stripeoffset % DALIGN_SIZE; 338 339 table = (struct g_part_bsd64_table *)basetable; 340 table->d_align = blksize; 341 table->d_bbase = ressize / pp->sectorsize; 342 table->d_abase = ((pp->mediasize - ressize) & 343 ~blkmask) / pp->sectorsize; 344 kern_uuidgen(&table->d_stor_uuid, 1); 345 basetable->gpt_first = pbase / pp->sectorsize; 346 basetable->gpt_last = table->d_abase - 1; /* XXX */ 347 /* 348 * Create 'c' partition and make it internal, so user will not be 349 * able use it. 350 */ 351 baseentry = g_part_new_entry(basetable, RAW_PART + 1, 0, 0); 352 baseentry->gpe_internal = 1; 353 return (0); 354 } 355 356 static int 357 g_part_bsd64_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 358 { 359 struct g_provider *pp; 360 361 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 362 if (pp->sectorsize > offsetof(struct disklabel64, d_magic)) 363 basetable->gpt_smhead |= 1; 364 else 365 basetable->gpt_smhead |= 3; 366 return (0); 367 } 368 369 static void 370 g_part_bsd64_dumpconf(struct g_part_table *basetable, 371 struct g_part_entry *baseentry, struct sbuf *sb, const char *indent) 372 { 373 struct g_part_bsd64_table *table; 374 struct g_part_bsd64_entry *entry; 375 char buf[sizeof(table->d_packname)]; 376 377 entry = (struct g_part_bsd64_entry *)baseentry; 378 if (indent == NULL) { 379 /* conftxt: libdisk compatibility */ 380 sbuf_printf(sb, " xs BSD64 xt %u", entry->fstype); 381 } else if (entry != NULL) { 382 /* confxml: partition entry information */ 383 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 384 entry->fstype); 385 if (!EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) { 386 sbuf_printf(sb, "%s<type_uuid>", indent); 387 sbuf_printf_uuid(sb, &entry->type_uuid); 388 sbuf_printf(sb, "</type_uuid>\n"); 389 } 390 sbuf_printf(sb, "%s<stor_uuid>", indent); 391 sbuf_printf_uuid(sb, &entry->stor_uuid); 392 sbuf_printf(sb, "</stor_uuid>\n"); 393 } else { 394 /* confxml: scheme information */ 395 table = (struct g_part_bsd64_table *)basetable; 396 sbuf_printf(sb, "%s<bootbase>%ju</bootbase>\n", indent, 397 (uintmax_t)table->d_bbase); 398 if (table->d_abase) 399 sbuf_printf(sb, "%s<backupbase>%ju</backupbase>\n", 400 indent, (uintmax_t)table->d_abase); 401 sbuf_printf(sb, "%s<stor_uuid>", indent); 402 sbuf_printf_uuid(sb, &table->d_stor_uuid); 403 sbuf_printf(sb, "</stor_uuid>\n"); 404 sbuf_printf(sb, "%s<label>", indent); 405 strncpy(buf, table->d_packname, sizeof(buf) - 1); 406 buf[sizeof(buf) - 1] = '\0'; 407 g_conf_printf_escaped(sb, "%s", buf); 408 sbuf_printf(sb, "</label>\n"); 409 } 410 } 411 412 static int 413 g_part_bsd64_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 414 { 415 struct g_part_bsd64_entry *entry; 416 417 /* Allow dumping to a swap partition. */ 418 entry = (struct g_part_bsd64_entry *)baseentry; 419 if (entry->fstype == FS_SWAP || 420 EQUUID(&entry->type_uuid, &bsd64_uuid_dfbsd_swap) || 421 EQUUID(&entry->type_uuid, &bsd64_uuid_freebsd_swap)) 422 return (1); 423 return (0); 424 } 425 426 static int 427 g_part_bsd64_modify(struct g_part_table *basetable, 428 struct g_part_entry *baseentry, struct g_part_parms *gpp) 429 { 430 struct g_part_bsd64_entry *entry; 431 432 if (gpp->gpp_parms & G_PART_PARM_LABEL) 433 return (EINVAL); 434 435 entry = (struct g_part_bsd64_entry *)baseentry; 436 if (gpp->gpp_parms & G_PART_PARM_TYPE) 437 return (bsd64_parse_type(gpp->gpp_type, entry)); 438 return (0); 439 } 440 441 static int 442 g_part_bsd64_resize(struct g_part_table *basetable, 443 struct g_part_entry *baseentry, struct g_part_parms *gpp) 444 { 445 struct g_part_bsd64_table *table; 446 struct g_provider *pp; 447 448 if (baseentry == NULL) { 449 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 450 table = (struct g_part_bsd64_table *)basetable; 451 table->d_abase = 452 rounddown2(pp->mediasize - table->d_bbase * pp->sectorsize, 453 table->d_align) / pp->sectorsize; 454 basetable->gpt_last = table->d_abase - 1; 455 return (0); 456 } 457 baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 458 return (0); 459 } 460 461 static const char * 462 g_part_bsd64_name(struct g_part_table *table, struct g_part_entry *baseentry, 463 char *buf, size_t bufsz) 464 { 465 466 snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); 467 return (buf); 468 } 469 470 static int 471 g_part_bsd64_probe(struct g_part_table *table, struct g_consumer *cp) 472 { 473 struct g_provider *pp; 474 uint32_t v; 475 int error; 476 u_char *buf; 477 478 pp = cp->provider; 479 if (pp->mediasize < 2 * PALIGN_SIZE) 480 return (ENOSPC); 481 v = rounddown2(pp->sectorsize + offsetof(struct disklabel64, d_magic), 482 pp->sectorsize); 483 buf = g_read_data(cp, 0, v, &error); 484 if (buf == NULL) 485 return (error); 486 v = le32dec(buf + offsetof(struct disklabel64, d_magic)); 487 g_free(buf); 488 return (v == DISKMAGIC64 ? G_PART_PROBE_PRI_HIGH: ENXIO); 489 } 490 491 static int 492 g_part_bsd64_read(struct g_part_table *basetable, struct g_consumer *cp) 493 { 494 struct g_part_bsd64_table *table; 495 struct g_part_bsd64_entry *entry; 496 struct g_part_entry *baseentry; 497 struct g_provider *pp; 498 struct disklabel64 *dlp; 499 uint64_t v64, sz; 500 uint32_t v32; 501 int error, index; 502 u_char *buf; 503 504 pp = cp->provider; 505 table = (struct g_part_bsd64_table *)basetable; 506 v32 = roundup2(sizeof(struct disklabel64), pp->sectorsize); 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 575 invalid_label: 576 g_free(buf); 577 return (EINVAL); 578 } 579 580 static const char * 581 g_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 609 static int 610 g_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 = roundup2(sizeof(struct disklabel64), pp->sectorsize); 623 dlp = g_malloc(sz, M_WAITOK | M_ZERO); 624 625 memcpy(dlp->d_reserved0, table->d_reserved0, 626 sizeof(table->d_reserved0)); 627 memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 628 memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 629 le32enc(&dlp->d_magic, DISKMAGIC64); 630 le32enc(&dlp->d_align, table->d_align); 631 le32enc(&dlp->d_npartitions, basetable->gpt_entries); 632 le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid); 633 le64enc(&dlp->d_total_size, pp->mediasize); 634 le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize); 635 le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize); 636 le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize); 637 le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize); 638 639 LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 640 if (baseentry->gpe_deleted) 641 continue; 642 index = baseentry->gpe_index - 1; 643 entry = (struct g_part_bsd64_entry *)baseentry; 644 if (index == RAW_PART) 645 continue; 646 le64enc(&dlp->d_partitions[index].p_boffset, 647 baseentry->gpe_start * pp->sectorsize); 648 le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize * 649 (baseentry->gpe_end - baseentry->gpe_start + 1)); 650 dlp->d_partitions[index].p_fstype = entry->fstype; 651 le_uuid_enc(&dlp->d_partitions[index].p_type_uuid, 652 &entry->type_uuid); 653 le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid, 654 &entry->stor_uuid); 655 } 656 /* Calculate checksum. */ 657 v = offsetof(struct disklabel64, 658 d_partitions[basetable->gpt_entries]) - 659 offsetof(struct disklabel64, d_magic); 660 le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v)); 661 error = g_write_data(cp, 0, dlp, sz); 662 g_free(dlp); 663 return (error); 664 } 665 666