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/param.h>
28 #include <sys/bio.h>
29 #include <sys/gsb_crc32.h>
30 #include <sys/disklabel.h>
31 #include <sys/endian.h>
32 #include <sys/gpt.h>
33 #include <sys/kernel.h>
34 #include <sys/kobj.h>
35 #include <sys/limits.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/mutex.h>
39 #include <sys/queue.h>
40 #include <sys/sbuf.h>
41 #include <sys/systm.h>
42 #include <sys/sysctl.h>
43 #include <geom/geom.h>
44 #include <geom/geom_int.h>
45 #include <geom/part/g_part.h>
46
47 #include "g_part_if.h"
48
49 FEATURE(geom_part_bsd64, "GEOM partitioning class for 64-bit BSD disklabels");
50
51 /* XXX: move this to sys/disklabel64.h */
52 #define DISKMAGIC64 ((uint32_t)0xc4464c59)
53 #define MAXPARTITIONS64 16
54 #define RESPARTITIONS64 32
55
56 struct disklabel64 {
57 char d_reserved0[512]; /* reserved or unused */
58 uint32_t d_magic; /* the magic number */
59 uint32_t d_crc; /* crc32() d_magic through last part */
60 uint32_t d_align; /* partition alignment requirement */
61 uint32_t d_npartitions; /* number of partitions */
62 struct uuid d_stor_uuid; /* unique uuid for label */
63
64 uint64_t d_total_size; /* total size incl everything (bytes) */
65 uint64_t d_bbase; /* boot area base offset (bytes) */
66 /* boot area is pbase - bbase */
67 uint64_t d_pbase; /* first allocatable offset (bytes) */
68 uint64_t d_pstop; /* last allocatable offset+1 (bytes) */
69 uint64_t d_abase; /* location of backup copy if not 0 */
70
71 u_char d_packname[64];
72 u_char d_reserved[64];
73
74 /*
75 * Note: offsets are relative to the base of the slice, NOT to
76 * d_pbase. Unlike 32 bit disklabels the on-disk format for
77 * a 64 bit disklabel remains slice-relative.
78 *
79 * An uninitialized partition has a p_boffset and p_bsize of 0.
80 *
81 * If p_fstype is not supported for a live partition it is set
82 * to FS_OTHER. This is typically the case when the filesystem
83 * is identified by its uuid.
84 */
85 struct partition64 { /* the partition table */
86 uint64_t p_boffset; /* slice relative offset, in bytes */
87 uint64_t p_bsize; /* size of partition, in bytes */
88 uint8_t p_fstype;
89 uint8_t p_unused01; /* reserved, must be 0 */
90 uint8_t p_unused02; /* reserved, must be 0 */
91 uint8_t p_unused03; /* reserved, must be 0 */
92 uint32_t p_unused04; /* reserved, must be 0 */
93 uint32_t p_unused05; /* reserved, must be 0 */
94 uint32_t p_unused06; /* reserved, must be 0 */
95 struct uuid p_type_uuid;/* mount type as UUID */
96 struct uuid p_stor_uuid;/* unique uuid for storage */
97 } d_partitions[MAXPARTITIONS64];/* actually may be more */
98 };
99
100 struct g_part_bsd64_table {
101 struct g_part_table base;
102
103 uint32_t d_align;
104 uint64_t d_bbase;
105 uint64_t d_abase;
106 struct uuid d_stor_uuid;
107 char d_reserved0[512];
108 u_char d_packname[64];
109 u_char d_reserved[64];
110 };
111
112 struct g_part_bsd64_entry {
113 struct g_part_entry base;
114
115 uint8_t fstype;
116 struct uuid type_uuid;
117 struct uuid stor_uuid;
118 };
119
120 static int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *,
121 struct g_part_parms *);
122 static int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *);
123 static int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *);
124 static int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *);
125 static void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *,
126 struct sbuf *, const char *);
127 static int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *);
128 static int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *,
129 struct g_part_parms *);
130 static const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *,
131 char *, size_t);
132 static int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *);
133 static int g_part_bsd64_read(struct g_part_table *, struct g_consumer *);
134 static const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *,
135 char *, size_t);
136 static int g_part_bsd64_write(struct g_part_table *, struct g_consumer *);
137 static int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *,
138 struct g_part_parms *);
139
140 static kobj_method_t g_part_bsd64_methods[] = {
141 KOBJMETHOD(g_part_add, g_part_bsd64_add),
142 KOBJMETHOD(g_part_bootcode, g_part_bsd64_bootcode),
143 KOBJMETHOD(g_part_create, g_part_bsd64_create),
144 KOBJMETHOD(g_part_destroy, g_part_bsd64_destroy),
145 KOBJMETHOD(g_part_dumpconf, g_part_bsd64_dumpconf),
146 KOBJMETHOD(g_part_dumpto, g_part_bsd64_dumpto),
147 KOBJMETHOD(g_part_modify, g_part_bsd64_modify),
148 KOBJMETHOD(g_part_resize, g_part_bsd64_resize),
149 KOBJMETHOD(g_part_name, g_part_bsd64_name),
150 KOBJMETHOD(g_part_probe, g_part_bsd64_probe),
151 KOBJMETHOD(g_part_read, g_part_bsd64_read),
152 KOBJMETHOD(g_part_type, g_part_bsd64_type),
153 KOBJMETHOD(g_part_write, g_part_bsd64_write),
154 { 0, 0 }
155 };
156
157 static struct g_part_scheme g_part_bsd64_scheme = {
158 "BSD64",
159 g_part_bsd64_methods,
160 sizeof(struct g_part_bsd64_table),
161 .gps_entrysz = sizeof(struct g_part_bsd64_entry),
162 .gps_minent = MAXPARTITIONS64,
163 .gps_maxent = MAXPARTITIONS64
164 };
165 G_PART_SCHEME_DECLARE(g_part_bsd64);
166 MODULE_VERSION(geom_part_bsd64, 0);
167
168 #define EQUUID(a, b) (memcmp(a, b, sizeof(struct uuid)) == 0)
169 static struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED;
170 static struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP;
171 static struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1;
172 static struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM;
173 static struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD;
174 static struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY;
175 static struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER;
176 static struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2;
177 static struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
178 static struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
179 static struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
180 static struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
181 static struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
182 static struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
183
184 struct bsd64_uuid_alias {
185 struct uuid *uuid;
186 uint8_t fstype;
187 int alias;
188 };
189 static struct bsd64_uuid_alias dfbsd_alias_match[] = {
190 { &bsd64_uuid_dfbsd_swap, FS_SWAP, G_PART_ALIAS_DFBSD_SWAP },
191 { &bsd64_uuid_dfbsd_ufs1, FS_BSDFFS, G_PART_ALIAS_DFBSD_UFS },
192 { &bsd64_uuid_dfbsd_vinum, FS_VINUM, G_PART_ALIAS_DFBSD_VINUM },
193 { &bsd64_uuid_dfbsd_ccd, FS_CCD, G_PART_ALIAS_DFBSD_CCD },
194 { &bsd64_uuid_dfbsd_legacy, FS_OTHER, G_PART_ALIAS_DFBSD_LEGACY },
195 { &bsd64_uuid_dfbsd_hammer, FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER },
196 { &bsd64_uuid_dfbsd_hammer2, FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 },
197 { NULL, 0, 0}
198 };
199 static struct bsd64_uuid_alias fbsd_alias_match[] = {
200 { &bsd64_uuid_freebsd_boot, FS_OTHER, G_PART_ALIAS_FREEBSD_BOOT },
201 { &bsd64_uuid_freebsd_swap, FS_OTHER, G_PART_ALIAS_FREEBSD_SWAP },
202 { &bsd64_uuid_freebsd_ufs, FS_OTHER, G_PART_ALIAS_FREEBSD_UFS },
203 { &bsd64_uuid_freebsd_zfs, FS_OTHER, G_PART_ALIAS_FREEBSD_ZFS },
204 { &bsd64_uuid_freebsd_vinum, FS_OTHER, G_PART_ALIAS_FREEBSD_VINUM },
205 { &bsd64_uuid_freebsd_nandfs, FS_OTHER, G_PART_ALIAS_FREEBSD_NANDFS },
206 { NULL, 0, 0}
207 };
208
209 static int
bsd64_parse_type(const char * type,struct g_part_bsd64_entry * entry)210 bsd64_parse_type(const char *type, struct g_part_bsd64_entry *entry)
211 {
212 struct uuid tmp;
213 const struct bsd64_uuid_alias *uap;
214 const char *alias;
215 char *p;
216 long lt;
217 int error;
218
219 if (type[0] == '!') {
220 if (type[1] == '\0')
221 return (EINVAL);
222 lt = strtol(type + 1, &p, 0);
223 /* The type specified as number */
224 if (*p == '\0') {
225 if (lt <= 0 || lt > 255)
226 return (EINVAL);
227 entry->fstype = lt;
228 entry->type_uuid = bsd64_uuid_unused;
229 return (0);
230 }
231 /* The type specified as uuid */
232 error = parse_uuid(type + 1, &tmp);
233 if (error != 0)
234 return (error);
235 if (EQUUID(&tmp, &bsd64_uuid_unused))
236 return (EINVAL);
237 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) {
238 if (EQUUID(&tmp, uap->uuid)) {
239 /* Prefer fstype for known uuids */
240 entry->type_uuid = bsd64_uuid_unused;
241 entry->fstype = uap->fstype;
242 return (0);
243 }
244 }
245 entry->type_uuid = tmp;
246 entry->fstype = FS_OTHER;
247 return (0);
248 }
249 /* The type specified as symbolic alias name */
250 for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) {
251 alias = g_part_alias_name(uap->alias);
252 if (!strcasecmp(type, alias)) {
253 entry->type_uuid = *uap->uuid;
254 entry->fstype = uap->fstype;
255 return (0);
256 }
257 }
258 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) {
259 alias = g_part_alias_name(uap->alias);
260 if (!strcasecmp(type, alias)) {
261 entry->type_uuid = bsd64_uuid_unused;
262 entry->fstype = uap->fstype;
263 return (0);
264 }
265 }
266 return (EINVAL);
267 }
268
269 static int
g_part_bsd64_add(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)270 g_part_bsd64_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
271 struct g_part_parms *gpp)
272 {
273 struct g_part_bsd64_entry *entry;
274
275 if (gpp->gpp_parms & G_PART_PARM_LABEL)
276 return (EINVAL);
277
278 entry = (struct g_part_bsd64_entry *)baseentry;
279 if (bsd64_parse_type(gpp->gpp_type, entry) != 0)
280 return (EINVAL);
281 kern_uuidgen(&entry->stor_uuid, 1);
282 return (0);
283 }
284
285 static int
g_part_bsd64_bootcode(struct g_part_table * basetable,struct g_part_parms * gpp)286 g_part_bsd64_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
287 {
288
289 return (EOPNOTSUPP);
290 }
291
292 #define PALIGN_SIZE (1024 * 1024)
293 #define PALIGN_MASK (PALIGN_SIZE - 1)
294 #define BLKSIZE (4 * 1024)
295 #define BOOTSIZE (32 * 1024)
296 #define DALIGN_SIZE (32 * 1024)
297 static int
g_part_bsd64_create(struct g_part_table * basetable,struct g_part_parms * gpp)298 g_part_bsd64_create(struct g_part_table *basetable, struct g_part_parms *gpp)
299 {
300 struct g_part_bsd64_table *table;
301 struct g_part_entry *baseentry;
302 struct g_provider *pp;
303 uint64_t blkmask, pbase;
304 uint32_t blksize, ressize;
305
306 pp = gpp->gpp_provider;
307 if (pp->mediasize < 2* PALIGN_SIZE)
308 return (ENOSPC);
309
310 /*
311 * Use at least 4KB block size. Blksize is stored in the d_align.
312 * XXX: Actually it is used just for calculate d_bbase and used
313 * for better alignment in bsdlabel64(8).
314 */
315 blksize = pp->sectorsize < BLKSIZE ? BLKSIZE: pp->sectorsize;
316 blkmask = blksize - 1;
317 /* Reserve enough space for RESPARTITIONS64 partitions. */
318 ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]);
319 ressize = (ressize + blkmask) & ~blkmask;
320 /*
321 * Reserve enough space for bootcode and align first allocatable
322 * offset to PALIGN_SIZE.
323 * XXX: Currently DragonFlyBSD has 32KB bootcode, but the size could
324 * be bigger, because it is possible change it (it is equal pbase-bbase)
325 * in the bsdlabel64(8).
326 */
327 pbase = ressize + ((BOOTSIZE + blkmask) & ~blkmask);
328 pbase = (pbase + PALIGN_MASK) & ~PALIGN_MASK;
329 /*
330 * Take physical offset into account and make first allocatable
331 * offset 32KB aligned to the start of the physical disk.
332 * XXX: Actually there are no such restrictions, this is how
333 * DragonFlyBSD behaves.
334 */
335 pbase += DALIGN_SIZE - pp->stripeoffset % DALIGN_SIZE;
336
337 table = (struct g_part_bsd64_table *)basetable;
338 table->d_align = blksize;
339 table->d_bbase = ressize / pp->sectorsize;
340 table->d_abase = ((pp->mediasize - ressize) &
341 ~blkmask) / pp->sectorsize;
342 kern_uuidgen(&table->d_stor_uuid, 1);
343 basetable->gpt_first = pbase / pp->sectorsize;
344 basetable->gpt_last = table->d_abase - 1; /* XXX */
345 /*
346 * Create 'c' partition and make it internal, so user will not be
347 * able use it.
348 */
349 baseentry = g_part_new_entry(basetable, RAW_PART + 1, 0, 0);
350 baseentry->gpe_internal = 1;
351 return (0);
352 }
353
354 static int
g_part_bsd64_destroy(struct g_part_table * basetable,struct g_part_parms * gpp)355 g_part_bsd64_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
356 {
357 struct g_provider *pp;
358
359 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
360 if (pp->sectorsize > offsetof(struct disklabel64, d_magic))
361 basetable->gpt_smhead |= 1;
362 else
363 basetable->gpt_smhead |= 3;
364 return (0);
365 }
366
367 static void
g_part_bsd64_dumpconf(struct g_part_table * basetable,struct g_part_entry * baseentry,struct sbuf * sb,const char * indent)368 g_part_bsd64_dumpconf(struct g_part_table *basetable,
369 struct g_part_entry *baseentry, struct sbuf *sb, const char *indent)
370 {
371 struct g_part_bsd64_table *table;
372 struct g_part_bsd64_entry *entry;
373 char buf[sizeof(table->d_packname)];
374
375 entry = (struct g_part_bsd64_entry *)baseentry;
376 if (indent == NULL) {
377 /* conftxt: libdisk compatibility */
378 sbuf_printf(sb, " xs BSD64 xt %u", entry->fstype);
379 } else if (entry != NULL) {
380 /* confxml: partition entry information */
381 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
382 entry->fstype);
383 if (!EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) {
384 sbuf_printf(sb, "%s<type_uuid>", indent);
385 sbuf_printf_uuid(sb, &entry->type_uuid);
386 sbuf_cat(sb, "</type_uuid>\n");
387 }
388 sbuf_printf(sb, "%s<stor_uuid>", indent);
389 sbuf_printf_uuid(sb, &entry->stor_uuid);
390 sbuf_cat(sb, "</stor_uuid>\n");
391 } else {
392 /* confxml: scheme information */
393 table = (struct g_part_bsd64_table *)basetable;
394 sbuf_printf(sb, "%s<bootbase>%ju</bootbase>\n", indent,
395 (uintmax_t)table->d_bbase);
396 if (table->d_abase)
397 sbuf_printf(sb, "%s<backupbase>%ju</backupbase>\n",
398 indent, (uintmax_t)table->d_abase);
399 sbuf_printf(sb, "%s<stor_uuid>", indent);
400 sbuf_printf_uuid(sb, &table->d_stor_uuid);
401 sbuf_cat(sb, "</stor_uuid>\n");
402 sbuf_printf(sb, "%s<label>", indent);
403 strncpy(buf, table->d_packname, sizeof(buf) - 1);
404 buf[sizeof(buf) - 1] = '\0';
405 g_conf_cat_escaped(sb, buf);
406 sbuf_cat(sb, "</label>\n");
407 }
408 }
409
410 static int
g_part_bsd64_dumpto(struct g_part_table * table,struct g_part_entry * baseentry)411 g_part_bsd64_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
412 {
413 struct g_part_bsd64_entry *entry;
414
415 /* Allow dumping to a swap partition. */
416 entry = (struct g_part_bsd64_entry *)baseentry;
417 if (entry->fstype == FS_SWAP ||
418 EQUUID(&entry->type_uuid, &bsd64_uuid_dfbsd_swap) ||
419 EQUUID(&entry->type_uuid, &bsd64_uuid_freebsd_swap))
420 return (1);
421 return (0);
422 }
423
424 static int
g_part_bsd64_modify(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)425 g_part_bsd64_modify(struct g_part_table *basetable,
426 struct g_part_entry *baseentry, struct g_part_parms *gpp)
427 {
428 struct g_part_bsd64_entry *entry;
429
430 if (gpp->gpp_parms & G_PART_PARM_LABEL)
431 return (EINVAL);
432
433 entry = (struct g_part_bsd64_entry *)baseentry;
434 if (gpp->gpp_parms & G_PART_PARM_TYPE)
435 return (bsd64_parse_type(gpp->gpp_type, entry));
436 return (0);
437 }
438
439 static int
g_part_bsd64_resize(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)440 g_part_bsd64_resize(struct g_part_table *basetable,
441 struct g_part_entry *baseentry, struct g_part_parms *gpp)
442 {
443 struct g_part_bsd64_table *table;
444 struct g_provider *pp;
445
446 if (baseentry == NULL) {
447 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
448 table = (struct g_part_bsd64_table *)basetable;
449 table->d_abase =
450 rounddown2(pp->mediasize - table->d_bbase * pp->sectorsize,
451 table->d_align) / pp->sectorsize;
452 basetable->gpt_last = table->d_abase - 1;
453 return (0);
454 }
455 baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
456 return (0);
457 }
458
459 static const char *
g_part_bsd64_name(struct g_part_table * table,struct g_part_entry * baseentry,char * buf,size_t bufsz)460 g_part_bsd64_name(struct g_part_table *table, struct g_part_entry *baseentry,
461 char *buf, size_t bufsz)
462 {
463
464 snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
465 return (buf);
466 }
467
468 static int
g_part_bsd64_probe(struct g_part_table * table,struct g_consumer * cp)469 g_part_bsd64_probe(struct g_part_table *table, struct g_consumer *cp)
470 {
471 struct g_provider *pp;
472 uint32_t v;
473 int error;
474 u_char *buf;
475
476 pp = cp->provider;
477 if (pp->mediasize < 2 * PALIGN_SIZE)
478 return (ENOSPC);
479 v = rounddown2(pp->sectorsize + offsetof(struct disklabel64, d_magic),
480 pp->sectorsize);
481 buf = g_read_data(cp, 0, v, &error);
482 if (buf == NULL)
483 return (error);
484 v = le32dec(buf + offsetof(struct disklabel64, d_magic));
485 g_free(buf);
486 return (v == DISKMAGIC64 ? G_PART_PROBE_PRI_HIGH: ENXIO);
487 }
488
489 static int
g_part_bsd64_read(struct g_part_table * basetable,struct g_consumer * cp)490 g_part_bsd64_read(struct g_part_table *basetable, struct g_consumer *cp)
491 {
492 struct g_part_bsd64_table *table;
493 struct g_part_bsd64_entry *entry;
494 struct g_part_entry *baseentry;
495 struct g_provider *pp;
496 struct disklabel64 *dlp;
497 uint64_t v64, sz;
498 uint32_t v32;
499 int error, index;
500 u_char *buf;
501
502 pp = cp->provider;
503 table = (struct g_part_bsd64_table *)basetable;
504 v32 = roundup2(sizeof(struct disklabel64), pp->sectorsize);
505 buf = g_read_data(cp, 0, v32, &error);
506 if (buf == NULL)
507 return (error);
508
509 dlp = (struct disklabel64 *)buf;
510 basetable->gpt_entries = le32toh(dlp->d_npartitions);
511 if (basetable->gpt_entries > MAXPARTITIONS64 ||
512 basetable->gpt_entries < 1)
513 goto invalid_label;
514 v32 = le32toh(dlp->d_crc);
515 dlp->d_crc = 0;
516 if (crc32(&dlp->d_magic, offsetof(struct disklabel64,
517 d_partitions[basetable->gpt_entries]) -
518 offsetof(struct disklabel64, d_magic)) != v32)
519 goto invalid_label;
520 table->d_align = le32toh(dlp->d_align);
521 if (table->d_align == 0 || (table->d_align & (pp->sectorsize - 1)))
522 goto invalid_label;
523 if (le64toh(dlp->d_total_size) > pp->mediasize)
524 goto invalid_label;
525 v64 = le64toh(dlp->d_pbase);
526 if (v64 % pp->sectorsize)
527 goto invalid_label;
528 basetable->gpt_first = v64 / pp->sectorsize;
529 v64 = le64toh(dlp->d_pstop);
530 if (v64 % pp->sectorsize)
531 goto invalid_label;
532 basetable->gpt_last = v64 / pp->sectorsize;
533 basetable->gpt_isleaf = 1;
534 v64 = le64toh(dlp->d_bbase);
535 if (v64 % pp->sectorsize)
536 goto invalid_label;
537 table->d_bbase = v64 / pp->sectorsize;
538 v64 = le64toh(dlp->d_abase);
539 if (v64 % pp->sectorsize)
540 goto invalid_label;
541 table->d_abase = v64 / pp->sectorsize;
542 le_uuid_dec(&dlp->d_stor_uuid, &table->d_stor_uuid);
543 for (index = basetable->gpt_entries - 1; index >= 0; index--) {
544 if (index == RAW_PART) {
545 /* Skip 'c' partition. */
546 baseentry = g_part_new_entry(basetable,
547 index + 1, 0, 0);
548 baseentry->gpe_internal = 1;
549 continue;
550 }
551 v64 = le64toh(dlp->d_partitions[index].p_boffset);
552 sz = le64toh(dlp->d_partitions[index].p_bsize);
553 if (sz == 0 && v64 == 0)
554 continue;
555 if (sz == 0 || (v64 % pp->sectorsize) || (sz % pp->sectorsize))
556 goto invalid_label;
557 baseentry = g_part_new_entry(basetable, index + 1,
558 v64 / pp->sectorsize, (v64 + sz) / pp->sectorsize - 1);
559 entry = (struct g_part_bsd64_entry *)baseentry;
560 le_uuid_dec(&dlp->d_partitions[index].p_type_uuid,
561 &entry->type_uuid);
562 le_uuid_dec(&dlp->d_partitions[index].p_stor_uuid,
563 &entry->stor_uuid);
564 entry->fstype = dlp->d_partitions[index].p_fstype;
565 }
566 bcopy(dlp->d_reserved0, table->d_reserved0,
567 sizeof(table->d_reserved0));
568 bcopy(dlp->d_packname, table->d_packname, sizeof(table->d_packname));
569 bcopy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved));
570 g_free(buf);
571 return (0);
572
573 invalid_label:
574 g_free(buf);
575 return (EINVAL);
576 }
577
578 static const char *
g_part_bsd64_type(struct g_part_table * basetable,struct g_part_entry * baseentry,char * buf,size_t bufsz)579 g_part_bsd64_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
580 char *buf, size_t bufsz)
581 {
582 struct g_part_bsd64_entry *entry;
583 struct bsd64_uuid_alias *uap;
584
585 entry = (struct g_part_bsd64_entry *)baseentry;
586 if (entry->fstype != FS_OTHER) {
587 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++)
588 if (uap->fstype == entry->fstype)
589 return (g_part_alias_name(uap->alias));
590 } else {
591 for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++)
592 if (EQUUID(uap->uuid, &entry->type_uuid))
593 return (g_part_alias_name(uap->alias));
594 for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++)
595 if (EQUUID(uap->uuid, &entry->type_uuid))
596 return (g_part_alias_name(uap->alias));
597 }
598 if (EQUUID(&bsd64_uuid_unused, &entry->type_uuid))
599 snprintf(buf, bufsz, "!%d", entry->fstype);
600 else {
601 buf[0] = '!';
602 snprintf_uuid(buf + 1, bufsz - 1, &entry->type_uuid);
603 }
604 return (buf);
605 }
606
607 static int
g_part_bsd64_write(struct g_part_table * basetable,struct g_consumer * cp)608 g_part_bsd64_write(struct g_part_table *basetable, struct g_consumer *cp)
609 {
610 struct g_provider *pp;
611 struct g_part_entry *baseentry;
612 struct g_part_bsd64_entry *entry;
613 struct g_part_bsd64_table *table;
614 struct disklabel64 *dlp;
615 uint32_t v, sz;
616 int error, index;
617
618 pp = cp->provider;
619 table = (struct g_part_bsd64_table *)basetable;
620 sz = roundup2(sizeof(struct disklabel64), pp->sectorsize);
621 dlp = g_malloc(sz, M_WAITOK | M_ZERO);
622
623 memcpy(dlp->d_reserved0, table->d_reserved0,
624 sizeof(table->d_reserved0));
625 memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname));
626 memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved));
627 le32enc(&dlp->d_magic, DISKMAGIC64);
628 le32enc(&dlp->d_align, table->d_align);
629 le32enc(&dlp->d_npartitions, basetable->gpt_entries);
630 le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid);
631 le64enc(&dlp->d_total_size, pp->mediasize);
632 le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize);
633 le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize);
634 le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize);
635 le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize);
636
637 LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
638 if (baseentry->gpe_deleted)
639 continue;
640 index = baseentry->gpe_index - 1;
641 entry = (struct g_part_bsd64_entry *)baseentry;
642 if (index == RAW_PART)
643 continue;
644 le64enc(&dlp->d_partitions[index].p_boffset,
645 baseentry->gpe_start * pp->sectorsize);
646 le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize *
647 (baseentry->gpe_end - baseentry->gpe_start + 1));
648 dlp->d_partitions[index].p_fstype = entry->fstype;
649 le_uuid_enc(&dlp->d_partitions[index].p_type_uuid,
650 &entry->type_uuid);
651 le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid,
652 &entry->stor_uuid);
653 }
654 /* Calculate checksum. */
655 v = offsetof(struct disklabel64,
656 d_partitions[basetable->gpt_entries]) -
657 offsetof(struct disklabel64, d_magic);
658 le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v));
659 error = g_write_data(cp, 0, dlp, sz);
660 g_free(dlp);
661 return (error);
662 }
663