1267359Sae/*- 2267359Sae * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org> 3267359Sae * All rights reserved. 4267359Sae * 5267359Sae * Redistribution and use in source and binary forms, with or without 6267359Sae * modification, are permitted provided that the following conditions 7267359Sae * are met: 8267359Sae * 9267359Sae * 1. Redistributions of source code must retain the above copyright 10267359Sae * notice, this list of conditions and the following disclaimer. 11267359Sae * 2. Redistributions in binary form must reproduce the above copyright 12267359Sae * notice, this list of conditions and the following disclaimer in the 13267359Sae * documentation and/or other materials provided with the distribution. 14267359Sae * 15267359Sae * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16267359Sae * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17267359Sae * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18267359Sae * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19267359Sae * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20267359Sae * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21267359Sae * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22267359Sae * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23267359Sae * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24267359Sae * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25267359Sae */ 26267359Sae 27267359Sae#include <sys/cdefs.h> 28267359Sae__FBSDID("$FreeBSD: stable/11/sys/geom/part/g_part_bsd64.c 332640 2018-04-17 02:18:04Z kevans $"); 29267359Sae 30267359Sae#include <sys/param.h> 31267359Sae#include <sys/bio.h> 32267359Sae#include <sys/disklabel.h> 33267359Sae#include <sys/endian.h> 34267359Sae#include <sys/gpt.h> 35267359Sae#include <sys/kernel.h> 36267359Sae#include <sys/kobj.h> 37267359Sae#include <sys/limits.h> 38267359Sae#include <sys/lock.h> 39267359Sae#include <sys/malloc.h> 40267359Sae#include <sys/mutex.h> 41267359Sae#include <sys/queue.h> 42267359Sae#include <sys/sbuf.h> 43267359Sae#include <sys/systm.h> 44267359Sae#include <sys/sysctl.h> 45267359Sae#include <geom/geom.h> 46267359Sae#include <geom/geom_int.h> 47267359Sae#include <geom/part/g_part.h> 48267359Sae 49267359Sae#include "g_part_if.h" 50267359Sae 51267359SaeFEATURE(geom_part_bsd64, "GEOM partitioning class for 64-bit BSD disklabels"); 52267359Sae 53267359Sae/* XXX: move this to sys/disklabel64.h */ 54267359Sae#define DISKMAGIC64 ((uint32_t)0xc4464c59) 55267359Sae#define MAXPARTITIONS64 16 56267359Sae#define RESPARTITIONS64 32 57267359Sae 58267359Saestruct disklabel64 { 59267359Sae char d_reserved0[512]; /* reserved or unused */ 60267359Sae u_int32_t d_magic; /* the magic number */ 61298808Spfg u_int32_t d_crc; /* crc32() d_magic through last part */ 62267359Sae u_int32_t d_align; /* partition alignment requirement */ 63267359Sae u_int32_t d_npartitions; /* number of partitions */ 64267359Sae struct uuid d_stor_uuid; /* unique uuid for label */ 65267359Sae 66267359Sae u_int64_t d_total_size; /* total size incl everything (bytes) */ 67267359Sae u_int64_t d_bbase; /* boot area base offset (bytes) */ 68267359Sae /* boot area is pbase - bbase */ 69267359Sae u_int64_t d_pbase; /* first allocatable offset (bytes) */ 70267359Sae u_int64_t d_pstop; /* last allocatable offset+1 (bytes) */ 71267359Sae u_int64_t d_abase; /* location of backup copy if not 0 */ 72267359Sae 73267359Sae u_char d_packname[64]; 74267359Sae u_char d_reserved[64]; 75267359Sae 76267359Sae /* 77267359Sae * Note: offsets are relative to the base of the slice, NOT to 78267359Sae * d_pbase. Unlike 32 bit disklabels the on-disk format for 79267359Sae * a 64 bit disklabel remains slice-relative. 80267359Sae * 81267359Sae * An uninitialized partition has a p_boffset and p_bsize of 0. 82267359Sae * 83267359Sae * If p_fstype is not supported for a live partition it is set 84267359Sae * to FS_OTHER. This is typically the case when the filesystem 85267359Sae * is identified by its uuid. 86267359Sae */ 87267359Sae struct partition64 { /* the partition table */ 88267359Sae u_int64_t p_boffset; /* slice relative offset, in bytes */ 89267359Sae u_int64_t p_bsize; /* size of partition, in bytes */ 90267359Sae u_int8_t p_fstype; 91267359Sae u_int8_t p_unused01; /* reserved, must be 0 */ 92267359Sae u_int8_t p_unused02; /* reserved, must be 0 */ 93267359Sae u_int8_t p_unused03; /* reserved, must be 0 */ 94267359Sae u_int32_t p_unused04; /* reserved, must be 0 */ 95267359Sae u_int32_t p_unused05; /* reserved, must be 0 */ 96267359Sae u_int32_t p_unused06; /* reserved, must be 0 */ 97267359Sae struct uuid p_type_uuid;/* mount type as UUID */ 98267359Sae struct uuid p_stor_uuid;/* unique uuid for storage */ 99267359Sae } d_partitions[MAXPARTITIONS64];/* actually may be more */ 100267359Sae}; 101267359Sae 102267359Saestruct g_part_bsd64_table { 103267359Sae struct g_part_table base; 104267359Sae 105267359Sae uint32_t d_align; 106267359Sae uint64_t d_bbase; 107267359Sae uint64_t d_abase; 108267359Sae struct uuid d_stor_uuid; 109267359Sae char d_reserved0[512]; 110267359Sae u_char d_packname[64]; 111267359Sae u_char d_reserved[64]; 112267359Sae}; 113267359Sae 114267359Saestruct g_part_bsd64_entry { 115267359Sae struct g_part_entry base; 116267359Sae 117267359Sae uint8_t fstype; 118267359Sae struct uuid type_uuid; 119267359Sae struct uuid stor_uuid; 120267359Sae}; 121267359Sae 122267359Saestatic int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *, 123267359Sae struct g_part_parms *); 124267359Saestatic int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *); 125267359Saestatic int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *); 126267359Saestatic int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *); 127267359Saestatic void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *, 128267359Sae struct sbuf *, const char *); 129267359Saestatic int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *); 130332521Skevansstatic int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *, 131267359Sae struct g_part_parms *); 132267359Saestatic const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *, 133267359Sae char *, size_t); 134267359Saestatic int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *); 135267359Saestatic int g_part_bsd64_read(struct g_part_table *, struct g_consumer *); 136267359Saestatic const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *, 137267359Sae char *, size_t); 138267359Saestatic int g_part_bsd64_write(struct g_part_table *, struct g_consumer *); 139267359Saestatic int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *, 140267359Sae struct g_part_parms *); 141267359Sae 142267359Saestatic kobj_method_t g_part_bsd64_methods[] = { 143267359Sae KOBJMETHOD(g_part_add, g_part_bsd64_add), 144267359Sae KOBJMETHOD(g_part_bootcode, g_part_bsd64_bootcode), 145267359Sae KOBJMETHOD(g_part_create, g_part_bsd64_create), 146267359Sae KOBJMETHOD(g_part_destroy, g_part_bsd64_destroy), 147267359Sae KOBJMETHOD(g_part_dumpconf, g_part_bsd64_dumpconf), 148267359Sae KOBJMETHOD(g_part_dumpto, g_part_bsd64_dumpto), 149267359Sae KOBJMETHOD(g_part_modify, g_part_bsd64_modify), 150267359Sae KOBJMETHOD(g_part_resize, g_part_bsd64_resize), 151267359Sae KOBJMETHOD(g_part_name, g_part_bsd64_name), 152267359Sae KOBJMETHOD(g_part_probe, g_part_bsd64_probe), 153267359Sae KOBJMETHOD(g_part_read, g_part_bsd64_read), 154267359Sae KOBJMETHOD(g_part_type, g_part_bsd64_type), 155267359Sae KOBJMETHOD(g_part_write, g_part_bsd64_write), 156267359Sae { 0, 0 } 157267359Sae}; 158267359Sae 159267359Saestatic struct g_part_scheme g_part_bsd64_scheme = { 160267359Sae "BSD64", 161267359Sae g_part_bsd64_methods, 162267359Sae sizeof(struct g_part_bsd64_table), 163267359Sae .gps_entrysz = sizeof(struct g_part_bsd64_entry), 164267359Sae .gps_minent = MAXPARTITIONS64, 165267359Sae .gps_maxent = MAXPARTITIONS64 166267359Sae}; 167267359SaeG_PART_SCHEME_DECLARE(g_part_bsd64); 168332640SkevansMODULE_VERSION(geom_part_bsd64, 0); 169267359Sae 170267359Sae#define EQUUID(a, b) (memcmp(a, b, sizeof(struct uuid)) == 0) 171267359Saestatic struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED; 172267359Saestatic struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP; 173267359Saestatic struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1; 174267359Saestatic struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM; 175267359Saestatic struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD; 176267359Saestatic struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY; 177267359Saestatic struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER; 178267359Saestatic struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2; 179267359Saestatic struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 180267359Saestatic struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; 181267359Saestatic struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 182267359Saestatic struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 183267359Saestatic struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 184267359Saestatic struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 185267359Sae 186267359Saestruct bsd64_uuid_alias { 187267359Sae struct uuid *uuid; 188267359Sae uint8_t fstype; 189267359Sae int alias; 190267359Sae}; 191267359Saestatic struct bsd64_uuid_alias dfbsd_alias_match[] = { 192267359Sae { &bsd64_uuid_dfbsd_swap, FS_SWAP, G_PART_ALIAS_DFBSD_SWAP }, 193267359Sae { &bsd64_uuid_dfbsd_ufs1, FS_BSDFFS, G_PART_ALIAS_DFBSD_UFS }, 194267359Sae { &bsd64_uuid_dfbsd_vinum, FS_VINUM, G_PART_ALIAS_DFBSD_VINUM }, 195267359Sae { &bsd64_uuid_dfbsd_ccd, FS_CCD, G_PART_ALIAS_DFBSD_CCD }, 196267359Sae { &bsd64_uuid_dfbsd_legacy, FS_OTHER, G_PART_ALIAS_DFBSD_LEGACY }, 197267359Sae { &bsd64_uuid_dfbsd_hammer, FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER }, 198267359Sae { &bsd64_uuid_dfbsd_hammer2, FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 }, 199267359Sae { NULL, 0, 0} 200267359Sae}; 201267359Saestatic struct bsd64_uuid_alias fbsd_alias_match[] = { 202267359Sae { &bsd64_uuid_freebsd_boot, FS_OTHER, G_PART_ALIAS_FREEBSD_BOOT }, 203267359Sae { &bsd64_uuid_freebsd_swap, FS_OTHER, G_PART_ALIAS_FREEBSD_SWAP }, 204267359Sae { &bsd64_uuid_freebsd_ufs, FS_OTHER, G_PART_ALIAS_FREEBSD_UFS }, 205267359Sae { &bsd64_uuid_freebsd_zfs, FS_OTHER, G_PART_ALIAS_FREEBSD_ZFS }, 206267359Sae { &bsd64_uuid_freebsd_vinum, FS_OTHER, G_PART_ALIAS_FREEBSD_VINUM }, 207267359Sae { &bsd64_uuid_freebsd_nandfs, FS_OTHER, G_PART_ALIAS_FREEBSD_NANDFS }, 208267359Sae { NULL, 0, 0} 209267359Sae}; 210267359Sae 211267359Saestatic int 212267359Saebsd64_parse_type(const char *type, struct g_part_bsd64_entry *entry) 213267359Sae{ 214267359Sae struct uuid tmp; 215267359Sae const struct bsd64_uuid_alias *uap; 216267359Sae const char *alias; 217267359Sae char *p; 218267359Sae long lt; 219267359Sae int error; 220267359Sae 221267359Sae if (type[0] == '!') { 222267359Sae if (type[1] == '\0') 223267359Sae return (EINVAL); 224267359Sae lt = strtol(type + 1, &p, 0); 225267359Sae /* The type specified as number */ 226267359Sae if (*p == '\0') { 227267359Sae if (lt <= 0 || lt > 255) 228267359Sae return (EINVAL); 229267359Sae entry->fstype = lt; 230267359Sae entry->type_uuid = bsd64_uuid_unused; 231267359Sae return (0); 232267359Sae } 233267359Sae /* The type specified as uuid */ 234267359Sae error = parse_uuid(type + 1, &tmp); 235267359Sae if (error != 0) 236267359Sae return (error); 237267359Sae if (EQUUID(&tmp, &bsd64_uuid_unused)) 238267359Sae return (EINVAL); 239267359Sae for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) { 240267359Sae if (EQUUID(&tmp, uap->uuid)) { 241267359Sae /* Prefer fstype for known uuids */ 242267359Sae entry->type_uuid = bsd64_uuid_unused; 243267359Sae entry->fstype = uap->fstype; 244267359Sae return (0); 245267359Sae } 246267359Sae } 247267359Sae entry->type_uuid = tmp; 248267359Sae entry->fstype = FS_OTHER; 249267359Sae return (0); 250267359Sae } 251267359Sae /* The type specified as symbolic alias name */ 252267359Sae for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) { 253267359Sae alias = g_part_alias_name(uap->alias); 254267359Sae if (!strcasecmp(type, alias)) { 255267359Sae entry->type_uuid = *uap->uuid; 256267359Sae entry->fstype = uap->fstype; 257267359Sae return (0); 258267359Sae } 259267359Sae } 260267359Sae for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) { 261267359Sae alias = g_part_alias_name(uap->alias); 262267359Sae if (!strcasecmp(type, alias)) { 263267359Sae entry->type_uuid = bsd64_uuid_unused; 264267359Sae entry->fstype = uap->fstype; 265267359Sae return (0); 266267359Sae } 267267359Sae } 268267359Sae return (EINVAL); 269267359Sae} 270267359Sae 271267359Saestatic int 272267359Saeg_part_bsd64_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 273267359Sae struct g_part_parms *gpp) 274267359Sae{ 275267359Sae struct g_part_bsd64_entry *entry; 276267359Sae 277267359Sae if (gpp->gpp_parms & G_PART_PARM_LABEL) 278267359Sae return (EINVAL); 279267359Sae 280267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 281267359Sae if (bsd64_parse_type(gpp->gpp_type, entry) != 0) 282267359Sae return (EINVAL); 283267359Sae kern_uuidgen(&entry->stor_uuid, 1); 284267359Sae return (0); 285267359Sae} 286267359Sae 287267359Saestatic int 288267359Saeg_part_bsd64_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 289267359Sae{ 290267359Sae 291267359Sae return (EOPNOTSUPP); 292267359Sae} 293267359Sae 294267359Sae#define PALIGN_SIZE (1024 * 1024) 295267359Sae#define PALIGN_MASK (PALIGN_SIZE - 1) 296267359Sae#define BLKSIZE (4 * 1024) 297267359Sae#define BOOTSIZE (32 * 1024) 298267359Sae#define DALIGN_SIZE (32 * 1024) 299267359Saestatic int 300267359Saeg_part_bsd64_create(struct g_part_table *basetable, struct g_part_parms *gpp) 301267359Sae{ 302267359Sae struct g_part_bsd64_table *table; 303267359Sae struct g_part_entry *baseentry; 304267359Sae struct g_provider *pp; 305267359Sae uint64_t blkmask, pbase; 306267359Sae uint32_t blksize, ressize; 307267359Sae 308267359Sae pp = gpp->gpp_provider; 309267359Sae if (pp->mediasize < 2* PALIGN_SIZE) 310267359Sae return (ENOSPC); 311267359Sae 312267359Sae /* 313267359Sae * Use at least 4KB block size. Blksize is stored in the d_align. 314267359Sae * XXX: Actually it is used just for calculate d_bbase and used 315267359Sae * for better alignment in bsdlabel64(8). 316267359Sae */ 317267359Sae blksize = pp->sectorsize < BLKSIZE ? BLKSIZE: pp->sectorsize; 318267359Sae blkmask = blksize - 1; 319267359Sae /* Reserve enough space for RESPARTITIONS64 partitions. */ 320267359Sae ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]); 321267359Sae ressize = (ressize + blkmask) & ~blkmask; 322267359Sae /* 323267359Sae * Reserve enough space for bootcode and align first allocatable 324267359Sae * offset to PALIGN_SIZE. 325267359Sae * XXX: Currently DragonFlyBSD has 32KB bootcode, but the size could 326267359Sae * be bigger, because it is possible change it (it is equal pbase-bbase) 327267359Sae * in the bsdlabel64(8). 328267359Sae */ 329267359Sae pbase = ressize + ((BOOTSIZE + blkmask) & ~blkmask); 330267359Sae pbase = (pbase + PALIGN_MASK) & ~PALIGN_MASK; 331267359Sae /* 332267359Sae * Take physical offset into account and make first allocatable 333267359Sae * offset 32KB aligned to the start of the physical disk. 334267359Sae * XXX: Actually there are no such restrictions, this is how 335267359Sae * DragonFlyBSD behaves. 336267359Sae */ 337267359Sae pbase += DALIGN_SIZE - pp->stripeoffset % DALIGN_SIZE; 338267359Sae 339267359Sae table = (struct g_part_bsd64_table *)basetable; 340267359Sae table->d_align = blksize; 341267359Sae table->d_bbase = ressize / pp->sectorsize; 342267359Sae table->d_abase = ((pp->mediasize - ressize) & 343267359Sae ~blkmask) / pp->sectorsize; 344267359Sae kern_uuidgen(&table->d_stor_uuid, 1); 345267359Sae basetable->gpt_first = pbase / pp->sectorsize; 346267359Sae basetable->gpt_last = table->d_abase - 1; /* XXX */ 347267359Sae /* 348267359Sae * Create 'c' partition and make it internal, so user will not be 349267359Sae * able use it. 350267359Sae */ 351267359Sae baseentry = g_part_new_entry(basetable, RAW_PART + 1, 0, 0); 352267359Sae baseentry->gpe_internal = 1; 353267359Sae return (0); 354267359Sae} 355267359Sae 356267359Saestatic int 357267359Saeg_part_bsd64_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 358267359Sae{ 359267359Sae struct g_provider *pp; 360267359Sae 361267359Sae pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 362267359Sae if (pp->sectorsize > offsetof(struct disklabel64, d_magic)) 363267359Sae basetable->gpt_smhead |= 1; 364267359Sae else 365267359Sae basetable->gpt_smhead |= 3; 366267359Sae return (0); 367267359Sae} 368267359Sae 369267359Saestatic void 370267359Saeg_part_bsd64_dumpconf(struct g_part_table *basetable, 371267359Sae struct g_part_entry *baseentry, struct sbuf *sb, const char *indent) 372267359Sae{ 373267359Sae struct g_part_bsd64_table *table; 374267359Sae struct g_part_bsd64_entry *entry; 375267359Sae char buf[sizeof(table->d_packname)]; 376267359Sae 377267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 378267359Sae if (indent == NULL) { 379267359Sae /* conftxt: libdisk compatibility */ 380267359Sae sbuf_printf(sb, " xs BSD64 xt %u", entry->fstype); 381267359Sae } else if (entry != NULL) { 382267359Sae /* confxml: partition entry information */ 383267359Sae sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 384267359Sae entry->fstype); 385267359Sae if (!EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) { 386267359Sae sbuf_printf(sb, "%s<type_uuid>", indent); 387267359Sae sbuf_printf_uuid(sb, &entry->type_uuid); 388267359Sae sbuf_printf(sb, "</type_uuid>\n"); 389267359Sae } 390267359Sae sbuf_printf(sb, "%s<stor_uuid>", indent); 391267359Sae sbuf_printf_uuid(sb, &entry->stor_uuid); 392267359Sae sbuf_printf(sb, "</stor_uuid>\n"); 393267359Sae } else { 394267359Sae /* confxml: scheme information */ 395267359Sae table = (struct g_part_bsd64_table *)basetable; 396267359Sae sbuf_printf(sb, "%s<bootbase>%ju</bootbase>\n", indent, 397267359Sae (uintmax_t)table->d_bbase); 398267359Sae if (table->d_abase) 399267359Sae sbuf_printf(sb, "%s<backupbase>%ju</backupbase>\n", 400267359Sae indent, (uintmax_t)table->d_abase); 401267359Sae sbuf_printf(sb, "%s<stor_uuid>", indent); 402267359Sae sbuf_printf_uuid(sb, &table->d_stor_uuid); 403267359Sae sbuf_printf(sb, "</stor_uuid>\n"); 404267359Sae sbuf_printf(sb, "%s<label>", indent); 405267359Sae strncpy(buf, table->d_packname, sizeof(buf) - 1); 406267359Sae buf[sizeof(buf) - 1] = '\0'; 407267359Sae g_conf_printf_escaped(sb, "%s", buf); 408267359Sae sbuf_printf(sb, "</label>\n"); 409267359Sae } 410267359Sae} 411267359Sae 412267359Saestatic int 413332521Skevansg_part_bsd64_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 414267359Sae{ 415267359Sae struct g_part_bsd64_entry *entry; 416267359Sae 417267359Sae /* Allow dumping to a swap partition. */ 418267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 419267359Sae if (entry->fstype == FS_SWAP || 420267359Sae EQUUID(&entry->type_uuid, &bsd64_uuid_dfbsd_swap) || 421267359Sae EQUUID(&entry->type_uuid, &bsd64_uuid_freebsd_swap)) 422267359Sae return (1); 423267359Sae return (0); 424267359Sae} 425267359Sae 426267359Saestatic int 427267359Saeg_part_bsd64_modify(struct g_part_table *basetable, 428267359Sae struct g_part_entry *baseentry, struct g_part_parms *gpp) 429267359Sae{ 430267359Sae struct g_part_bsd64_entry *entry; 431267359Sae 432267359Sae if (gpp->gpp_parms & G_PART_PARM_LABEL) 433267359Sae return (EINVAL); 434267359Sae 435267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 436267359Sae if (gpp->gpp_parms & G_PART_PARM_TYPE) 437267359Sae return (bsd64_parse_type(gpp->gpp_type, entry)); 438267359Sae return (0); 439267359Sae} 440267359Sae 441267359Saestatic int 442267359Saeg_part_bsd64_resize(struct g_part_table *basetable, 443267359Sae struct g_part_entry *baseentry, struct g_part_parms *gpp) 444267359Sae{ 445267359Sae struct g_part_bsd64_table *table; 446267359Sae struct g_provider *pp; 447267359Sae 448267359Sae if (baseentry == NULL) { 449267359Sae pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 450267359Sae table = (struct g_part_bsd64_table *)basetable; 451298433Spfg table->d_abase = 452298433Spfg rounddown2(pp->mediasize - table->d_bbase * pp->sectorsize, 453298433Spfg table->d_align) / pp->sectorsize; 454267359Sae basetable->gpt_last = table->d_abase - 1; 455267359Sae return (0); 456267359Sae } 457267359Sae baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 458267359Sae return (0); 459267359Sae} 460267359Sae 461267359Saestatic const char * 462267359Saeg_part_bsd64_name(struct g_part_table *table, struct g_part_entry *baseentry, 463267359Sae char *buf, size_t bufsz) 464267359Sae{ 465267359Sae 466267359Sae snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); 467267359Sae return (buf); 468267359Sae} 469267359Sae 470267359Saestatic int 471267359Saeg_part_bsd64_probe(struct g_part_table *table, struct g_consumer *cp) 472267359Sae{ 473267359Sae struct g_provider *pp; 474267359Sae uint32_t v; 475267359Sae int error; 476267359Sae u_char *buf; 477267359Sae 478267359Sae pp = cp->provider; 479267359Sae if (pp->mediasize < 2 * PALIGN_SIZE) 480267359Sae return (ENOSPC); 481298433Spfg v = rounddown2(pp->sectorsize + offsetof(struct disklabel64, d_magic), 482298433Spfg pp->sectorsize); 483267359Sae buf = g_read_data(cp, 0, v, &error); 484267359Sae if (buf == NULL) 485267359Sae return (error); 486267359Sae v = le32dec(buf + offsetof(struct disklabel64, d_magic)); 487267359Sae g_free(buf); 488267359Sae return (v == DISKMAGIC64 ? G_PART_PROBE_PRI_HIGH: ENXIO); 489267359Sae} 490267359Sae 491267359Saestatic int 492267359Saeg_part_bsd64_read(struct g_part_table *basetable, struct g_consumer *cp) 493267359Sae{ 494267359Sae struct g_part_bsd64_table *table; 495267359Sae struct g_part_bsd64_entry *entry; 496267359Sae struct g_part_entry *baseentry; 497267359Sae struct g_provider *pp; 498267359Sae struct disklabel64 *dlp; 499267359Sae uint64_t v64, sz; 500267359Sae uint32_t v32; 501267359Sae int error, index; 502267359Sae u_char *buf; 503267359Sae 504267359Sae pp = cp->provider; 505267359Sae table = (struct g_part_bsd64_table *)basetable; 506298433Spfg v32 = roundup2(sizeof(struct disklabel64), pp->sectorsize); 507267359Sae buf = g_read_data(cp, 0, v32, &error); 508267359Sae if (buf == NULL) 509267359Sae return (error); 510267359Sae 511267359Sae dlp = (struct disklabel64 *)buf; 512267359Sae basetable->gpt_entries = le32toh(dlp->d_npartitions); 513298671Scem if (basetable->gpt_entries > MAXPARTITIONS64 || 514298671Scem basetable->gpt_entries < 1) 515267359Sae goto invalid_label; 516267359Sae v32 = le32toh(dlp->d_crc); 517267359Sae dlp->d_crc = 0; 518267359Sae if (crc32(&dlp->d_magic, offsetof(struct disklabel64, 519267359Sae d_partitions[basetable->gpt_entries]) - 520267359Sae offsetof(struct disklabel64, d_magic)) != v32) 521267359Sae goto invalid_label; 522267359Sae table->d_align = le32toh(dlp->d_align); 523267359Sae if (table->d_align == 0 || (table->d_align & (pp->sectorsize - 1))) 524267359Sae goto invalid_label; 525267359Sae if (le64toh(dlp->d_total_size) > pp->mediasize) 526267359Sae goto invalid_label; 527267359Sae v64 = le64toh(dlp->d_pbase); 528267359Sae if (v64 % pp->sectorsize) 529267359Sae goto invalid_label; 530267359Sae basetable->gpt_first = v64 / pp->sectorsize; 531267359Sae v64 = le64toh(dlp->d_pstop); 532267359Sae if (v64 % pp->sectorsize) 533267359Sae goto invalid_label; 534267359Sae basetable->gpt_last = v64 / pp->sectorsize; 535267359Sae basetable->gpt_isleaf = 1; 536267359Sae v64 = le64toh(dlp->d_bbase); 537267359Sae if (v64 % pp->sectorsize) 538267359Sae goto invalid_label; 539267359Sae table->d_bbase = v64 / pp->sectorsize; 540267359Sae v64 = le64toh(dlp->d_abase); 541267359Sae if (v64 % pp->sectorsize) 542267359Sae goto invalid_label; 543267359Sae table->d_abase = v64 / pp->sectorsize; 544267359Sae le_uuid_dec(&dlp->d_stor_uuid, &table->d_stor_uuid); 545267359Sae for (index = basetable->gpt_entries - 1; index >= 0; index--) { 546267359Sae if (index == RAW_PART) { 547267359Sae /* Skip 'c' partition. */ 548267359Sae baseentry = g_part_new_entry(basetable, 549267359Sae index + 1, 0, 0); 550267359Sae baseentry->gpe_internal = 1; 551267359Sae continue; 552267359Sae } 553267359Sae v64 = le64toh(dlp->d_partitions[index].p_boffset); 554267359Sae sz = le64toh(dlp->d_partitions[index].p_bsize); 555267359Sae if (sz == 0 && v64 == 0) 556267359Sae continue; 557267359Sae if (sz == 0 || (v64 % pp->sectorsize) || (sz % pp->sectorsize)) 558267359Sae goto invalid_label; 559267359Sae baseentry = g_part_new_entry(basetable, index + 1, 560267359Sae v64 / pp->sectorsize, (v64 + sz) / pp->sectorsize - 1); 561267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 562267359Sae le_uuid_dec(&dlp->d_partitions[index].p_type_uuid, 563267359Sae &entry->type_uuid); 564267359Sae le_uuid_dec(&dlp->d_partitions[index].p_stor_uuid, 565267359Sae &entry->stor_uuid); 566267359Sae entry->fstype = dlp->d_partitions[index].p_fstype; 567267359Sae } 568267359Sae bcopy(dlp->d_reserved0, table->d_reserved0, 569267359Sae sizeof(table->d_reserved0)); 570267359Sae bcopy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 571267359Sae bcopy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 572267359Sae g_free(buf); 573267359Sae return (0); 574267359Sae 575267359Saeinvalid_label: 576267359Sae g_free(buf); 577267359Sae return (EINVAL); 578267359Sae} 579267359Sae 580267359Saestatic const char * 581332521Skevansg_part_bsd64_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 582267359Sae char *buf, size_t bufsz) 583267359Sae{ 584267359Sae struct g_part_bsd64_entry *entry; 585267359Sae struct bsd64_uuid_alias *uap; 586267359Sae 587267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 588267359Sae if (entry->fstype != FS_OTHER) { 589267359Sae for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) 590267359Sae if (uap->fstype == entry->fstype) 591267359Sae return (g_part_alias_name(uap->alias)); 592267359Sae } else { 593267359Sae for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) 594267359Sae if (EQUUID(uap->uuid, &entry->type_uuid)) 595267359Sae return (g_part_alias_name(uap->alias)); 596267359Sae for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) 597267359Sae if (EQUUID(uap->uuid, &entry->type_uuid)) 598267359Sae return (g_part_alias_name(uap->alias)); 599267359Sae } 600267359Sae if (EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) 601267359Sae snprintf(buf, bufsz, "!%d", entry->fstype); 602267359Sae else { 603267359Sae buf[0] = '!'; 604267359Sae snprintf_uuid(buf + 1, bufsz - 1, &entry->type_uuid); 605267359Sae } 606267359Sae return (buf); 607267359Sae} 608267359Sae 609267359Saestatic int 610267359Saeg_part_bsd64_write(struct g_part_table *basetable, struct g_consumer *cp) 611267359Sae{ 612267359Sae struct g_provider *pp; 613267359Sae struct g_part_entry *baseentry; 614267359Sae struct g_part_bsd64_entry *entry; 615267359Sae struct g_part_bsd64_table *table; 616267359Sae struct disklabel64 *dlp; 617267359Sae uint32_t v, sz; 618267359Sae int error, index; 619267359Sae 620267359Sae pp = cp->provider; 621267359Sae table = (struct g_part_bsd64_table *)basetable; 622298433Spfg sz = roundup2(sizeof(struct disklabel64), pp->sectorsize); 623267359Sae dlp = g_malloc(sz, M_WAITOK | M_ZERO); 624267359Sae 625267359Sae memcpy(dlp->d_reserved0, table->d_reserved0, 626267359Sae sizeof(table->d_reserved0)); 627267359Sae memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname)); 628267359Sae memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved)); 629267359Sae le32enc(&dlp->d_magic, DISKMAGIC64); 630267359Sae le32enc(&dlp->d_align, table->d_align); 631267359Sae le32enc(&dlp->d_npartitions, basetable->gpt_entries); 632267359Sae le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid); 633267359Sae le64enc(&dlp->d_total_size, pp->mediasize); 634267359Sae le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize); 635267359Sae le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize); 636267359Sae le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize); 637267359Sae le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize); 638267359Sae 639267359Sae LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 640267359Sae if (baseentry->gpe_deleted) 641267359Sae continue; 642267359Sae index = baseentry->gpe_index - 1; 643267359Sae entry = (struct g_part_bsd64_entry *)baseentry; 644267359Sae if (index == RAW_PART) 645267359Sae continue; 646267359Sae le64enc(&dlp->d_partitions[index].p_boffset, 647267359Sae baseentry->gpe_start * pp->sectorsize); 648267359Sae le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize * 649267359Sae (baseentry->gpe_end - baseentry->gpe_start + 1)); 650267359Sae dlp->d_partitions[index].p_fstype = entry->fstype; 651267359Sae le_uuid_enc(&dlp->d_partitions[index].p_type_uuid, 652267359Sae &entry->type_uuid); 653267359Sae le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid, 654267359Sae &entry->stor_uuid); 655267359Sae } 656267359Sae /* Calculate checksum. */ 657267359Sae v = offsetof(struct disklabel64, 658267359Sae d_partitions[basetable->gpt_entries]) - 659267359Sae offsetof(struct disklabel64, d_magic); 660267359Sae le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v)); 661267359Sae error = g_write_data(cp, 0, dlp, sz); 662267359Sae g_free(dlp); 663267359Sae return (error); 664267359Sae} 665267359Sae 666