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