g_part_bsd.c revision 174326
1174326Smarcel/*-
2174326Smarcel * Copyright (c) 2007 Marcel Moolenaar
3174326Smarcel * All rights reserved.
4174326Smarcel *
5174326Smarcel * Redistribution and use in source and binary forms, with or without
6174326Smarcel * modification, are permitted provided that the following conditions
7174326Smarcel * are met:
8174326Smarcel *
9174326Smarcel * 1. Redistributions of source code must retain the above copyright
10174326Smarcel *    notice, this list of conditions and the following disclaimer.
11174326Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12174326Smarcel *    notice, this list of conditions and the following disclaimer in the
13174326Smarcel *    documentation and/or other materials provided with the distribution.
14174326Smarcel *
15174326Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16174326Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17174326Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18174326Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19174326Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20174326Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21174326Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22174326Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23174326Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24174326Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25174326Smarcel */
26174326Smarcel
27174326Smarcel#include <sys/cdefs.h>
28174326Smarcel__FBSDID("$FreeBSD: head/sys/geom/part/g_part_bsd.c 174326 2007-12-06 02:32:42Z marcel $");
29174326Smarcel
30174326Smarcel#include <sys/param.h>
31174326Smarcel#include <sys/bio.h>
32174326Smarcel#include <sys/disklabel.h>
33174326Smarcel#include <sys/endian.h>
34174326Smarcel#include <sys/kernel.h>
35174326Smarcel#include <sys/kobj.h>
36174326Smarcel#include <sys/limits.h>
37174326Smarcel#include <sys/lock.h>
38174326Smarcel#include <sys/malloc.h>
39174326Smarcel#include <sys/mutex.h>
40174326Smarcel#include <sys/queue.h>
41174326Smarcel#include <sys/sbuf.h>
42174326Smarcel#include <sys/systm.h>
43174326Smarcel#include <geom/geom.h>
44174326Smarcel#include <geom/part/g_part.h>
45174326Smarcel
46174326Smarcel#include "g_part_if.h"
47174326Smarcel
48174326Smarcelstruct g_part_bsd_table {
49174326Smarcel	struct g_part_table	base;
50174326Smarcel	u_char			*label;
51174326Smarcel};
52174326Smarcel
53174326Smarcelstruct g_part_bsd_entry {
54174326Smarcel	struct g_part_entry	base;
55174326Smarcel	struct partition	part;
56174326Smarcel};
57174326Smarcel
58174326Smarcelstatic int g_part_bsd_add(struct g_part_table *, struct g_part_entry *,
59174326Smarcel    struct g_part_parms *);
60174326Smarcelstatic int g_part_bsd_create(struct g_part_table *, struct g_part_parms *);
61174326Smarcelstatic int g_part_bsd_destroy(struct g_part_table *, struct g_part_parms *);
62174326Smarcelstatic int g_part_bsd_dumpto(struct g_part_table *, struct g_part_entry *);
63174326Smarcelstatic int g_part_bsd_modify(struct g_part_table *, struct g_part_entry *,
64174326Smarcel    struct g_part_parms *);
65174326Smarcelstatic char *g_part_bsd_name(struct g_part_table *, struct g_part_entry *,
66174326Smarcel    char *, size_t);
67174326Smarcelstatic int g_part_bsd_probe(struct g_part_table *, struct g_consumer *);
68174326Smarcelstatic int g_part_bsd_read(struct g_part_table *, struct g_consumer *);
69174326Smarcelstatic const char *g_part_bsd_type(struct g_part_table *, struct g_part_entry *,
70174326Smarcel    char *, size_t);
71174326Smarcelstatic int g_part_bsd_write(struct g_part_table *, struct g_consumer *);
72174326Smarcel
73174326Smarcelstatic kobj_method_t g_part_bsd_methods[] = {
74174326Smarcel	KOBJMETHOD(g_part_add,		g_part_bsd_add),
75174326Smarcel	KOBJMETHOD(g_part_create,	g_part_bsd_create),
76174326Smarcel	KOBJMETHOD(g_part_destroy,	g_part_bsd_destroy),
77174326Smarcel	KOBJMETHOD(g_part_dumpto,	g_part_bsd_dumpto),
78174326Smarcel	KOBJMETHOD(g_part_modify,	g_part_bsd_modify),
79174326Smarcel	KOBJMETHOD(g_part_name,		g_part_bsd_name),
80174326Smarcel	KOBJMETHOD(g_part_probe,	g_part_bsd_probe),
81174326Smarcel	KOBJMETHOD(g_part_read,		g_part_bsd_read),
82174326Smarcel	KOBJMETHOD(g_part_type,		g_part_bsd_type),
83174326Smarcel	KOBJMETHOD(g_part_write,	g_part_bsd_write),
84174326Smarcel	{ 0, 0 }
85174326Smarcel};
86174326Smarcel
87174326Smarcelstatic struct g_part_scheme g_part_bsd_scheme = {
88174326Smarcel	"BSD",
89174326Smarcel	g_part_bsd_methods,
90174326Smarcel	sizeof(struct g_part_bsd_table),
91174326Smarcel	.gps_entrysz = sizeof(struct g_part_bsd_entry),
92174326Smarcel	.gps_minent = 8,
93174326Smarcel	.gps_maxent = 20,
94174326Smarcel};
95174326SmarcelG_PART_SCHEME_DECLARE(g_part_bsd_scheme);
96174326Smarcel
97174326Smarcelstatic int
98174326Smarcelbsd_parse_type(const char *type, uint8_t *fstype)
99174326Smarcel{
100174326Smarcel	const char *alias;
101174326Smarcel	char *endp;
102174326Smarcel	long lt;
103174326Smarcel
104174326Smarcel	if (type[0] == '!') {
105174326Smarcel		lt = strtol(type + 1, &endp, 0);
106174326Smarcel		if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256)
107174326Smarcel			return (EINVAL);
108174326Smarcel		*fstype = (u_int)lt;
109174326Smarcel		return (0);
110174326Smarcel	}
111174326Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
112174326Smarcel	if (!strcasecmp(type, alias)) {
113174326Smarcel		*fstype = FS_SWAP;
114174326Smarcel		return (0);
115174326Smarcel	}
116174326Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
117174326Smarcel	if (!strcasecmp(type, alias)) {
118174326Smarcel		*fstype = FS_BSDFFS;
119174326Smarcel		return (0);
120174326Smarcel	}
121174326Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
122174326Smarcel	if (!strcasecmp(type, alias)) {
123174326Smarcel		*fstype = FS_VINUM;
124174326Smarcel		return (0);
125174326Smarcel	}
126174326Smarcel	return (EINVAL);
127174326Smarcel}
128174326Smarcel
129174326Smarcelstatic int
130174326Smarcelg_part_bsd_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
131174326Smarcel    struct g_part_parms *gpp)
132174326Smarcel{
133174326Smarcel	struct g_part_bsd_entry *entry;
134174326Smarcel	struct g_part_bsd_table *table;
135174326Smarcel	uint32_t start, size, sectors;
136174326Smarcel
137174326Smarcel	if (gpp->gpp_parms & G_PART_PARM_LABEL)
138174326Smarcel		return (EINVAL);
139174326Smarcel
140174326Smarcel	sectors = basetable->gpt_sectors;
141174326Smarcel
142174326Smarcel	entry = (struct g_part_bsd_entry *)baseentry;
143174326Smarcel	table = (struct g_part_bsd_table *)basetable;
144174326Smarcel
145174326Smarcel	start = gpp->gpp_start;
146174326Smarcel	size = gpp->gpp_size;
147174326Smarcel	if (size < sectors)
148174326Smarcel		return (EINVAL);
149174326Smarcel	if (start % sectors) {
150174326Smarcel		size = size - sectors + (start % sectors);
151174326Smarcel		start = start - (start % sectors) + sectors;
152174326Smarcel	}
153174326Smarcel	if (size % sectors)
154174326Smarcel		size = size - (size % sectors);
155174326Smarcel	if (size < sectors)
156174326Smarcel		return (EINVAL);
157174326Smarcel
158174326Smarcel	KASSERT(baseentry->gpe_start <= start, (__func__));
159174326Smarcel	KASSERT(baseentry->gpe_end >= start + size - 1, (__func__));
160174326Smarcel	baseentry->gpe_start = start;
161174326Smarcel	baseentry->gpe_end = start + size - 1;
162174326Smarcel	entry->part.p_size = size;
163174326Smarcel	entry->part.p_offset = start + basetable->gpt_offset;
164174326Smarcel	entry->part.p_fsize = 0;
165174326Smarcel	entry->part.p_frag = 0;
166174326Smarcel	entry->part.p_cpg = 0;
167174326Smarcel	return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype));
168174326Smarcel}
169174326Smarcel
170174326Smarcelstatic int
171174326Smarcelg_part_bsd_create(struct g_part_table *basetable, struct g_part_parms *gpp)
172174326Smarcel{
173174326Smarcel	struct g_consumer *cp;
174174326Smarcel	struct g_provider *pp;
175174326Smarcel	struct g_part_entry *baseentry;
176174326Smarcel	struct g_part_bsd_entry *entry;
177174326Smarcel	struct g_part_bsd_table *table;
178174326Smarcel	u_char *ptr;
179174326Smarcel	uint64_t msize;
180174326Smarcel	uint32_t ncyls, secpercyl;
181174326Smarcel
182174326Smarcel	pp = gpp->gpp_provider;
183174326Smarcel	cp = LIST_FIRST(&pp->consumers);
184174326Smarcel
185174326Smarcel	if (pp->sectorsize < sizeof(struct disklabel))
186174326Smarcel		return (ENOSPC);
187174326Smarcel
188174326Smarcel	msize = pp->mediasize / pp->sectorsize;
189174326Smarcel	secpercyl = basetable->gpt_sectors * basetable->gpt_heads;
190174326Smarcel	ncyls = msize / secpercyl;
191174326Smarcel
192174326Smarcel	table = (struct g_part_bsd_table *)basetable;
193174326Smarcel	ptr = table->label = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
194174326Smarcel
195174326Smarcel	le32enc(ptr + 0, DISKMAGIC);			/* d_magic */
196174326Smarcel	le32enc(ptr + 40, pp->sectorsize);		/* d_secsize */
197174326Smarcel	le32enc(ptr + 44, basetable->gpt_sectors);	/* d_nsectors */
198174326Smarcel	le32enc(ptr + 48, basetable->gpt_heads);	/* d_ntracks */
199174326Smarcel	le32enc(ptr + 52, ncyls);			/* d_ncylinders */
200174326Smarcel	le32enc(ptr + 56, secpercyl);			/* d_secpercyl */
201174326Smarcel	le32enc(ptr + 60, ncyls * secpercyl);		/* d_secperunit */
202174326Smarcel	le16enc(ptr + 72, 3600);			/* d_rpm */
203174326Smarcel	le32enc(ptr + 132, DISKMAGIC);			/* d_magic2 */
204174326Smarcel	le16enc(ptr + 138, basetable->gpt_entries);	/* d_npartitions */
205174326Smarcel	le32enc(ptr + 140, BBSIZE);			/* d_bbsize */
206174326Smarcel
207174326Smarcel	basetable->gpt_first = 0;
208174326Smarcel	basetable->gpt_last = ncyls * secpercyl - 1;
209174326Smarcel	basetable->gpt_isleaf = 1;
210174326Smarcel
211174326Smarcel	baseentry = g_part_new_entry(basetable, RAW_PART + 1,
212174326Smarcel	    basetable->gpt_first, basetable->gpt_last);
213174326Smarcel	baseentry->gpe_internal = 1;
214174326Smarcel	entry = (struct g_part_bsd_entry *)baseentry;
215174326Smarcel	entry->part.p_size = basetable->gpt_last + 1;
216174326Smarcel	entry->part.p_offset = basetable->gpt_offset;
217174326Smarcel
218174326Smarcel	return (0);
219174326Smarcel}
220174326Smarcel
221174326Smarcelstatic int
222174326Smarcelg_part_bsd_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
223174326Smarcel{
224174326Smarcel
225174326Smarcel	/* Wipe the second sector to clear the partitioning. */
226174326Smarcel	basetable->gpt_smhead |= 2;
227174326Smarcel	return (0);
228174326Smarcel}
229174326Smarcel
230174326Smarcelstatic int
231174326Smarcelg_part_bsd_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
232174326Smarcel{
233174326Smarcel	struct g_part_bsd_entry *entry;
234174326Smarcel
235174326Smarcel	/* Allow dumping to a swap partition only. */
236174326Smarcel	entry = (struct g_part_bsd_entry *)baseentry;
237174326Smarcel	return ((entry->part.p_fstype == FS_SWAP) ? 1 : 0);
238174326Smarcel}
239174326Smarcel
240174326Smarcelstatic int
241174326Smarcelg_part_bsd_modify(struct g_part_table *basetable,
242174326Smarcel    struct g_part_entry *baseentry, struct g_part_parms *gpp)
243174326Smarcel{
244174326Smarcel	struct g_part_bsd_entry *entry;
245174326Smarcel
246174326Smarcel	if (gpp->gpp_parms & G_PART_PARM_LABEL)
247174326Smarcel		return (EINVAL);
248174326Smarcel
249174326Smarcel	entry = (struct g_part_bsd_entry *)baseentry;
250174326Smarcel	if (gpp->gpp_parms & G_PART_PARM_TYPE)
251174326Smarcel		return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype));
252174326Smarcel	return (0);
253174326Smarcel}
254174326Smarcel
255174326Smarcelstatic char *
256174326Smarcelg_part_bsd_name(struct g_part_table *table, struct g_part_entry *baseentry,
257174326Smarcel    char *buf, size_t bufsz)
258174326Smarcel{
259174326Smarcel
260174326Smarcel	snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
261174326Smarcel	return (buf);
262174326Smarcel}
263174326Smarcel
264174326Smarcelstatic int
265174326Smarcelg_part_bsd_probe(struct g_part_table *table, struct g_consumer *cp)
266174326Smarcel{
267174326Smarcel	struct g_provider *pp;
268174326Smarcel	u_char *buf;
269174326Smarcel	uint32_t magic1, magic2;
270174326Smarcel	int error;
271174326Smarcel
272174326Smarcel	pp = cp->provider;
273174326Smarcel
274174326Smarcel	/* Sanity-check the provider. */
275174326Smarcel	if (pp->sectorsize < sizeof(struct disklabel) ||
276174326Smarcel	    pp->mediasize < BBSIZE)
277174326Smarcel		return (ENOSPC);
278174326Smarcel
279174326Smarcel	/* Check that there's a disklabel. */
280174326Smarcel	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
281174326Smarcel	if (buf == NULL)
282174326Smarcel		return (error);
283174326Smarcel	magic1 = le32dec(buf + 0);
284174326Smarcel	magic2 = le32dec(buf + 132);
285174326Smarcel	g_free(buf);
286174326Smarcel	return ((magic1 == DISKMAGIC && magic2 == DISKMAGIC)
287174326Smarcel	    ? G_PART_PROBE_PRI_NORM : ENXIO);
288174326Smarcel}
289174326Smarcel
290174326Smarcelstatic int
291174326Smarcelg_part_bsd_read(struct g_part_table *basetable, struct g_consumer *cp)
292174326Smarcel{
293174326Smarcel	struct g_provider *pp;
294174326Smarcel	struct g_part_bsd_table *table;
295174326Smarcel	struct g_part_entry *baseentry;
296174326Smarcel	struct g_part_bsd_entry *entry;
297174326Smarcel	struct partition part;
298174326Smarcel	u_char *buf, *p;
299174326Smarcel	off_t chs, msize;
300174326Smarcel	u_int sectors, heads;
301174326Smarcel	int error, index;
302174326Smarcel
303174326Smarcel	pp = cp->provider;
304174326Smarcel	table = (struct g_part_bsd_table *)basetable;
305174326Smarcel	msize = pp->mediasize / pp->sectorsize;
306174326Smarcel
307174326Smarcel	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
308174326Smarcel	if (buf == NULL)
309174326Smarcel		return (error);
310174326Smarcel
311174326Smarcel	table->label = buf;
312174326Smarcel
313174326Smarcel	if (le32dec(buf + 40) != pp->sectorsize)
314174326Smarcel		goto invalid_label;
315174326Smarcel	sectors = le32dec(buf + 44);
316174326Smarcel	if (sectors < 1 || sectors > 63)
317174326Smarcel		goto invalid_label;
318174326Smarcel	if (sectors != basetable->gpt_sectors) {
319174326Smarcel		if (basetable->gpt_fixgeom)
320174326Smarcel			goto invalid_label;
321174326Smarcel		g_part_geometry_heads(msize, sectors, &chs, &heads);
322174326Smarcel		if (chs == 0)
323174326Smarcel			goto invalid_label;
324174326Smarcel		basetable->gpt_sectors = sectors;
325174326Smarcel		basetable->gpt_heads = heads;
326174326Smarcel	}
327174326Smarcel	heads = le32dec(buf + 48);
328174326Smarcel	if (heads < 1 || heads > 255)
329174326Smarcel		goto invalid_label;
330174326Smarcel	if (heads != basetable->gpt_heads) {
331174326Smarcel		if (basetable->gpt_fixgeom)
332174326Smarcel			goto invalid_label;
333174326Smarcel		basetable->gpt_heads = heads;
334174326Smarcel	}
335174326Smarcel	chs = le32dec(buf + 52) * heads * sectors;
336174326Smarcel	if (chs < 1 || chs > msize)
337174326Smarcel		goto invalid_label;
338174326Smarcel
339174326Smarcel	basetable->gpt_first = 0;
340174326Smarcel	basetable->gpt_last = chs - 1;
341174326Smarcel	basetable->gpt_isleaf = 1;
342174326Smarcel
343174326Smarcel	basetable->gpt_entries = le16dec(buf + 138);
344174326Smarcel	if (basetable->gpt_entries < g_part_bsd_scheme.gps_minent ||
345174326Smarcel	    basetable->gpt_entries > g_part_bsd_scheme.gps_maxent)
346174326Smarcel		goto invalid_label;
347174326Smarcel
348174326Smarcel	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
349174326Smarcel		p = buf + 148 + index * 16;
350174326Smarcel		part.p_size = le32dec(p + 0);
351174326Smarcel		part.p_offset = le32dec(p + 4);
352174326Smarcel		part.p_fsize = le32dec(p + 8);
353174326Smarcel		part.p_fstype = p[12];
354174326Smarcel		part.p_frag = p[13];
355174326Smarcel		part.p_cpg = le16dec(p + 14);
356174326Smarcel		if (part.p_size == 0)
357174326Smarcel			continue;
358174326Smarcel		if (part.p_fstype == FS_UNUSED && index != RAW_PART)
359174326Smarcel			continue;
360174326Smarcel		if (part.p_offset < basetable->gpt_offset)
361174326Smarcel			continue;
362174326Smarcel		baseentry = g_part_new_entry(basetable, index + 1,
363174326Smarcel		    part.p_offset - basetable->gpt_offset,
364174326Smarcel		    part.p_offset - basetable->gpt_offset + part.p_size - 1);
365174326Smarcel		entry = (struct g_part_bsd_entry *)baseentry;
366174326Smarcel		entry->part = part;
367174326Smarcel		if (part.p_fstype == FS_UNUSED)
368174326Smarcel			baseentry->gpe_internal = 1;
369174326Smarcel	}
370174326Smarcel
371174326Smarcel	return (0);
372174326Smarcel
373174326Smarcel invalid_label:
374174326Smarcel	printf("GEOM: %s: invalid disklabel.\n", pp->name);
375174326Smarcel	g_free(table->label);
376174326Smarcel	return (EINVAL);
377174326Smarcel}
378174326Smarcel
379174326Smarcelstatic const char *
380174326Smarcelg_part_bsd_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
381174326Smarcel    char *buf, size_t bufsz)
382174326Smarcel{
383174326Smarcel	struct g_part_bsd_entry *entry;
384174326Smarcel	int type;
385174326Smarcel
386174326Smarcel	entry = (struct g_part_bsd_entry *)baseentry;
387174326Smarcel	type = entry->part.p_fstype;
388174326Smarcel	if (type == FS_SWAP)
389174326Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
390174326Smarcel	if (type == FS_BSDFFS)
391174326Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
392174326Smarcel	if (type == FS_VINUM)
393174326Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
394174326Smarcel	snprintf(buf, bufsz, "!%d", type);
395174326Smarcel	return (buf);
396174326Smarcel}
397174326Smarcel
398174326Smarcelstatic int
399174326Smarcelg_part_bsd_write(struct g_part_table *basetable, struct g_consumer *cp)
400174326Smarcel{
401174326Smarcel	struct g_provider *pp;
402174326Smarcel	struct g_part_entry *baseentry;
403174326Smarcel	struct g_part_bsd_entry *entry;
404174326Smarcel	struct g_part_bsd_table *table;
405174326Smarcel	uint16_t sum;
406174326Smarcel	u_char *p, *pe;
407174326Smarcel	int error, index;
408174326Smarcel
409174326Smarcel	pp = cp->provider;
410174326Smarcel	table = (struct g_part_bsd_table *)basetable;
411174326Smarcel	baseentry = LIST_FIRST(&basetable->gpt_entry);
412174326Smarcel	for (index = 1; index <= basetable->gpt_entries; index++) {
413174326Smarcel		p = table->label + 148 + (index - 1) * 16;
414174326Smarcel		entry = (baseentry != NULL && index == baseentry->gpe_index)
415174326Smarcel		    ? (struct g_part_bsd_entry *)baseentry : NULL;
416174326Smarcel		if (entry != NULL && !baseentry->gpe_deleted) {
417174326Smarcel			le32enc(p + 0, entry->part.p_size);
418174326Smarcel			le32enc(p + 4, entry->part.p_offset);
419174326Smarcel			le32enc(p + 8, entry->part.p_fsize);
420174326Smarcel			p[12] = entry->part.p_fstype;
421174326Smarcel			p[13] = entry->part.p_frag;
422174326Smarcel			le16enc(p + 14, entry->part.p_cpg);
423174326Smarcel		} else
424174326Smarcel			bzero(p, 16);
425174326Smarcel
426174326Smarcel		if (entry != NULL)
427174326Smarcel			baseentry = LIST_NEXT(baseentry, gpe_entry);
428174326Smarcel	}
429174326Smarcel
430174326Smarcel	/* Calculate checksum. */
431174326Smarcel	le16enc(table->label + 136, 0);
432174326Smarcel	pe = table->label + 148 + basetable->gpt_entries * 16;
433174326Smarcel	sum = 0;
434174326Smarcel	for (p = table->label; p < pe; p += 2)
435174326Smarcel		sum ^= le16dec(p);
436174326Smarcel	le16enc(table->label + 136, sum);
437174326Smarcel
438174326Smarcel	error = g_write_data(cp, pp->sectorsize, table->label, pp->sectorsize);
439174326Smarcel	return (error);
440174326Smarcel}
441