xref: /freebsd/sys/geom/part/g_part_bsd64.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
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