xref: /freebsd/sys/geom/part/g_part_bsd64.c (revision 09c999b1557a8031d2b60435d71a0a5ed4f0f016)
191ca76a5SAndrey V. Elsukov /*-
291ca76a5SAndrey V. Elsukov  * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org>
391ca76a5SAndrey V. Elsukov  * All rights reserved.
491ca76a5SAndrey V. Elsukov  *
591ca76a5SAndrey V. Elsukov  * Redistribution and use in source and binary forms, with or without
691ca76a5SAndrey V. Elsukov  * modification, are permitted provided that the following conditions
791ca76a5SAndrey V. Elsukov  * are met:
891ca76a5SAndrey V. Elsukov  *
991ca76a5SAndrey V. Elsukov  * 1. Redistributions of source code must retain the above copyright
1091ca76a5SAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer.
1191ca76a5SAndrey V. Elsukov  * 2. Redistributions in binary form must reproduce the above copyright
1291ca76a5SAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer in the
1391ca76a5SAndrey V. Elsukov  *    documentation and/or other materials provided with the distribution.
1491ca76a5SAndrey V. Elsukov  *
1591ca76a5SAndrey V. Elsukov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1691ca76a5SAndrey V. Elsukov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1791ca76a5SAndrey V. Elsukov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1891ca76a5SAndrey V. Elsukov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1991ca76a5SAndrey V. Elsukov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2091ca76a5SAndrey V. Elsukov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2191ca76a5SAndrey V. Elsukov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2291ca76a5SAndrey V. Elsukov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2391ca76a5SAndrey V. Elsukov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2491ca76a5SAndrey V. Elsukov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2591ca76a5SAndrey V. Elsukov  */
2691ca76a5SAndrey V. Elsukov 
2791ca76a5SAndrey V. Elsukov #include <sys/param.h>
2891ca76a5SAndrey V. Elsukov #include <sys/bio.h>
29f89d2072SXin LI #include <sys/gsb_crc32.h>
3091ca76a5SAndrey V. Elsukov #include <sys/disklabel.h>
3191ca76a5SAndrey V. Elsukov #include <sys/endian.h>
3291ca76a5SAndrey V. Elsukov #include <sys/gpt.h>
3391ca76a5SAndrey V. Elsukov #include <sys/kernel.h>
3491ca76a5SAndrey V. Elsukov #include <sys/kobj.h>
3591ca76a5SAndrey V. Elsukov #include <sys/limits.h>
3691ca76a5SAndrey V. Elsukov #include <sys/lock.h>
3791ca76a5SAndrey V. Elsukov #include <sys/malloc.h>
3891ca76a5SAndrey V. Elsukov #include <sys/mutex.h>
3991ca76a5SAndrey V. Elsukov #include <sys/queue.h>
4091ca76a5SAndrey V. Elsukov #include <sys/sbuf.h>
4191ca76a5SAndrey V. Elsukov #include <sys/systm.h>
4291ca76a5SAndrey V. Elsukov #include <sys/sysctl.h>
4391ca76a5SAndrey V. Elsukov #include <geom/geom.h>
4491ca76a5SAndrey V. Elsukov #include <geom/geom_int.h>
4591ca76a5SAndrey V. Elsukov #include <geom/part/g_part.h>
4691ca76a5SAndrey V. Elsukov 
4791ca76a5SAndrey V. Elsukov #include "g_part_if.h"
4891ca76a5SAndrey V. Elsukov 
4991ca76a5SAndrey V. Elsukov FEATURE(geom_part_bsd64, "GEOM partitioning class for 64-bit BSD disklabels");
5091ca76a5SAndrey V. Elsukov 
5191ca76a5SAndrey V. Elsukov /* XXX: move this to sys/disklabel64.h */
5291ca76a5SAndrey V. Elsukov #define	DISKMAGIC64     ((uint32_t)0xc4464c59)
5391ca76a5SAndrey V. Elsukov #define	MAXPARTITIONS64	16
5491ca76a5SAndrey V. Elsukov #define	RESPARTITIONS64	32
5591ca76a5SAndrey V. Elsukov 
5691ca76a5SAndrey V. Elsukov struct disklabel64 {
5791ca76a5SAndrey V. Elsukov 	char	  d_reserved0[512];	/* reserved or unused */
580ff783dcSJohn Baldwin 	uint32_t d_magic;		/* the magic number */
590ff783dcSJohn Baldwin 	uint32_t d_crc;		/* crc32() d_magic through last part */
600ff783dcSJohn Baldwin 	uint32_t d_align;		/* partition alignment requirement */
610ff783dcSJohn Baldwin 	uint32_t d_npartitions;	/* number of partitions */
6291ca76a5SAndrey V. Elsukov 	struct uuid d_stor_uuid;	/* unique uuid for label */
6391ca76a5SAndrey V. Elsukov 
640ff783dcSJohn Baldwin 	uint64_t d_total_size;		/* total size incl everything (bytes) */
650ff783dcSJohn Baldwin 	uint64_t d_bbase;		/* boot area base offset (bytes) */
6691ca76a5SAndrey V. Elsukov 					/* boot area is pbase - bbase */
670ff783dcSJohn Baldwin 	uint64_t d_pbase;		/* first allocatable offset (bytes) */
680ff783dcSJohn Baldwin 	uint64_t d_pstop;		/* last allocatable offset+1 (bytes) */
690ff783dcSJohn Baldwin 	uint64_t d_abase;		/* location of backup copy if not 0 */
7091ca76a5SAndrey V. Elsukov 
7191ca76a5SAndrey V. Elsukov 	u_char	  d_packname[64];
7291ca76a5SAndrey V. Elsukov 	u_char    d_reserved[64];
7391ca76a5SAndrey V. Elsukov 
7491ca76a5SAndrey V. Elsukov 	/*
7591ca76a5SAndrey V. Elsukov 	 * Note: offsets are relative to the base of the slice, NOT to
7691ca76a5SAndrey V. Elsukov 	 * d_pbase.  Unlike 32 bit disklabels the on-disk format for
7791ca76a5SAndrey V. Elsukov 	 * a 64 bit disklabel remains slice-relative.
7891ca76a5SAndrey V. Elsukov 	 *
7991ca76a5SAndrey V. Elsukov 	 * An uninitialized partition has a p_boffset and p_bsize of 0.
8091ca76a5SAndrey V. Elsukov 	 *
8191ca76a5SAndrey V. Elsukov 	 * If p_fstype is not supported for a live partition it is set
8291ca76a5SAndrey V. Elsukov 	 * to FS_OTHER.  This is typically the case when the filesystem
8391ca76a5SAndrey V. Elsukov 	 * is identified by its uuid.
8491ca76a5SAndrey V. Elsukov 	 */
8591ca76a5SAndrey V. Elsukov 	struct partition64 {		/* the partition table */
860ff783dcSJohn Baldwin 		uint64_t p_boffset;	/* slice relative offset, in bytes */
870ff783dcSJohn Baldwin 		uint64_t p_bsize;	/* size of partition, in bytes */
880ff783dcSJohn Baldwin 		uint8_t  p_fstype;
890ff783dcSJohn Baldwin 		uint8_t  p_unused01;	/* reserved, must be 0 */
900ff783dcSJohn Baldwin 		uint8_t  p_unused02;	/* reserved, must be 0 */
910ff783dcSJohn Baldwin 		uint8_t  p_unused03;	/* reserved, must be 0 */
920ff783dcSJohn Baldwin 		uint32_t p_unused04;	/* reserved, must be 0 */
930ff783dcSJohn Baldwin 		uint32_t p_unused05;	/* reserved, must be 0 */
940ff783dcSJohn Baldwin 		uint32_t p_unused06;	/* reserved, must be 0 */
9591ca76a5SAndrey V. Elsukov 		struct uuid p_type_uuid;/* mount type as UUID */
9691ca76a5SAndrey V. Elsukov 		struct uuid p_stor_uuid;/* unique uuid for storage */
9791ca76a5SAndrey V. Elsukov 	} d_partitions[MAXPARTITIONS64];/* actually may be more */
9891ca76a5SAndrey V. Elsukov };
9991ca76a5SAndrey V. Elsukov 
10091ca76a5SAndrey V. Elsukov struct g_part_bsd64_table {
10191ca76a5SAndrey V. Elsukov 	struct g_part_table	base;
10291ca76a5SAndrey V. Elsukov 
10391ca76a5SAndrey V. Elsukov 	uint32_t		d_align;
10491ca76a5SAndrey V. Elsukov 	uint64_t		d_bbase;
10591ca76a5SAndrey V. Elsukov 	uint64_t		d_abase;
10691ca76a5SAndrey V. Elsukov 	struct uuid		d_stor_uuid;
10791ca76a5SAndrey V. Elsukov 	char			d_reserved0[512];
10891ca76a5SAndrey V. Elsukov 	u_char			d_packname[64];
10991ca76a5SAndrey V. Elsukov 	u_char			d_reserved[64];
11091ca76a5SAndrey V. Elsukov };
11191ca76a5SAndrey V. Elsukov 
11291ca76a5SAndrey V. Elsukov struct g_part_bsd64_entry {
11391ca76a5SAndrey V. Elsukov 	struct g_part_entry	base;
11491ca76a5SAndrey V. Elsukov 
11591ca76a5SAndrey V. Elsukov 	uint8_t			fstype;
11691ca76a5SAndrey V. Elsukov 	struct uuid		type_uuid;
11791ca76a5SAndrey V. Elsukov 	struct uuid		stor_uuid;
11891ca76a5SAndrey V. Elsukov };
11991ca76a5SAndrey V. Elsukov 
12091ca76a5SAndrey V. Elsukov static int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *,
12191ca76a5SAndrey V. Elsukov     struct g_part_parms *);
12291ca76a5SAndrey V. Elsukov static int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *);
12391ca76a5SAndrey V. Elsukov static int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *);
12491ca76a5SAndrey V. Elsukov static int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *);
12591ca76a5SAndrey V. Elsukov static void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *,
12691ca76a5SAndrey V. Elsukov     struct sbuf *, const char *);
12791ca76a5SAndrey V. Elsukov static int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *);
12891ca76a5SAndrey V. Elsukov static int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *,
12991ca76a5SAndrey V. Elsukov     struct g_part_parms *);
13091ca76a5SAndrey V. Elsukov static const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *,
13191ca76a5SAndrey V. Elsukov     char *, size_t);
13291ca76a5SAndrey V. Elsukov static int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *);
13391ca76a5SAndrey V. Elsukov static int g_part_bsd64_read(struct g_part_table *, struct g_consumer *);
13491ca76a5SAndrey V. Elsukov static const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *,
13591ca76a5SAndrey V. Elsukov     char *, size_t);
13691ca76a5SAndrey V. Elsukov static int g_part_bsd64_write(struct g_part_table *, struct g_consumer *);
13791ca76a5SAndrey V. Elsukov static int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *,
13891ca76a5SAndrey V. Elsukov     struct g_part_parms *);
13991ca76a5SAndrey V. Elsukov 
14091ca76a5SAndrey V. Elsukov static kobj_method_t g_part_bsd64_methods[] = {
14191ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_add,		g_part_bsd64_add),
14291ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_bootcode,	g_part_bsd64_bootcode),
14391ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_create,	g_part_bsd64_create),
14491ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_destroy,	g_part_bsd64_destroy),
14591ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_dumpconf,	g_part_bsd64_dumpconf),
14691ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_dumpto,	g_part_bsd64_dumpto),
14791ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_modify,	g_part_bsd64_modify),
14891ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_resize,	g_part_bsd64_resize),
14991ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_name,		g_part_bsd64_name),
15091ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_probe,	g_part_bsd64_probe),
15191ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_read,		g_part_bsd64_read),
15291ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_type,		g_part_bsd64_type),
15391ca76a5SAndrey V. Elsukov 	KOBJMETHOD(g_part_write,	g_part_bsd64_write),
15491ca76a5SAndrey V. Elsukov 	{ 0, 0 }
15591ca76a5SAndrey V. Elsukov };
15691ca76a5SAndrey V. Elsukov 
15791ca76a5SAndrey V. Elsukov static struct g_part_scheme g_part_bsd64_scheme = {
15891ca76a5SAndrey V. Elsukov 	"BSD64",
15991ca76a5SAndrey V. Elsukov 	g_part_bsd64_methods,
16091ca76a5SAndrey V. Elsukov 	sizeof(struct g_part_bsd64_table),
16191ca76a5SAndrey V. Elsukov 	.gps_entrysz = sizeof(struct g_part_bsd64_entry),
16291ca76a5SAndrey V. Elsukov 	.gps_minent = MAXPARTITIONS64,
163*09c999b1SWarner Losh 	.gps_defent = MAXPARTITIONS64,
16491ca76a5SAndrey V. Elsukov 	.gps_maxent = MAXPARTITIONS64
16591ca76a5SAndrey V. Elsukov };
16691ca76a5SAndrey V. Elsukov G_PART_SCHEME_DECLARE(g_part_bsd64);
16774d6c131SKyle Evans MODULE_VERSION(geom_part_bsd64, 0);
16891ca76a5SAndrey V. Elsukov 
16991ca76a5SAndrey V. Elsukov #define	EQUUID(a, b)	(memcmp(a, b, sizeof(struct uuid)) == 0)
17091ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED;
17191ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP;
17291ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1;
17391ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM;
17491ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD;
17591ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY;
17691ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER;
17791ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2;
17891ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
17991ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
18091ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
18191ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
18291ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
18391ca76a5SAndrey V. Elsukov static struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
18491ca76a5SAndrey V. Elsukov 
18591ca76a5SAndrey V. Elsukov struct bsd64_uuid_alias {
18691ca76a5SAndrey V. Elsukov 	struct uuid *uuid;
18791ca76a5SAndrey V. Elsukov 	uint8_t fstype;
18891ca76a5SAndrey V. Elsukov 	int alias;
18991ca76a5SAndrey V. Elsukov };
19091ca76a5SAndrey V. Elsukov static struct bsd64_uuid_alias dfbsd_alias_match[] = {
19191ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_swap, FS_SWAP, G_PART_ALIAS_DFBSD_SWAP },
19291ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_ufs1, FS_BSDFFS, G_PART_ALIAS_DFBSD_UFS },
19391ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_vinum, FS_VINUM, G_PART_ALIAS_DFBSD_VINUM },
19491ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_ccd, FS_CCD, G_PART_ALIAS_DFBSD_CCD },
19591ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_legacy, FS_OTHER, G_PART_ALIAS_DFBSD_LEGACY },
19691ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_hammer, FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER },
19791ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_dfbsd_hammer2, FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 },
19891ca76a5SAndrey V. Elsukov 	{ NULL, 0, 0}
19991ca76a5SAndrey V. Elsukov };
20091ca76a5SAndrey V. Elsukov static struct bsd64_uuid_alias fbsd_alias_match[] = {
20191ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_freebsd_boot, FS_OTHER, G_PART_ALIAS_FREEBSD_BOOT },
20291ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_freebsd_swap, FS_OTHER, G_PART_ALIAS_FREEBSD_SWAP },
20391ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_freebsd_ufs, FS_OTHER, G_PART_ALIAS_FREEBSD_UFS },
20491ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_freebsd_zfs, FS_OTHER, G_PART_ALIAS_FREEBSD_ZFS },
20591ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_freebsd_vinum, FS_OTHER, G_PART_ALIAS_FREEBSD_VINUM },
20691ca76a5SAndrey V. Elsukov 	{ &bsd64_uuid_freebsd_nandfs, FS_OTHER, G_PART_ALIAS_FREEBSD_NANDFS },
20791ca76a5SAndrey V. Elsukov 	{ NULL, 0, 0}
20891ca76a5SAndrey V. Elsukov };
20991ca76a5SAndrey V. Elsukov 
21091ca76a5SAndrey V. Elsukov static int
bsd64_parse_type(const char * type,struct g_part_bsd64_entry * entry)21191ca76a5SAndrey V. Elsukov bsd64_parse_type(const char *type, struct g_part_bsd64_entry *entry)
21291ca76a5SAndrey V. Elsukov {
21391ca76a5SAndrey V. Elsukov 	struct uuid tmp;
21491ca76a5SAndrey V. Elsukov 	const struct bsd64_uuid_alias *uap;
21591ca76a5SAndrey V. Elsukov 	const char *alias;
21691ca76a5SAndrey V. Elsukov 	char *p;
21791ca76a5SAndrey V. Elsukov 	long lt;
21891ca76a5SAndrey V. Elsukov 	int error;
21991ca76a5SAndrey V. Elsukov 
22091ca76a5SAndrey V. Elsukov 	if (type[0] == '!') {
22191ca76a5SAndrey V. Elsukov 		if (type[1] == '\0')
22291ca76a5SAndrey V. Elsukov 			return (EINVAL);
22391ca76a5SAndrey V. Elsukov 		lt = strtol(type + 1, &p, 0);
22491ca76a5SAndrey V. Elsukov 		/* The type specified as number */
22591ca76a5SAndrey V. Elsukov 		if (*p == '\0') {
22691ca76a5SAndrey V. Elsukov 			if (lt <= 0 || lt > 255)
22791ca76a5SAndrey V. Elsukov 				return (EINVAL);
22891ca76a5SAndrey V. Elsukov 			entry->fstype = lt;
22991ca76a5SAndrey V. Elsukov 			entry->type_uuid = bsd64_uuid_unused;
23091ca76a5SAndrey V. Elsukov 			return (0);
23191ca76a5SAndrey V. Elsukov 		}
23291ca76a5SAndrey V. Elsukov 		/* The type specified as uuid */
23391ca76a5SAndrey V. Elsukov 		error = parse_uuid(type + 1, &tmp);
23491ca76a5SAndrey V. Elsukov 		if (error != 0)
23591ca76a5SAndrey V. Elsukov 			return (error);
23691ca76a5SAndrey V. Elsukov 		if (EQUUID(&tmp, &bsd64_uuid_unused))
23791ca76a5SAndrey V. Elsukov 			return (EINVAL);
23891ca76a5SAndrey V. Elsukov 		for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) {
23991ca76a5SAndrey V. Elsukov 			if (EQUUID(&tmp, uap->uuid)) {
24091ca76a5SAndrey V. Elsukov 				/* Prefer fstype for known uuids */
24191ca76a5SAndrey V. Elsukov 				entry->type_uuid = bsd64_uuid_unused;
24291ca76a5SAndrey V. Elsukov 				entry->fstype = uap->fstype;
24391ca76a5SAndrey V. Elsukov 				return (0);
24491ca76a5SAndrey V. Elsukov 			}
24591ca76a5SAndrey V. Elsukov 		}
24691ca76a5SAndrey V. Elsukov 		entry->type_uuid = tmp;
24791ca76a5SAndrey V. Elsukov 		entry->fstype = FS_OTHER;
24891ca76a5SAndrey V. Elsukov 		return (0);
24991ca76a5SAndrey V. Elsukov 	}
25091ca76a5SAndrey V. Elsukov 	/* The type specified as symbolic alias name */
25191ca76a5SAndrey V. Elsukov 	for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) {
25291ca76a5SAndrey V. Elsukov 		alias = g_part_alias_name(uap->alias);
25391ca76a5SAndrey V. Elsukov 		if (!strcasecmp(type, alias)) {
25491ca76a5SAndrey V. Elsukov 			entry->type_uuid = *uap->uuid;
25591ca76a5SAndrey V. Elsukov 			entry->fstype = uap->fstype;
25691ca76a5SAndrey V. Elsukov 			return (0);
25791ca76a5SAndrey V. Elsukov 		}
25891ca76a5SAndrey V. Elsukov 	}
25991ca76a5SAndrey V. Elsukov 	for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) {
26091ca76a5SAndrey V. Elsukov 		alias = g_part_alias_name(uap->alias);
26191ca76a5SAndrey V. Elsukov 		if (!strcasecmp(type, alias)) {
26291ca76a5SAndrey V. Elsukov 			entry->type_uuid = bsd64_uuid_unused;
26391ca76a5SAndrey V. Elsukov 			entry->fstype = uap->fstype;
26491ca76a5SAndrey V. Elsukov 			return (0);
26591ca76a5SAndrey V. Elsukov 		}
26691ca76a5SAndrey V. Elsukov 	}
26791ca76a5SAndrey V. Elsukov 	return (EINVAL);
26891ca76a5SAndrey V. Elsukov }
26991ca76a5SAndrey V. Elsukov 
27091ca76a5SAndrey V. Elsukov static int
g_part_bsd64_add(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)27191ca76a5SAndrey V. Elsukov g_part_bsd64_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
27291ca76a5SAndrey V. Elsukov     struct g_part_parms *gpp)
27391ca76a5SAndrey V. Elsukov {
27491ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
27591ca76a5SAndrey V. Elsukov 
27691ca76a5SAndrey V. Elsukov 	if (gpp->gpp_parms & G_PART_PARM_LABEL)
27791ca76a5SAndrey V. Elsukov 		return (EINVAL);
27891ca76a5SAndrey V. Elsukov 
27991ca76a5SAndrey V. Elsukov 	entry = (struct g_part_bsd64_entry *)baseentry;
28091ca76a5SAndrey V. Elsukov 	if (bsd64_parse_type(gpp->gpp_type, entry) != 0)
28191ca76a5SAndrey V. Elsukov 		return (EINVAL);
28291ca76a5SAndrey V. Elsukov 	kern_uuidgen(&entry->stor_uuid, 1);
28391ca76a5SAndrey V. Elsukov 	return (0);
28491ca76a5SAndrey V. Elsukov }
28591ca76a5SAndrey V. Elsukov 
28691ca76a5SAndrey V. Elsukov static int
g_part_bsd64_bootcode(struct g_part_table * basetable,struct g_part_parms * gpp)28791ca76a5SAndrey V. Elsukov g_part_bsd64_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
28891ca76a5SAndrey V. Elsukov {
28991ca76a5SAndrey V. Elsukov 
29091ca76a5SAndrey V. Elsukov 	return (EOPNOTSUPP);
29191ca76a5SAndrey V. Elsukov }
29291ca76a5SAndrey V. Elsukov 
29391ca76a5SAndrey V. Elsukov #define	PALIGN_SIZE	(1024 * 1024)
29491ca76a5SAndrey V. Elsukov #define	PALIGN_MASK	(PALIGN_SIZE - 1)
29591ca76a5SAndrey V. Elsukov #define	BLKSIZE		(4 * 1024)
29691ca76a5SAndrey V. Elsukov #define	BOOTSIZE	(32 * 1024)
29791ca76a5SAndrey V. Elsukov #define	DALIGN_SIZE	(32 * 1024)
29891ca76a5SAndrey V. Elsukov static int
g_part_bsd64_create(struct g_part_table * basetable,struct g_part_parms * gpp)29991ca76a5SAndrey V. Elsukov g_part_bsd64_create(struct g_part_table *basetable, struct g_part_parms *gpp)
30091ca76a5SAndrey V. Elsukov {
30191ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_table *table;
30291ca76a5SAndrey V. Elsukov 	struct g_part_entry *baseentry;
30391ca76a5SAndrey V. Elsukov 	struct g_provider *pp;
30491ca76a5SAndrey V. Elsukov 	uint64_t blkmask, pbase;
30591ca76a5SAndrey V. Elsukov 	uint32_t blksize, ressize;
30691ca76a5SAndrey V. Elsukov 
30791ca76a5SAndrey V. Elsukov 	pp = gpp->gpp_provider;
30891ca76a5SAndrey V. Elsukov 	if (pp->mediasize < 2* PALIGN_SIZE)
30991ca76a5SAndrey V. Elsukov 		return (ENOSPC);
31091ca76a5SAndrey V. Elsukov 
31191ca76a5SAndrey V. Elsukov 	/*
31291ca76a5SAndrey V. Elsukov 	 * Use at least 4KB block size. Blksize is stored in the d_align.
31391ca76a5SAndrey V. Elsukov 	 * XXX: Actually it is used just for calculate d_bbase and used
31491ca76a5SAndrey V. Elsukov 	 * for better alignment in bsdlabel64(8).
31591ca76a5SAndrey V. Elsukov 	 */
31691ca76a5SAndrey V. Elsukov 	blksize = pp->sectorsize < BLKSIZE ? BLKSIZE: pp->sectorsize;
31791ca76a5SAndrey V. Elsukov 	blkmask = blksize - 1;
31891ca76a5SAndrey V. Elsukov 	/* Reserve enough space for RESPARTITIONS64 partitions. */
31991ca76a5SAndrey V. Elsukov 	ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]);
32091ca76a5SAndrey V. Elsukov 	ressize = (ressize + blkmask) & ~blkmask;
32191ca76a5SAndrey V. Elsukov 	/*
32291ca76a5SAndrey V. Elsukov 	 * Reserve enough space for bootcode and align first allocatable
32391ca76a5SAndrey V. Elsukov 	 * offset to PALIGN_SIZE.
32491ca76a5SAndrey V. Elsukov 	 * XXX: Currently DragonFlyBSD has 32KB bootcode, but the size could
32591ca76a5SAndrey V. Elsukov 	 * be bigger, because it is possible change it (it is equal pbase-bbase)
32691ca76a5SAndrey V. Elsukov 	 * in the bsdlabel64(8).
32791ca76a5SAndrey V. Elsukov 	 */
32891ca76a5SAndrey V. Elsukov 	pbase = ressize + ((BOOTSIZE + blkmask) & ~blkmask);
32991ca76a5SAndrey V. Elsukov 	pbase = (pbase + PALIGN_MASK) & ~PALIGN_MASK;
33091ca76a5SAndrey V. Elsukov 	/*
33191ca76a5SAndrey V. Elsukov 	 * Take physical offset into account and make first allocatable
33291ca76a5SAndrey V. Elsukov 	 * offset 32KB aligned to the start of the physical disk.
33391ca76a5SAndrey V. Elsukov 	 * XXX: Actually there are no such restrictions, this is how
33491ca76a5SAndrey V. Elsukov 	 * DragonFlyBSD behaves.
33591ca76a5SAndrey V. Elsukov 	 */
33691ca76a5SAndrey V. Elsukov 	pbase += DALIGN_SIZE - pp->stripeoffset % DALIGN_SIZE;
33791ca76a5SAndrey V. Elsukov 
33891ca76a5SAndrey V. Elsukov 	table = (struct g_part_bsd64_table *)basetable;
33991ca76a5SAndrey V. Elsukov 	table->d_align = blksize;
34091ca76a5SAndrey V. Elsukov 	table->d_bbase = ressize / pp->sectorsize;
34191ca76a5SAndrey V. Elsukov 	table->d_abase = ((pp->mediasize - ressize) &
34291ca76a5SAndrey V. Elsukov 	    ~blkmask) / pp->sectorsize;
34391ca76a5SAndrey V. Elsukov 	kern_uuidgen(&table->d_stor_uuid, 1);
34491ca76a5SAndrey V. Elsukov 	basetable->gpt_first = pbase / pp->sectorsize;
34591ca76a5SAndrey V. Elsukov 	basetable->gpt_last = table->d_abase - 1; /* XXX */
34691ca76a5SAndrey V. Elsukov 	/*
34791ca76a5SAndrey V. Elsukov 	 * Create 'c' partition and make it internal, so user will not be
34891ca76a5SAndrey V. Elsukov 	 * able use it.
34991ca76a5SAndrey V. Elsukov 	 */
35091ca76a5SAndrey V. Elsukov 	baseentry = g_part_new_entry(basetable, RAW_PART + 1, 0, 0);
35191ca76a5SAndrey V. Elsukov 	baseentry->gpe_internal = 1;
35291ca76a5SAndrey V. Elsukov 	return (0);
35391ca76a5SAndrey V. Elsukov }
35491ca76a5SAndrey V. Elsukov 
35591ca76a5SAndrey V. Elsukov static int
g_part_bsd64_destroy(struct g_part_table * basetable,struct g_part_parms * gpp)35691ca76a5SAndrey V. Elsukov g_part_bsd64_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
35791ca76a5SAndrey V. Elsukov {
35891ca76a5SAndrey V. Elsukov 	struct g_provider *pp;
35991ca76a5SAndrey V. Elsukov 
36091ca76a5SAndrey V. Elsukov 	pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
36191ca76a5SAndrey V. Elsukov 	if (pp->sectorsize > offsetof(struct disklabel64, d_magic))
36291ca76a5SAndrey V. Elsukov 		basetable->gpt_smhead |= 1;
36391ca76a5SAndrey V. Elsukov 	else
36491ca76a5SAndrey V. Elsukov 		basetable->gpt_smhead |= 3;
36591ca76a5SAndrey V. Elsukov 	return (0);
36691ca76a5SAndrey V. Elsukov }
36791ca76a5SAndrey V. Elsukov 
36891ca76a5SAndrey V. Elsukov static void
g_part_bsd64_dumpconf(struct g_part_table * basetable,struct g_part_entry * baseentry,struct sbuf * sb,const char * indent)36991ca76a5SAndrey V. Elsukov g_part_bsd64_dumpconf(struct g_part_table *basetable,
37091ca76a5SAndrey V. Elsukov     struct g_part_entry *baseentry, struct sbuf *sb, const char *indent)
37191ca76a5SAndrey V. Elsukov {
37291ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_table *table;
37391ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
37491ca76a5SAndrey V. Elsukov 	char buf[sizeof(table->d_packname)];
37591ca76a5SAndrey V. Elsukov 
37691ca76a5SAndrey V. Elsukov 	entry = (struct g_part_bsd64_entry *)baseentry;
37791ca76a5SAndrey V. Elsukov 	if (indent == NULL) {
37891ca76a5SAndrey V. Elsukov 		/* conftxt: libdisk compatibility */
37991ca76a5SAndrey V. Elsukov 		sbuf_printf(sb, " xs BSD64 xt %u", entry->fstype);
38091ca76a5SAndrey V. Elsukov 	} else if (entry != NULL) {
38191ca76a5SAndrey V. Elsukov 		/* confxml: partition entry information */
38291ca76a5SAndrey V. Elsukov 		sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
38391ca76a5SAndrey V. Elsukov 		    entry->fstype);
38491ca76a5SAndrey V. Elsukov 		if (!EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) {
38591ca76a5SAndrey V. Elsukov 			sbuf_printf(sb, "%s<type_uuid>", indent);
38691ca76a5SAndrey V. Elsukov 			sbuf_printf_uuid(sb, &entry->type_uuid);
38749ee0fceSAlexander Motin 			sbuf_cat(sb, "</type_uuid>\n");
38891ca76a5SAndrey V. Elsukov 		}
38991ca76a5SAndrey V. Elsukov 		sbuf_printf(sb, "%s<stor_uuid>", indent);
39091ca76a5SAndrey V. Elsukov 		sbuf_printf_uuid(sb, &entry->stor_uuid);
39149ee0fceSAlexander Motin 		sbuf_cat(sb, "</stor_uuid>\n");
39291ca76a5SAndrey V. Elsukov 	} else {
39391ca76a5SAndrey V. Elsukov 		/* confxml: scheme information */
39491ca76a5SAndrey V. Elsukov 		table = (struct g_part_bsd64_table *)basetable;
39591ca76a5SAndrey V. Elsukov 		sbuf_printf(sb, "%s<bootbase>%ju</bootbase>\n", indent,
39691ca76a5SAndrey V. Elsukov 		    (uintmax_t)table->d_bbase);
39791ca76a5SAndrey V. Elsukov 		if (table->d_abase)
39891ca76a5SAndrey V. Elsukov 			sbuf_printf(sb, "%s<backupbase>%ju</backupbase>\n",
39991ca76a5SAndrey V. Elsukov 			    indent, (uintmax_t)table->d_abase);
40091ca76a5SAndrey V. Elsukov 		sbuf_printf(sb, "%s<stor_uuid>", indent);
40191ca76a5SAndrey V. Elsukov 		sbuf_printf_uuid(sb, &table->d_stor_uuid);
40249ee0fceSAlexander Motin 		sbuf_cat(sb, "</stor_uuid>\n");
40391ca76a5SAndrey V. Elsukov 		sbuf_printf(sb, "%s<label>", indent);
40491ca76a5SAndrey V. Elsukov 		strncpy(buf, table->d_packname, sizeof(buf) - 1);
40591ca76a5SAndrey V. Elsukov 		buf[sizeof(buf) - 1] = '\0';
40649ee0fceSAlexander Motin 		g_conf_cat_escaped(sb, buf);
40749ee0fceSAlexander Motin 		sbuf_cat(sb, "</label>\n");
40891ca76a5SAndrey V. Elsukov 	}
40991ca76a5SAndrey V. Elsukov }
41091ca76a5SAndrey V. Elsukov 
41191ca76a5SAndrey V. Elsukov static int
g_part_bsd64_dumpto(struct g_part_table * table,struct g_part_entry * baseentry)41291ca76a5SAndrey V. Elsukov g_part_bsd64_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
41391ca76a5SAndrey V. Elsukov {
41491ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
41591ca76a5SAndrey V. Elsukov 
41691ca76a5SAndrey V. Elsukov 	/* Allow dumping to a swap partition. */
41791ca76a5SAndrey V. Elsukov 	entry = (struct g_part_bsd64_entry *)baseentry;
41891ca76a5SAndrey V. Elsukov 	if (entry->fstype == FS_SWAP ||
41991ca76a5SAndrey V. Elsukov 	    EQUUID(&entry->type_uuid, &bsd64_uuid_dfbsd_swap) ||
42091ca76a5SAndrey V. Elsukov 	    EQUUID(&entry->type_uuid, &bsd64_uuid_freebsd_swap))
42191ca76a5SAndrey V. Elsukov 		return (1);
42291ca76a5SAndrey V. Elsukov 	return (0);
42391ca76a5SAndrey V. Elsukov }
42491ca76a5SAndrey V. Elsukov 
42591ca76a5SAndrey V. Elsukov static int
g_part_bsd64_modify(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)42691ca76a5SAndrey V. Elsukov g_part_bsd64_modify(struct g_part_table *basetable,
42791ca76a5SAndrey V. Elsukov     struct g_part_entry *baseentry, struct g_part_parms *gpp)
42891ca76a5SAndrey V. Elsukov {
42991ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
43091ca76a5SAndrey V. Elsukov 
43191ca76a5SAndrey V. Elsukov 	if (gpp->gpp_parms & G_PART_PARM_LABEL)
43291ca76a5SAndrey V. Elsukov 		return (EINVAL);
43391ca76a5SAndrey V. Elsukov 
43491ca76a5SAndrey V. Elsukov 	entry = (struct g_part_bsd64_entry *)baseentry;
43591ca76a5SAndrey V. Elsukov 	if (gpp->gpp_parms & G_PART_PARM_TYPE)
43691ca76a5SAndrey V. Elsukov 		return (bsd64_parse_type(gpp->gpp_type, entry));
43791ca76a5SAndrey V. Elsukov 	return (0);
43891ca76a5SAndrey V. Elsukov }
43991ca76a5SAndrey V. Elsukov 
44091ca76a5SAndrey V. Elsukov static int
g_part_bsd64_resize(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)44191ca76a5SAndrey V. Elsukov g_part_bsd64_resize(struct g_part_table *basetable,
44291ca76a5SAndrey V. Elsukov     struct g_part_entry *baseentry, struct g_part_parms *gpp)
44391ca76a5SAndrey V. Elsukov {
44491ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_table *table;
44591ca76a5SAndrey V. Elsukov 	struct g_provider *pp;
44691ca76a5SAndrey V. Elsukov 
44791ca76a5SAndrey V. Elsukov 	if (baseentry == NULL) {
44891ca76a5SAndrey V. Elsukov 		pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
44991ca76a5SAndrey V. Elsukov 		table = (struct g_part_bsd64_table *)basetable;
450d9c9c81cSPedro F. Giffuni 		table->d_abase =
451d9c9c81cSPedro F. Giffuni 		    rounddown2(pp->mediasize - table->d_bbase * pp->sectorsize,
452d9c9c81cSPedro F. Giffuni 		        table->d_align) / pp->sectorsize;
45391ca76a5SAndrey V. Elsukov 		basetable->gpt_last = table->d_abase - 1;
45491ca76a5SAndrey V. Elsukov 		return (0);
45591ca76a5SAndrey V. Elsukov 	}
45691ca76a5SAndrey V. Elsukov 	baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
45791ca76a5SAndrey V. Elsukov 	return (0);
45891ca76a5SAndrey V. Elsukov }
45991ca76a5SAndrey V. Elsukov 
46091ca76a5SAndrey V. Elsukov static const char *
g_part_bsd64_name(struct g_part_table * table,struct g_part_entry * baseentry,char * buf,size_t bufsz)46191ca76a5SAndrey V. Elsukov g_part_bsd64_name(struct g_part_table *table, struct g_part_entry *baseentry,
46291ca76a5SAndrey V. Elsukov     char *buf, size_t bufsz)
46391ca76a5SAndrey V. Elsukov {
46491ca76a5SAndrey V. Elsukov 
46591ca76a5SAndrey V. Elsukov 	snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
46691ca76a5SAndrey V. Elsukov 	return (buf);
46791ca76a5SAndrey V. Elsukov }
46891ca76a5SAndrey V. Elsukov 
46991ca76a5SAndrey V. Elsukov static int
g_part_bsd64_probe(struct g_part_table * table,struct g_consumer * cp)47091ca76a5SAndrey V. Elsukov g_part_bsd64_probe(struct g_part_table *table, struct g_consumer *cp)
47191ca76a5SAndrey V. Elsukov {
47291ca76a5SAndrey V. Elsukov 	struct g_provider *pp;
47391ca76a5SAndrey V. Elsukov 	uint32_t v;
47491ca76a5SAndrey V. Elsukov 	int error;
47591ca76a5SAndrey V. Elsukov 	u_char *buf;
47691ca76a5SAndrey V. Elsukov 
47791ca76a5SAndrey V. Elsukov 	pp = cp->provider;
47891ca76a5SAndrey V. Elsukov 	if (pp->mediasize < 2 * PALIGN_SIZE)
47991ca76a5SAndrey V. Elsukov 		return (ENOSPC);
480d9c9c81cSPedro F. Giffuni 	v = rounddown2(pp->sectorsize + offsetof(struct disklabel64, d_magic),
481d9c9c81cSPedro F. Giffuni 		       pp->sectorsize);
48291ca76a5SAndrey V. Elsukov 	buf = g_read_data(cp, 0, v, &error);
48391ca76a5SAndrey V. Elsukov 	if (buf == NULL)
48491ca76a5SAndrey V. Elsukov 		return (error);
48591ca76a5SAndrey V. Elsukov 	v = le32dec(buf + offsetof(struct disklabel64, d_magic));
48691ca76a5SAndrey V. Elsukov 	g_free(buf);
48791ca76a5SAndrey V. Elsukov 	return (v == DISKMAGIC64 ? G_PART_PROBE_PRI_HIGH: ENXIO);
48891ca76a5SAndrey V. Elsukov }
48991ca76a5SAndrey V. Elsukov 
49091ca76a5SAndrey V. Elsukov static int
g_part_bsd64_read(struct g_part_table * basetable,struct g_consumer * cp)49191ca76a5SAndrey V. Elsukov g_part_bsd64_read(struct g_part_table *basetable, struct g_consumer *cp)
49291ca76a5SAndrey V. Elsukov {
49391ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_table *table;
49491ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
49591ca76a5SAndrey V. Elsukov 	struct g_part_entry *baseentry;
49691ca76a5SAndrey V. Elsukov 	struct g_provider *pp;
49791ca76a5SAndrey V. Elsukov 	struct disklabel64 *dlp;
49891ca76a5SAndrey V. Elsukov 	uint64_t v64, sz;
49991ca76a5SAndrey V. Elsukov 	uint32_t v32;
50091ca76a5SAndrey V. Elsukov 	int error, index;
50191ca76a5SAndrey V. Elsukov 	u_char *buf;
50291ca76a5SAndrey V. Elsukov 
50391ca76a5SAndrey V. Elsukov 	pp = cp->provider;
50491ca76a5SAndrey V. Elsukov 	table = (struct g_part_bsd64_table *)basetable;
505d9c9c81cSPedro F. Giffuni 	v32 = roundup2(sizeof(struct disklabel64), pp->sectorsize);
50691ca76a5SAndrey V. Elsukov 	buf = g_read_data(cp, 0, v32, &error);
50791ca76a5SAndrey V. Elsukov 	if (buf == NULL)
50891ca76a5SAndrey V. Elsukov 		return (error);
50991ca76a5SAndrey V. Elsukov 
51091ca76a5SAndrey V. Elsukov 	dlp = (struct disklabel64 *)buf;
51191ca76a5SAndrey V. Elsukov 	basetable->gpt_entries = le32toh(dlp->d_npartitions);
5125ad33e77SConrad Meyer 	if (basetable->gpt_entries > MAXPARTITIONS64 ||
5135ad33e77SConrad Meyer 	    basetable->gpt_entries < 1)
51491ca76a5SAndrey V. Elsukov 		goto invalid_label;
51591ca76a5SAndrey V. Elsukov 	v32 = le32toh(dlp->d_crc);
51691ca76a5SAndrey V. Elsukov 	dlp->d_crc = 0;
51791ca76a5SAndrey V. Elsukov 	if (crc32(&dlp->d_magic, offsetof(struct disklabel64,
51891ca76a5SAndrey V. Elsukov 	    d_partitions[basetable->gpt_entries]) -
51991ca76a5SAndrey V. Elsukov 	    offsetof(struct disklabel64, d_magic)) != v32)
52091ca76a5SAndrey V. Elsukov 		goto invalid_label;
52191ca76a5SAndrey V. Elsukov 	table->d_align = le32toh(dlp->d_align);
52291ca76a5SAndrey V. Elsukov 	if (table->d_align == 0 || (table->d_align & (pp->sectorsize - 1)))
52391ca76a5SAndrey V. Elsukov 		goto invalid_label;
52491ca76a5SAndrey V. Elsukov 	if (le64toh(dlp->d_total_size) > pp->mediasize)
52591ca76a5SAndrey V. Elsukov 		goto invalid_label;
52691ca76a5SAndrey V. Elsukov 	v64 = le64toh(dlp->d_pbase);
52791ca76a5SAndrey V. Elsukov 	if (v64 % pp->sectorsize)
52891ca76a5SAndrey V. Elsukov 		goto invalid_label;
52991ca76a5SAndrey V. Elsukov 	basetable->gpt_first = v64 / pp->sectorsize;
53091ca76a5SAndrey V. Elsukov 	v64 = le64toh(dlp->d_pstop);
53191ca76a5SAndrey V. Elsukov 	if (v64 % pp->sectorsize)
53291ca76a5SAndrey V. Elsukov 		goto invalid_label;
53391ca76a5SAndrey V. Elsukov 	basetable->gpt_last = v64 / pp->sectorsize;
53491ca76a5SAndrey V. Elsukov 	basetable->gpt_isleaf = 1;
53591ca76a5SAndrey V. Elsukov 	v64 = le64toh(dlp->d_bbase);
53691ca76a5SAndrey V. Elsukov 	if (v64 % pp->sectorsize)
53791ca76a5SAndrey V. Elsukov 		goto invalid_label;
53891ca76a5SAndrey V. Elsukov 	table->d_bbase = v64 / pp->sectorsize;
53991ca76a5SAndrey V. Elsukov 	v64 = le64toh(dlp->d_abase);
54091ca76a5SAndrey V. Elsukov 	if (v64 % pp->sectorsize)
54191ca76a5SAndrey V. Elsukov 		goto invalid_label;
54291ca76a5SAndrey V. Elsukov 	table->d_abase = v64 / pp->sectorsize;
54391ca76a5SAndrey V. Elsukov 	le_uuid_dec(&dlp->d_stor_uuid, &table->d_stor_uuid);
54491ca76a5SAndrey V. Elsukov 	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
54591ca76a5SAndrey V. Elsukov 		if (index == RAW_PART) {
54691ca76a5SAndrey V. Elsukov 			/* Skip 'c' partition. */
54791ca76a5SAndrey V. Elsukov 			baseentry = g_part_new_entry(basetable,
54891ca76a5SAndrey V. Elsukov 			    index + 1, 0, 0);
54991ca76a5SAndrey V. Elsukov 			baseentry->gpe_internal = 1;
55091ca76a5SAndrey V. Elsukov 			continue;
55191ca76a5SAndrey V. Elsukov 		}
55291ca76a5SAndrey V. Elsukov 		v64 = le64toh(dlp->d_partitions[index].p_boffset);
55391ca76a5SAndrey V. Elsukov 		sz = le64toh(dlp->d_partitions[index].p_bsize);
55491ca76a5SAndrey V. Elsukov 		if (sz == 0 && v64 == 0)
55591ca76a5SAndrey V. Elsukov 			continue;
55691ca76a5SAndrey V. Elsukov 		if (sz == 0 || (v64 % pp->sectorsize) || (sz % pp->sectorsize))
55791ca76a5SAndrey V. Elsukov 			goto invalid_label;
55891ca76a5SAndrey V. Elsukov 		baseentry = g_part_new_entry(basetable, index + 1,
55991ca76a5SAndrey V. Elsukov 		    v64 / pp->sectorsize, (v64 + sz) / pp->sectorsize - 1);
56091ca76a5SAndrey V. Elsukov 		entry = (struct g_part_bsd64_entry *)baseentry;
56191ca76a5SAndrey V. Elsukov 		le_uuid_dec(&dlp->d_partitions[index].p_type_uuid,
56291ca76a5SAndrey V. Elsukov 		    &entry->type_uuid);
56391ca76a5SAndrey V. Elsukov 		le_uuid_dec(&dlp->d_partitions[index].p_stor_uuid,
56491ca76a5SAndrey V. Elsukov 		    &entry->stor_uuid);
56591ca76a5SAndrey V. Elsukov 		entry->fstype = dlp->d_partitions[index].p_fstype;
56691ca76a5SAndrey V. Elsukov 	}
56791ca76a5SAndrey V. Elsukov 	bcopy(dlp->d_reserved0, table->d_reserved0,
56891ca76a5SAndrey V. Elsukov 	    sizeof(table->d_reserved0));
56991ca76a5SAndrey V. Elsukov 	bcopy(dlp->d_packname, table->d_packname, sizeof(table->d_packname));
57091ca76a5SAndrey V. Elsukov 	bcopy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved));
57191ca76a5SAndrey V. Elsukov 	g_free(buf);
57291ca76a5SAndrey V. Elsukov 	return (0);
57391ca76a5SAndrey V. Elsukov 
57491ca76a5SAndrey V. Elsukov invalid_label:
57591ca76a5SAndrey V. Elsukov 	g_free(buf);
57691ca76a5SAndrey V. Elsukov 	return (EINVAL);
57791ca76a5SAndrey V. Elsukov }
57891ca76a5SAndrey V. Elsukov 
57991ca76a5SAndrey V. Elsukov static const char *
g_part_bsd64_type(struct g_part_table * basetable,struct g_part_entry * baseentry,char * buf,size_t bufsz)58091ca76a5SAndrey V. Elsukov g_part_bsd64_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
58191ca76a5SAndrey V. Elsukov     char *buf, size_t bufsz)
58291ca76a5SAndrey V. Elsukov {
58391ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
58491ca76a5SAndrey V. Elsukov 	struct bsd64_uuid_alias *uap;
58591ca76a5SAndrey V. Elsukov 
58691ca76a5SAndrey V. Elsukov 	entry = (struct g_part_bsd64_entry *)baseentry;
58791ca76a5SAndrey V. Elsukov 	if (entry->fstype != FS_OTHER) {
58891ca76a5SAndrey V. Elsukov 		for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++)
58991ca76a5SAndrey V. Elsukov 			if (uap->fstype == entry->fstype)
59091ca76a5SAndrey V. Elsukov 				return (g_part_alias_name(uap->alias));
59191ca76a5SAndrey V. Elsukov 	} else {
59291ca76a5SAndrey V. Elsukov 		for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++)
59391ca76a5SAndrey V. Elsukov 			if (EQUUID(uap->uuid, &entry->type_uuid))
59491ca76a5SAndrey V. Elsukov 				return (g_part_alias_name(uap->alias));
59591ca76a5SAndrey V. Elsukov 		for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++)
59691ca76a5SAndrey V. Elsukov 			if (EQUUID(uap->uuid, &entry->type_uuid))
59791ca76a5SAndrey V. Elsukov 				return (g_part_alias_name(uap->alias));
59891ca76a5SAndrey V. Elsukov 	}
59991ca76a5SAndrey V. Elsukov 	if (EQUUID(&bsd64_uuid_unused, &entry->type_uuid))
60091ca76a5SAndrey V. Elsukov 		snprintf(buf, bufsz, "!%d", entry->fstype);
60191ca76a5SAndrey V. Elsukov 	else {
60291ca76a5SAndrey V. Elsukov 		buf[0] = '!';
60391ca76a5SAndrey V. Elsukov 		snprintf_uuid(buf + 1, bufsz - 1, &entry->type_uuid);
60491ca76a5SAndrey V. Elsukov 	}
60591ca76a5SAndrey V. Elsukov 	return (buf);
60691ca76a5SAndrey V. Elsukov }
60791ca76a5SAndrey V. Elsukov 
60891ca76a5SAndrey V. Elsukov static int
g_part_bsd64_write(struct g_part_table * basetable,struct g_consumer * cp)60991ca76a5SAndrey V. Elsukov g_part_bsd64_write(struct g_part_table *basetable, struct g_consumer *cp)
61091ca76a5SAndrey V. Elsukov {
61191ca76a5SAndrey V. Elsukov 	struct g_provider *pp;
61291ca76a5SAndrey V. Elsukov 	struct g_part_entry *baseentry;
61391ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_entry *entry;
61491ca76a5SAndrey V. Elsukov 	struct g_part_bsd64_table *table;
61591ca76a5SAndrey V. Elsukov 	struct disklabel64 *dlp;
61691ca76a5SAndrey V. Elsukov 	uint32_t v, sz;
61791ca76a5SAndrey V. Elsukov 	int error, index;
61891ca76a5SAndrey V. Elsukov 
61991ca76a5SAndrey V. Elsukov 	pp = cp->provider;
62091ca76a5SAndrey V. Elsukov 	table = (struct g_part_bsd64_table *)basetable;
621d9c9c81cSPedro F. Giffuni 	sz = roundup2(sizeof(struct disklabel64), pp->sectorsize);
62291ca76a5SAndrey V. Elsukov 	dlp = g_malloc(sz, M_WAITOK | M_ZERO);
62391ca76a5SAndrey V. Elsukov 
62491ca76a5SAndrey V. Elsukov 	memcpy(dlp->d_reserved0, table->d_reserved0,
62591ca76a5SAndrey V. Elsukov 	    sizeof(table->d_reserved0));
62691ca76a5SAndrey V. Elsukov 	memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname));
62791ca76a5SAndrey V. Elsukov 	memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved));
62891ca76a5SAndrey V. Elsukov 	le32enc(&dlp->d_magic, DISKMAGIC64);
62991ca76a5SAndrey V. Elsukov 	le32enc(&dlp->d_align, table->d_align);
63091ca76a5SAndrey V. Elsukov 	le32enc(&dlp->d_npartitions, basetable->gpt_entries);
63191ca76a5SAndrey V. Elsukov 	le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid);
63291ca76a5SAndrey V. Elsukov 	le64enc(&dlp->d_total_size, pp->mediasize);
63391ca76a5SAndrey V. Elsukov 	le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize);
63491ca76a5SAndrey V. Elsukov 	le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize);
63591ca76a5SAndrey V. Elsukov 	le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize);
63691ca76a5SAndrey V. Elsukov 	le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize);
63791ca76a5SAndrey V. Elsukov 
63891ca76a5SAndrey V. Elsukov 	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
63991ca76a5SAndrey V. Elsukov 		if (baseentry->gpe_deleted)
64091ca76a5SAndrey V. Elsukov 			continue;
64191ca76a5SAndrey V. Elsukov 		index = baseentry->gpe_index - 1;
64291ca76a5SAndrey V. Elsukov 		entry = (struct g_part_bsd64_entry *)baseentry;
64391ca76a5SAndrey V. Elsukov 		if (index == RAW_PART)
64491ca76a5SAndrey V. Elsukov 			continue;
64591ca76a5SAndrey V. Elsukov 		le64enc(&dlp->d_partitions[index].p_boffset,
64691ca76a5SAndrey V. Elsukov 		    baseentry->gpe_start * pp->sectorsize);
64791ca76a5SAndrey V. Elsukov 		le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize *
64891ca76a5SAndrey V. Elsukov 		    (baseentry->gpe_end - baseentry->gpe_start + 1));
64991ca76a5SAndrey V. Elsukov 		dlp->d_partitions[index].p_fstype = entry->fstype;
65091ca76a5SAndrey V. Elsukov 		le_uuid_enc(&dlp->d_partitions[index].p_type_uuid,
65191ca76a5SAndrey V. Elsukov 		    &entry->type_uuid);
65291ca76a5SAndrey V. Elsukov 		le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid,
65391ca76a5SAndrey V. Elsukov 		    &entry->stor_uuid);
65491ca76a5SAndrey V. Elsukov 	}
65591ca76a5SAndrey V. Elsukov 	/* Calculate checksum. */
65691ca76a5SAndrey V. Elsukov 	v = offsetof(struct disklabel64,
65791ca76a5SAndrey V. Elsukov 	    d_partitions[basetable->gpt_entries]) -
65891ca76a5SAndrey V. Elsukov 	    offsetof(struct disklabel64, d_magic);
65991ca76a5SAndrey V. Elsukov 	le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v));
66091ca76a5SAndrey V. Elsukov 	error = g_write_data(cp, 0, dlp, sz);
66191ca76a5SAndrey V. Elsukov 	g_free(dlp);
66291ca76a5SAndrey V. Elsukov 	return (error);
66391ca76a5SAndrey V. Elsukov }
664