192108Sphk/*-
292108Sphk * Copyright (c) 2002 Poul-Henning Kamp
392108Sphk * Copyright (c) 2002 Networks Associates Technology, Inc.
492108Sphk * All rights reserved.
592108Sphk *
692108Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp
792108Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc.
892108Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
992108Sphk * DARPA CHATS research program.
1092108Sphk *
1192108Sphk * Redistribution and use in source and binary forms, with or without
1292108Sphk * modification, are permitted provided that the following conditions
1392108Sphk * are met:
1492108Sphk * 1. Redistributions of source code must retain the above copyright
1592108Sphk *    notice, this list of conditions and the following disclaimer.
1692108Sphk * 2. Redistributions in binary form must reproduce the above copyright
1792108Sphk *    notice, this list of conditions and the following disclaimer in the
1892108Sphk *    documentation and/or other materials provided with the distribution.
1992108Sphk * 3. The names of the authors may not be used to endorse or promote
2092108Sphk *    products derived from this software without specific prior written
2192108Sphk *    permission.
2292108Sphk *
2392108Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2492108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2592108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2692108Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2792108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2892108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2992108Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3092108Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3192108Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3292108Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3392108Sphk * SUCH DAMAGE.
34139778Simp */
35139778Simp
36139778Simp/*
37104065Sphk * This is the method for dealing with BSD disklabels.  It has been
38104065Sphk * extensively (by my standards at least) commented, in the vain hope that
39108819Sphk * it will serve as the source in future copy&paste operations.
4092108Sphk */
4192108Sphk
42116196Sobrien#include <sys/cdefs.h>
43116196Sobrien__FBSDID("$FreeBSD: stable/10/sys/geom/geom_bsd.c 322860 2017-08-24 21:44:23Z mckusick $");
44116196Sobrien
4592108Sphk#include <sys/param.h>
46113011Sphk#include <sys/endian.h>
4792108Sphk#include <sys/systm.h>
48219029Snetchild#include <sys/sysctl.h>
4992108Sphk#include <sys/kernel.h>
50138732Sphk#include <sys/fcntl.h>
5192108Sphk#include <sys/conf.h>
5292108Sphk#include <sys/bio.h>
5392108Sphk#include <sys/malloc.h>
5492108Sphk#include <sys/lock.h>
5592108Sphk#include <sys/mutex.h>
56108819Sphk#include <sys/md5.h>
5792108Sphk#include <sys/errno.h>
5892108Sphk#include <sys/disklabel.h>
59174347Sjhb#include <sys/gpt.h>
60230643Sattilio#include <sys/proc.h>
61223921Sae#include <sys/sbuf.h>
62174347Sjhb#include <sys/uuid.h>
6392108Sphk#include <geom/geom.h>
6492108Sphk#include <geom/geom_slice.h>
6592108Sphk
66219029SnetchildFEATURE(geom_bsd, "GEOM BSD disklabels support");
67219029Snetchild
68105505Sphk#define	BSD_CLASS_NAME "BSD"
6992108Sphk
70106634Sphk#define ALPHA_LABEL_OFFSET	64
71152972Ssobomax#define HISTORIC_LABEL_OFFSET	512
72106634Sphk
73114556Sphk#define LABELSIZE (148 + 16 * MAXPARTITIONS)
74114556Sphk
75113713Sphkstatic void g_bsd_hotwrite(void *arg, int flag);
76104065Sphk/*
77104065Sphk * Our private data about one instance.  All the rest is handled by the
78105505Sphk * slice code and stored in its softc, so this is just the stuff
79104065Sphk * specific to BSD disklabels.
80104065Sphk */
8192108Sphkstruct g_bsd_softc {
8295323Sphk	off_t	labeloffset;
83106076Sphk	off_t	mbroffset;
84104065Sphk	off_t	rawoffset;
8592108Sphk	struct disklabel ondisk;
86114556Sphk	u_char	label[LABELSIZE];
87108819Sphk	u_char	labelsum[16];
8892108Sphk};
8992108Sphk
90104065Sphk/*
91104065Sphk * Modify our slicer to match proposed disklabel, if possible.
92114556Sphk * This is where we make sure we don't do something stupid.
93104065Sphk */
94104065Sphkstatic int
95114556Sphkg_bsd_modify(struct g_geom *gp, u_char *label)
96104065Sphk{
97104065Sphk	int i, error;
98104065Sphk	struct partition *ppp;
99104065Sphk	struct g_slicer *gsp;
100104065Sphk	struct g_consumer *cp;
101113713Sphk	struct g_bsd_softc *ms;
102107953Sphk	u_int secsize, u;
103115509Sphk	off_t rawoffset, o;
104114556Sphk	struct disklabel dl;
105114556Sphk	MD5_CTX md5sum;
106104065Sphk
107114556Sphk	g_topology_assert();
108114556Sphk	gsp = gp->softc;
109114556Sphk	ms = gsp->softc;
110114556Sphk
111114556Sphk	error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS);
112114556Sphk	if (error) {
113105505Sphk		return (error);
114114556Sphk	}
115104065Sphk
116105505Sphk	/* Get dimensions of our device. */
117104065Sphk	cp = LIST_FIRST(&gp->consumer);
118105551Sphk	secsize = cp->provider->sectorsize;
119104065Sphk
120105505Sphk	/* ... or a smaller sector size. */
121114556Sphk	if (dl.d_secsize < secsize) {
122104065Sphk		return (EINVAL);
123114556Sphk	}
124104065Sphk
125105505Sphk	/* ... or a non-multiple sector size. */
126114556Sphk	if (dl.d_secsize % secsize != 0) {
127104065Sphk		return (EINVAL);
128114556Sphk	}
129104065Sphk
130114556Sphk	/* Historical braindamage... */
131114556Sphk	rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize;
132114672Sphk
133114556Sphk	for (i = 0; i < dl.d_npartitions; i++) {
134114556Sphk		ppp = &dl.d_partitions[i];
135114556Sphk		if (ppp->p_size == 0)
136114556Sphk			continue;
137114556Sphk	        o = (off_t)ppp->p_offset * dl.d_secsize;
138104065Sphk
139114556Sphk		if (o < rawoffset)
140114556Sphk			rawoffset = 0;
141114556Sphk	}
142114705Sphk
143114785Sphk	if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset)
144185518Sivoras		printf("WARNING: %s expected rawoffset %jd, found %jd\n",
145185518Sivoras		    gp->name,
146114705Sphk		    (intmax_t)ms->mbroffset/dl.d_secsize,
147114785Sphk		    (intmax_t)rawoffset/dl.d_secsize);
148114556Sphk
149105505Sphk	/* Don't munge open partitions. */
150114556Sphk	for (i = 0; i < dl.d_npartitions; i++) {
151114556Sphk		ppp = &dl.d_partitions[i];
152104065Sphk
153114556Sphk	        o = (off_t)ppp->p_offset * dl.d_secsize;
154114556Sphk		if (o == 0)
155114556Sphk			o = rawoffset;
156104065Sphk		error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
157114556Sphk		    o - rawoffset,
158114556Sphk		    (off_t)ppp->p_size * dl.d_secsize,
159114556Sphk		     dl.d_secsize,
160104065Sphk		    "%s%c", gp->name, 'a' + i);
161114556Sphk		if (error)
162104065Sphk			return (error);
163104065Sphk	}
164104065Sphk
165104065Sphk	/* Look good, go for it... */
166107953Sphk	for (u = 0; u < gsp->nslice; u++) {
167114556Sphk		ppp = &dl.d_partitions[u];
168114556Sphk	        o = (off_t)ppp->p_offset * dl.d_secsize;
169114556Sphk		if (o == 0)
170114556Sphk			o = rawoffset;
171107953Sphk		g_slice_config(gp, u, G_SLICE_CONFIG_SET,
172114556Sphk		    o - rawoffset,
173114556Sphk		    (off_t)ppp->p_size * dl.d_secsize,
174114556Sphk		     dl.d_secsize,
175107953Sphk		    "%s%c", gp->name, 'a' + u);
176104065Sphk	}
177104065Sphk
178114556Sphk	/* Update our softc */
179114556Sphk	ms->ondisk = dl;
180114556Sphk	if (label != ms->label)
181114556Sphk		bcopy(label, ms->label, LABELSIZE);
182114556Sphk	ms->rawoffset = rawoffset;
18393097Sphk
184114556Sphk	/*
185114556Sphk	 * In order to avoid recursively attaching to the same
186114556Sphk	 * on-disk label (it's usually visible through the 'c'
187114556Sphk	 * partition) we calculate an MD5 and ask if other BSD's
188114556Sphk	 * below us love that label.  If they do, we don't.
189114556Sphk	 */
190114556Sphk	MD5Init(&md5sum);
191114556Sphk	MD5Update(&md5sum, ms->label, sizeof(ms->label));
192114556Sphk	MD5Final(ms->labelsum, &md5sum);
193114556Sphk
194114556Sphk	return (0);
19593097Sphk}
19693097Sphk
197104065Sphk/*
198104065Sphk * This is an internal helper function, called multiple times from the taste
199104065Sphk * function to try to locate a disklabel on the disk.  More civilized formats
200104065Sphk * will not need this, as there is only one possible place on disk to look
201104065Sphk * for the magic spot.
202104065Sphk */
203104065Sphk
20493097Sphkstatic int
205107526Sphkg_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset)
20693097Sphk{
20793097Sphk	int error;
20893097Sphk	u_char *buf;
20995323Sphk	struct disklabel *dl;
21096953Sphk	off_t secoff;
21193097Sphk
212104065Sphk	/*
213104065Sphk	 * We need to read entire aligned sectors, and we assume that the
214104065Sphk	 * disklabel does not span sectors, so one sector is enough.
215104065Sphk	 */
21696953Sphk	secoff = offset % secsize;
217152971Ssobomax	buf = g_read_data(cp, offset - secoff, secsize, NULL);
218152967Ssobomax	if (buf == NULL)
219105505Sphk		return (ENOENT);
220104065Sphk
221105505Sphk	/* Decode into our native format. */
222104065Sphk	dl = &ms->ondisk;
223114556Sphk	error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS);
224114556Sphk	if (!error)
225114556Sphk		bcopy(buf + secoff, ms->label, LABELSIZE);
226104065Sphk
227105505Sphk	/* Remember to free the buffer g_read_data() gave us. */
22893097Sphk	g_free(buf);
229104065Sphk
230113713Sphk	ms->labeloffset = offset;
231105505Sphk	return (error);
23293097Sphk}
23393097Sphk
234104065Sphk/*
235114568Sphk * This function writes the current label to disk, possibly updating
236114568Sphk * the alpha SRM checksum.
237114568Sphk */
238114568Sphk
239114568Sphkstatic int
240114568Sphkg_bsd_writelabel(struct g_geom *gp, u_char *bootcode)
241114568Sphk{
242114568Sphk	off_t secoff;
243114568Sphk	u_int secsize;
244114568Sphk	struct g_consumer *cp;
245114568Sphk	struct g_slicer *gsp;
246114568Sphk	struct g_bsd_softc *ms;
247114568Sphk	u_char *buf;
248114568Sphk	uint64_t sum;
249114568Sphk	int error, i;
250114568Sphk
251114568Sphk	gsp = gp->softc;
252114568Sphk	ms = gsp->softc;
253114568Sphk	cp = LIST_FIRST(&gp->consumer);
254114568Sphk	/* Get sector size, we need it to read data. */
255114568Sphk	secsize = cp->provider->sectorsize;
256114568Sphk	secoff = ms->labeloffset % secsize;
257114568Sphk	if (bootcode == NULL) {
258114568Sphk		buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
259152967Ssobomax		if (buf == NULL)
260114568Sphk			return (error);
261114568Sphk		bcopy(ms->label, buf + secoff, sizeof(ms->label));
262114568Sphk	} else {
263114568Sphk		buf = bootcode;
264114568Sphk		bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label));
265114568Sphk	}
266114568Sphk	if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
267114568Sphk		sum = 0;
268114568Sphk		for (i = 0; i < 63; i++)
269114568Sphk			sum += le64dec(buf + i * 8);
270114568Sphk		le64enc(buf + 504, sum);
271114568Sphk	}
272114568Sphk	if (bootcode == NULL) {
273114568Sphk		error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
274114568Sphk		g_free(buf);
275114568Sphk	} else {
276114568Sphk		error = g_write_data(cp, 0, bootcode, BBSIZE);
277114568Sphk	}
278114568Sphk	return(error);
279114568Sphk}
280114568Sphk
281114568Sphk/*
282107526Sphk * If the user tries to overwrite our disklabel through an open partition
283107526Sphk * or via a magicwrite config call, we end up here and try to prevent
284107526Sphk * footshooting as best we can.
285107526Sphk */
286107526Sphkstatic void
287112989Sphkg_bsd_hotwrite(void *arg, int flag)
288107526Sphk{
289107526Sphk	struct bio *bp;
290107526Sphk	struct g_geom *gp;
291107526Sphk	struct g_slicer *gsp;
292107832Sphk	struct g_slice *gsl;
293107526Sphk	struct g_bsd_softc *ms;
294107526Sphk	u_char *p;
295107526Sphk	int error;
296107526Sphk
297114556Sphk	g_topology_assert();
298113713Sphk	/*
299113713Sphk	 * We should never get canceled, because that would amount to a removal
300113713Sphk	 * of the geom while there was outstanding I/O requests.
301113713Sphk	 */
302112989Sphk	KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled"));
303107526Sphk	bp = arg;
304107526Sphk	gp = bp->bio_to->geom;
305107526Sphk	gsp = gp->softc;
306107526Sphk	ms = gsp->softc;
307107832Sphk	gsl = &gsp->slices[bp->bio_to->index];
308322860Smckusick	p = (u_char*)bp->bio_data + ms->labeloffset -
309322860Smckusick	    (bp->bio_offset + gsl->offset);
310114556Sphk	error = g_bsd_modify(gp, p);
311107526Sphk	if (error) {
312107526Sphk		g_io_deliver(bp, EPERM);
313107526Sphk		return;
314107526Sphk	}
315107526Sphk	g_slice_finish_hot(bp);
316107526Sphk}
317107526Sphk
31893097Sphkstatic int
319119660Sphkg_bsd_start(struct bio *bp)
320119660Sphk{
321119660Sphk	struct g_geom *gp;
322119660Sphk	struct g_bsd_softc *ms;
323119660Sphk	struct g_slicer *gsp;
324119660Sphk
325119660Sphk	gp = bp->bio_to->geom;
326119660Sphk	gsp = gp->softc;
327119660Sphk	ms = gsp->softc;
328119660Sphk	if (bp->bio_cmd == BIO_GETATTR) {
329119660Sphk		if (g_handleattr(bp, "BSD::labelsum", ms->labelsum,
330119660Sphk		    sizeof(ms->labelsum)))
331119660Sphk			return (1);
332119660Sphk	}
333119660Sphk	return (0);
334119660Sphk}
335119660Sphk
336104065Sphk/*
337104065Sphk * Dump configuration information in XML format.
338104065Sphk * Notice that the function is called once for the geom and once for each
339104065Sphk * consumer and provider.  We let g_slice_dumpconf() do most of the work.
340104065Sphk */
34192108Sphkstatic void
342107953Sphkg_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
34392108Sphk{
34495323Sphk	struct g_bsd_softc *ms;
34592108Sphk	struct g_slicer *gsp;
34692108Sphk
34792108Sphk	gsp = gp->softc;
34892108Sphk	ms = gsp->softc;
349106076Sphk	g_slice_dumpconf(sb, indent, gp, cp, pp);
350106076Sphk	if (indent != NULL && pp == NULL && cp == NULL) {
351103284Sphk		sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n",
352103284Sphk		    indent, (intmax_t)ms->labeloffset);
353106076Sphk		sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n",
354106076Sphk		    indent, (intmax_t)ms->rawoffset);
355106076Sphk		sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n",
356106076Sphk		    indent, (intmax_t)ms->mbroffset);
357109081Sjhb	} else if (pp != NULL) {
358109081Sjhb		if (indent == NULL)
359109081Sjhb			sbuf_printf(sb, " ty %d",
360114556Sphk			    ms->ondisk.d_partitions[pp->index].p_fstype);
361109081Sjhb		else
362109081Sjhb			sbuf_printf(sb, "%s<type>%d</type>\n", indent,
363114556Sphk			    ms->ondisk.d_partitions[pp->index].p_fstype);
36492108Sphk	}
36592108Sphk}
36692108Sphk
367104065Sphk/*
368104065Sphk * The taste function is called from the event-handler, with the topology
369104065Sphk * lock already held and a provider to examine.  The flags are unused.
370104065Sphk *
371104065Sphk * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and
372104065Sphk * if we find valid, consistent magic on it, build a geom on it.
373104065Sphk *
374104065Sphk * There may be cases where the operator would like to put a BSD-geom on
375104065Sphk * providers which do not meet all of the requirements.  This can be done
376104065Sphk * by instead passing the G_TF_INSIST flag, which will override these
377104065Sphk * checks.
378104065Sphk *
379104065Sphk * The final flags value is G_TF_TRANSPARENT, which instructs the method
380104065Sphk * to put a geom on top of the provider and configure it to be as transparent
381104065Sphk * as possible.  This is not really relevant to the BSD method and therefore
382104065Sphk * not implemented here.
383104065Sphk */
384104065Sphk
385174347Sjhbstatic struct uuid freebsd_slice = GPT_ENT_TYPE_FREEBSD;
386174347Sjhb
38792108Sphkstatic struct g_geom *
38893250Sphkg_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
38992108Sphk{
39092108Sphk	struct g_geom *gp;
39192108Sphk	struct g_consumer *cp;
392104065Sphk	int error, i;
39392108Sphk	struct g_bsd_softc *ms;
39492108Sphk	u_int secsize;
39594287Sphk	struct g_slicer *gsp;
396114556Sphk	u_char hash[16];
397108819Sphk	MD5_CTX md5sum;
398174347Sjhb	struct uuid uuid;
39992108Sphk
40092108Sphk	g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
40192108Sphk	g_topology_assert();
402104065Sphk
403105505Sphk	/* We don't implement transparent inserts. */
404104065Sphk	if (flags == G_TF_TRANSPARENT)
405104065Sphk		return (NULL);
406104065Sphk
407104065Sphk	/*
408104065Sphk	 * BSD labels are a subclass of the general "slicing" topology so
409104065Sphk	 * a lot of the work can be done by the common "slice" code.
410104065Sphk	 * Create a geom with space for MAXPARTITIONS providers, one consumer
411104065Sphk	 * and a softc structure for us.  Specify the provider to attach
412104065Sphk	 * the consumer to and our "start" routine for special requests.
413104065Sphk	 * The provider is opened with mode (1,0,0) so we can do reads
414104065Sphk	 * from it.
415104065Sphk	 */
416104065Sphk	gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms,
417105505Sphk	     sizeof(*ms), g_bsd_start);
41892108Sphk	if (gp == NULL)
41992108Sphk		return (NULL);
420104065Sphk
421105505Sphk	/* Get the geom_slicer softc from the geom. */
422104065Sphk	gsp = gp->softc;
423105505Sphk
424104065Sphk	/*
425104065Sphk	 * The do...while loop here allows us to have multiple escapes
426104065Sphk	 * using a simple "break".  This improves code clarity without
427104065Sphk	 * ending up in deep nesting and without using goto or come from.
428104065Sphk	 */
429104065Sphk	do {
430104065Sphk		/*
431104065Sphk		 * If the provider is an MBR we will only auto attach
432104065Sphk		 * to type 165 slices in the G_TF_NORMAL case.  We will
433108819Sphk		 * attach to any other type.
434104065Sphk		 */
43594287Sphk		error = g_getattr("MBR::type", cp, &i);
436107526Sphk		if (!error) {
437107526Sphk			if (i != 165 && flags == G_TF_NORMAL)
438107526Sphk				break;
439107526Sphk			error = g_getattr("MBR::offset", cp, &ms->mbroffset);
440107526Sphk			if (error)
441107526Sphk				break;
442107526Sphk		}
443104065Sphk
444107526Sphk		/* Same thing if we are inside a PC98 */
445106559Snyan		error = g_getattr("PC98::type", cp, &i);
446107526Sphk		if (!error) {
447107526Sphk			if (i != 0xc494 && flags == G_TF_NORMAL)
448107526Sphk				break;
449107526Sphk			error = g_getattr("PC98::offset", cp, &ms->mbroffset);
450107526Sphk			if (error)
451107526Sphk				break;
452107526Sphk		}
453106559Snyan
454174347Sjhb		/* Same thing if we are inside a GPT */
455174347Sjhb		error = g_getattr("GPT::type", cp, &uuid);
456174347Sjhb		if (!error) {
457174347Sjhb			if (memcmp(&uuid, &freebsd_slice, sizeof(uuid)) != 0 &&
458174347Sjhb			    flags == G_TF_NORMAL)
459174347Sjhb				break;
460174347Sjhb		}
461174347Sjhb
462104065Sphk		/* Get sector size, we need it to read data. */
463105551Sphk		secsize = cp->provider->sectorsize;
464105551Sphk		if (secsize < 512)
465104065Sphk			break;
466104065Sphk
467105505Sphk		/* First look for a label at the start of the second sector. */
468107526Sphk		error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize);
469104065Sphk
470152972Ssobomax		/*
471152972Ssobomax		 * If sector size is not 512 the label still can be at
472152972Ssobomax		 * offset 512, not at the start of the second sector. At least
473152972Ssobomax		 * it's true for labels created by the FreeBSD's bsdlabel(8).
474152972Ssobomax		 */
475152972Ssobomax		if (error && secsize != HISTORIC_LABEL_OFFSET)
476152972Ssobomax			error = g_bsd_try(gp, gsp, cp, secsize, ms,
477152972Ssobomax			    HISTORIC_LABEL_OFFSET);
478152972Ssobomax
479106634Sphk		/* Next, look for alpha labels */
480103009Sphk		if (error)
481107526Sphk			error = g_bsd_try(gp, gsp, cp, secsize, ms,
482106634Sphk			    ALPHA_LABEL_OFFSET);
483104065Sphk
484105505Sphk		/* If we didn't find a label, punt. */
48593097Sphk		if (error)
48692108Sphk			break;
487104065Sphk
488104065Sphk		/*
489108819Sphk		 * In order to avoid recursively attaching to the same
490108819Sphk		 * on-disk label (it's usually visible through the 'c'
491108819Sphk		 * partition) we calculate an MD5 and ask if other BSD's
492108819Sphk		 * below us love that label.  If they do, we don't.
493108819Sphk		 */
494108819Sphk		MD5Init(&md5sum);
495114556Sphk		MD5Update(&md5sum, ms->label, sizeof(ms->label));
496108819Sphk		MD5Final(ms->labelsum, &md5sum);
497108819Sphk
498108819Sphk		error = g_getattr("BSD::labelsum", cp, &hash);
499115611Sphk		if (!error && !bcmp(ms->labelsum, hash, sizeof(hash)))
500108819Sphk			break;
501108819Sphk
502108819Sphk		/*
503105505Sphk		 * Process the found disklabel, and modify our "slice"
504104065Sphk		 * instance to match it, if possible.
505104065Sphk		 */
506114556Sphk		error = g_bsd_modify(gp, ms->label);
507104065Sphk	} while (0);
508104065Sphk
509109169Sphk	/* Success or failure, we can close our provider now. */
510125803Sphk	g_access(cp, -1, 0, 0);
511104065Sphk
512104065Sphk	/* If we have configured any providers, return the new geom. */
513114556Sphk	if (gsp->nprovider > 0) {
514114556Sphk		g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE,
515114556Sphk		    G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL);
516114556Sphk		gsp->hot = g_bsd_hotwrite;
51792108Sphk		return (gp);
518114556Sphk	}
519104065Sphk	/*
520104065Sphk	 * ...else push the "self-destruct" button, by spoiling our own
521114506Sphk	 * consumer.  This triggers a call to g_slice_spoiled which will
522104065Sphk	 * dismantle what was setup.
523104065Sphk	 */
524114506Sphk	g_slice_spoiled(cp);
52592108Sphk	return (NULL);
52692108Sphk}
52792108Sphk
528114568Sphkstruct h0h0 {
529114568Sphk	struct g_geom *gp;
530114568Sphk	struct g_bsd_softc *ms;
531114568Sphk	u_char *label;
532114568Sphk	int error;
533114568Sphk};
534114568Sphk
535114568Sphkstatic void
536114568Sphkg_bsd_callconfig(void *arg, int flag)
537114568Sphk{
538114568Sphk	struct h0h0 *hp;
539114568Sphk
540114568Sphk	hp = arg;
541114568Sphk	hp->error = g_bsd_modify(hp->gp, hp->label);
542114568Sphk	if (!hp->error)
543114568Sphk		hp->error = g_bsd_writelabel(hp->gp, NULL);
544114568Sphk}
545114568Sphk
546114568Sphk/*
547114568Sphk * NB! curthread is user process which GCTL'ed.
548114568Sphk */
549115624Sphkstatic void
550115624Sphkg_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb)
551114568Sphk{
552114568Sphk	u_char *label;
553115509Sphk	int error;
554114568Sphk	struct h0h0 h0h0;
555115624Sphk	struct g_geom *gp;
556114568Sphk	struct g_slicer *gsp;
557114568Sphk	struct g_consumer *cp;
558114671Sphk	struct g_bsd_softc *ms;
559114568Sphk
560114568Sphk	g_topology_assert();
561115624Sphk	gp = gctl_get_geom(req, mp, "geom");
562115624Sphk	if (gp == NULL)
563115624Sphk		return;
564114568Sphk	cp = LIST_FIRST(&gp->consumer);
565114568Sphk	gsp = gp->softc;
566114671Sphk	ms = gsp->softc;
567114671Sphk	if (!strcmp(verb, "read mbroffset")) {
568157581Smarcel		gctl_set_param_err(req, "mbroffset", &ms->mbroffset,
569157581Smarcel		    sizeof(ms->mbroffset));
570115624Sphk		return;
571114671Sphk	} else if (!strcmp(verb, "write label")) {
572114568Sphk		label = gctl_get_paraml(req, "label", LABELSIZE);
573114568Sphk		if (label == NULL)
574115624Sphk			return;
575114568Sphk		h0h0.gp = gp;
576114568Sphk		h0h0.ms = gsp->softc;
577114568Sphk		h0h0.label = label;
578114568Sphk		h0h0.error = -1;
579114568Sphk		/* XXX: Does this reference register with our selfdestruct code ? */
580125755Sphk		error = g_access(cp, 1, 1, 1);
581114568Sphk		if (error) {
582115624Sphk			gctl_error(req, "could not access consumer");
583115624Sphk			return;
584114568Sphk		}
585115624Sphk		g_bsd_callconfig(&h0h0, 0);
586114568Sphk		error = h0h0.error;
587125755Sphk		g_access(cp, -1, -1, -1);
588114568Sphk	} else if (!strcmp(verb, "write bootcode")) {
589114568Sphk		label = gctl_get_paraml(req, "bootcode", BBSIZE);
590114568Sphk		if (label == NULL)
591115624Sphk			return;
592114568Sphk		/* XXX: Does this reference register with our selfdestruct code ? */
593125755Sphk		error = g_access(cp, 1, 1, 1);
594114568Sphk		if (error) {
595115624Sphk			gctl_error(req, "could not access consumer");
596115624Sphk			return;
597114568Sphk		}
598114568Sphk		error = g_bsd_writelabel(gp, label);
599125755Sphk		g_access(cp, -1, -1, -1);
600114568Sphk	} else {
601115624Sphk		gctl_error(req, "Unknown verb parameter");
602114568Sphk	}
603114568Sphk
604115624Sphk	return;
605114568Sphk}
606114568Sphk
607105505Sphk/* Finally, register with GEOM infrastructure. */
608104065Sphkstatic struct g_class g_bsd_class = {
609112552Sphk	.name = BSD_CLASS_NAME,
610133318Sphk	.version = G_VERSION,
611112552Sphk	.taste = g_bsd_taste,
612115624Sphk	.ctlreq = g_bsd_config,
613133314Sphk	.dumpconf = g_bsd_dumpconf,
61492108Sphk};
61592108Sphk
61693248SphkDECLARE_GEOM_CLASS(g_bsd_class, g_bsd);
617