FreeBSD/Linux Kernel Cross Reference
sys/geom/geom_bsd.c
1 /*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $FreeBSD: releng/5.1/sys/geom/geom_bsd.c 114785 2003-05-06 19:36:13Z phk $
36 *
37 * This is the method for dealing with BSD disklabels. It has been
38 * extensively (by my standards at least) commented, in the vain hope that
39 * it will serve as the source in future copy&paste operations.
40 */
41
42 #include <sys/param.h>
43 #include <sys/endian.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/conf.h>
47 #include <sys/bio.h>
48 #include <sys/malloc.h>
49 #include <sys/lock.h>
50 #include <sys/mutex.h>
51 #include <sys/md5.h>
52 #include <sys/errno.h>
53 #include <sys/disklabel.h>
54 #include <geom/geom.h>
55 #include <geom/geom_slice.h>
56
57 #define BSD_CLASS_NAME "BSD"
58
59 #define ALPHA_LABEL_OFFSET 64
60
61 #define LABELSIZE (148 + 16 * MAXPARTITIONS)
62
63 static void g_bsd_hotwrite(void *arg, int flag);
64 /*
65 * Our private data about one instance. All the rest is handled by the
66 * slice code and stored in its softc, so this is just the stuff
67 * specific to BSD disklabels.
68 */
69 struct g_bsd_softc {
70 off_t labeloffset;
71 off_t mbroffset;
72 off_t rawoffset;
73 struct disklabel ondisk;
74 u_char label[LABELSIZE];
75 u_char labelsum[16];
76 };
77
78 /*
79 * Modify our slicer to match proposed disklabel, if possible.
80 * This is where we make sure we don't do something stupid.
81 */
82 static int
83 g_bsd_modify(struct g_geom *gp, u_char *label)
84 {
85 int i, error;
86 struct partition *ppp;
87 struct g_slicer *gsp;
88 struct g_consumer *cp;
89 struct g_bsd_softc *ms;
90 u_int secsize, u;
91 off_t mediasize, rawoffset, o;
92 struct disklabel dl;
93 MD5_CTX md5sum;
94
95 g_topology_assert();
96 gsp = gp->softc;
97 ms = gsp->softc;
98
99 error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS);
100 if (error) {
101 return (error);
102 }
103
104 /* Get dimensions of our device. */
105 cp = LIST_FIRST(&gp->consumer);
106 secsize = cp->provider->sectorsize;
107 mediasize = cp->provider->mediasize;
108
109 #ifdef notyet
110 /*
111 * Indications are that the d_secperunit is not correctly
112 * initialized in many cases, and since we don't need it
113 * for anything, we dont strictly need this test.
114 * Preemptive action to avoid confusing people in disklabel(8)
115 * may be in order.
116 */
117 /* The label cannot claim a larger size than the media. */
118 if ((off_t)dl.d_secperunit * dl.d_secsize > mediasize)
119 return (EINVAL);
120 #endif
121
122 /* ... or a smaller sector size. */
123 if (dl.d_secsize < secsize) {
124 return (EINVAL);
125 }
126
127 /* ... or a non-multiple sector size. */
128 if (dl.d_secsize % secsize != 0) {
129 return (EINVAL);
130 }
131
132 /* Historical braindamage... */
133 rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize;
134
135 for (i = 0; i < dl.d_npartitions; i++) {
136 ppp = &dl.d_partitions[i];
137 if (ppp->p_size == 0)
138 continue;
139 o = (off_t)ppp->p_offset * dl.d_secsize;
140
141 if (o < rawoffset)
142 rawoffset = 0;
143 }
144
145 if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset)
146 printf("WARNING: Expected rawoffset %jd, found %jd\n",
147 (intmax_t)ms->mbroffset/dl.d_secsize,
148 (intmax_t)rawoffset/dl.d_secsize);
149
150 /* Don't munge open partitions. */
151 for (i = 0; i < dl.d_npartitions; i++) {
152 ppp = &dl.d_partitions[i];
153
154 o = (off_t)ppp->p_offset * dl.d_secsize;
155 if (o == 0)
156 o = rawoffset;
157 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
158 o - rawoffset,
159 (off_t)ppp->p_size * dl.d_secsize,
160 dl.d_secsize,
161 "%s%c", gp->name, 'a' + i);
162 if (error)
163 return (error);
164 }
165
166 /* Look good, go for it... */
167 for (u = 0; u < gsp->nslice; u++) {
168 ppp = &dl.d_partitions[u];
169 o = (off_t)ppp->p_offset * dl.d_secsize;
170 if (o == 0)
171 o = rawoffset;
172 g_slice_config(gp, u, G_SLICE_CONFIG_SET,
173 o - rawoffset,
174 (off_t)ppp->p_size * dl.d_secsize,
175 dl.d_secsize,
176 "%s%c", gp->name, 'a' + u);
177 }
178
179 /* Update our softc */
180 ms->ondisk = dl;
181 if (label != ms->label)
182 bcopy(label, ms->label, LABELSIZE);
183 ms->rawoffset = rawoffset;
184
185 /*
186 * In order to avoid recursively attaching to the same
187 * on-disk label (it's usually visible through the 'c'
188 * partition) we calculate an MD5 and ask if other BSD's
189 * below us love that label. If they do, we don't.
190 */
191 MD5Init(&md5sum);
192 MD5Update(&md5sum, ms->label, sizeof(ms->label));
193 MD5Final(ms->labelsum, &md5sum);
194
195 return (0);
196 }
197
198 /*
199 * This is an internal helper function, called multiple times from the taste
200 * function to try to locate a disklabel on the disk. More civilized formats
201 * will not need this, as there is only one possible place on disk to look
202 * for the magic spot.
203 */
204
205 static int
206 g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset)
207 {
208 int error;
209 u_char *buf;
210 struct disklabel *dl;
211 off_t secoff;
212
213 /*
214 * We need to read entire aligned sectors, and we assume that the
215 * disklabel does not span sectors, so one sector is enough.
216 */
217 error = 0;
218 secoff = offset % secsize;
219 buf = g_read_data(cp, offset - secoff, secsize, &error);
220 if (buf == NULL || error != 0)
221 return (ENOENT);
222
223 /* Decode into our native format. */
224 dl = &ms->ondisk;
225 error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS);
226 if (!error)
227 bcopy(buf + secoff, ms->label, LABELSIZE);
228
229 /* Remember to free the buffer g_read_data() gave us. */
230 g_free(buf);
231
232 ms->labeloffset = offset;
233 return (error);
234 }
235
236 /*
237 * This function writes the current label to disk, possibly updating
238 * the alpha SRM checksum.
239 */
240
241 static int
242 g_bsd_writelabel(struct g_geom *gp, u_char *bootcode)
243 {
244 off_t secoff;
245 u_int secsize;
246 struct g_consumer *cp;
247 struct g_slicer *gsp;
248 struct g_bsd_softc *ms;
249 u_char *buf;
250 uint64_t sum;
251 int error, i;
252
253 gsp = gp->softc;
254 ms = gsp->softc;
255 cp = LIST_FIRST(&gp->consumer);
256 /* Get sector size, we need it to read data. */
257 secsize = cp->provider->sectorsize;
258 secoff = ms->labeloffset % secsize;
259 if (bootcode == NULL) {
260 buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
261 if (buf == NULL || error != 0)
262 return (error);
263 bcopy(ms->label, buf + secoff, sizeof(ms->label));
264 } else {
265 buf = bootcode;
266 bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label));
267 }
268 if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
269 sum = 0;
270 for (i = 0; i < 63; i++)
271 sum += le64dec(buf + i * 8);
272 le64enc(buf + 504, sum);
273 }
274 if (bootcode == NULL) {
275 error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
276 g_free(buf);
277 } else {
278 error = g_write_data(cp, 0, bootcode, BBSIZE);
279 }
280 return(error);
281 }
282
283
284 /*
285 * Implement certain ioctls to modify disklabels with. This function
286 * is called by the event handler thread with topology locked as result
287 * of the g_post_event() in g_bsd_start(). It is not necessary to keep
288 * topology locked all the time but make sure to return with topology
289 * locked as well.
290 */
291
292 static void
293 g_bsd_ioctl(void *arg, int flag)
294 {
295 struct bio *bp;
296 struct g_geom *gp;
297 struct g_slicer *gsp;
298 struct g_bsd_softc *ms;
299 struct g_ioctl *gio;
300 u_char *label;
301 int error;
302
303 g_topology_assert();
304 bp = arg;
305 if (flag == EV_CANCEL) {
306 g_io_deliver(bp, ENXIO);
307 return;
308 }
309
310 gp = bp->bio_to->geom;
311 gsp = gp->softc;
312 ms = gsp->softc;
313 gio = (struct g_ioctl *)bp->bio_data;
314
315 label = g_malloc(LABELSIZE, M_WAITOK);
316
317 /* The disklabel to set is the ioctl argument. */
318 bsd_disklabel_le_enc(label, gio->data);
319
320 /* Validate and modify our slice instance to match. */
321 error = g_bsd_modify(gp, label); /* Picks up topology lock on success. */
322 g_free(label);
323 if (error || gio->cmd == DIOCSDINFO) {
324 g_io_deliver(bp, error);
325 return;
326 }
327
328 KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl"));
329 g_io_deliver(bp, g_bsd_writelabel(gp, NULL));
330 }
331
332 /*
333 * Rewrite the bootblock, which is BBSIZE bytes from the start of the disk.
334 * We punch down the disklabel where we expect it to be before writing.
335 */
336 static int
337 g_bsd_diocbsdbb(dev_t dev, u_long cmd __unused, caddr_t data, int fflag __unused, struct thread *td __unused)
338 {
339 struct g_geom *gp;
340 struct g_slicer *gsp;
341 struct g_bsd_softc *ms;
342 struct g_consumer *cp;
343 u_char *buf;
344 void *p;
345 u_int secsize;
346 int error, i;
347 uint64_t sum;
348
349 /* Get hold of the interesting bits from the bio. */
350 gp = (void *)dev;
351 gsp = gp->softc;
352 ms = gsp->softc;
353
354 /* The disklabel to set is the ioctl argument. */
355 buf = g_malloc(BBSIZE, M_WAITOK);
356 p = *(void **)data;
357 error = copyin(p, buf, BBSIZE);
358 if (!error) {
359 DROP_GIANT();
360 g_topology_lock();
361 /* Validate and modify our slice instance to match. */
362 error = g_bsd_modify(gp, buf + ms->labeloffset);
363 if (!error) {
364 cp = LIST_FIRST(&gp->consumer);
365 secsize = cp->provider->sectorsize;
366 if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
367 sum = 0;
368 for (i = 0; i < 63; i++)
369 sum += le64dec(buf + i * 8);
370 le64enc(buf + 504, sum);
371 }
372 error = g_write_data(cp, 0, buf, BBSIZE);
373 }
374 g_topology_unlock();
375 PICKUP_GIANT();
376 }
377 g_free(buf);
378 return (error);
379 }
380
381 /*
382 * If the user tries to overwrite our disklabel through an open partition
383 * or via a magicwrite config call, we end up here and try to prevent
384 * footshooting as best we can.
385 */
386 static void
387 g_bsd_hotwrite(void *arg, int flag)
388 {
389 struct bio *bp;
390 struct g_geom *gp;
391 struct g_slicer *gsp;
392 struct g_slice *gsl;
393 struct g_bsd_softc *ms;
394 u_char *p;
395 int error;
396
397 g_topology_assert();
398 /*
399 * We should never get canceled, because that would amount to a removal
400 * of the geom while there was outstanding I/O requests.
401 */
402 KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled"));
403 bp = arg;
404 gp = bp->bio_to->geom;
405 gsp = gp->softc;
406 ms = gsp->softc;
407 gsl = &gsp->slices[bp->bio_to->index];
408 p = (u_char*)bp->bio_data + ms->labeloffset
409 - (bp->bio_offset + gsl->offset);
410 error = g_bsd_modify(gp, p);
411 if (error) {
412 g_io_deliver(bp, EPERM);
413 return;
414 }
415 g_slice_finish_hot(bp);
416 }
417
418 /*-
419 * This start routine is only called for non-trivial requests, all the
420 * trivial ones are handled autonomously by the slice code.
421 * For requests we handle here, we must call the g_io_deliver() on the
422 * bio, and return non-zero to indicate to the slice code that we did so.
423 * This code executes in the "DOWN" I/O path, this means:
424 * * No sleeping.
425 * * Don't grab the topology lock.
426 * * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
427 */
428
429 static int
430 g_bsd_start(struct bio *bp)
431 {
432 struct g_geom *gp;
433 struct g_bsd_softc *ms;
434 struct g_slicer *gsp;
435 struct g_ioctl *gio;
436 int error;
437
438 gp = bp->bio_to->geom;
439 gsp = gp->softc;
440 ms = gsp->softc;
441 switch(bp->bio_cmd) {
442 case BIO_GETATTR:
443 if (g_handleattr(bp, "BSD::labelsum", ms->labelsum,
444 sizeof(ms->labelsum)))
445 return (1);
446 break;
447 default:
448 KASSERT(0 == 1, ("Unknown bio_cmd in g_bsd_start (%d)",
449 bp->bio_cmd));
450 }
451
452 /* We only handle ioctl(2) requests of the right format. */
453 if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
454 return (0);
455 else if (bp->bio_length != sizeof(*gio))
456 return (0);
457
458 /* Get hold of the ioctl parameters. */
459 gio = (struct g_ioctl *)bp->bio_data;
460
461 switch (gio->cmd) {
462 case DIOCGDINFO:
463 /* Return a copy of the disklabel to userland. */
464 bsd_disklabel_le_dec(ms->label, gio->data, MAXPARTITIONS);
465 g_io_deliver(bp, 0);
466 return (1);
467 case DIOCBSDBB:
468 gio->func = g_bsd_diocbsdbb;
469 gio->dev = (void *)gp;
470 g_io_deliver(bp, EDIRIOCTL);
471 return (1);
472 case DIOCSDINFO:
473 case DIOCWDINFO:
474 /*
475 * These we cannot do without the topology lock and some
476 * some I/O requests. Ask the event-handler to schedule
477 * us in a less restricted environment.
478 */
479 error = g_post_event(g_bsd_ioctl, bp, M_NOWAIT, gp, NULL);
480 if (error)
481 g_io_deliver(bp, error);
482 /*
483 * We must return non-zero to indicate that we will deal
484 * with this bio, even though we have not done so yet.
485 */
486 return (1);
487 default:
488 return (0);
489 }
490 }
491
492 /*
493 * Dump configuration information in XML format.
494 * Notice that the function is called once for the geom and once for each
495 * consumer and provider. We let g_slice_dumpconf() do most of the work.
496 */
497 static void
498 g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
499 {
500 struct g_bsd_softc *ms;
501 struct g_slicer *gsp;
502
503 gsp = gp->softc;
504 ms = gsp->softc;
505 g_slice_dumpconf(sb, indent, gp, cp, pp);
506 if (indent != NULL && pp == NULL && cp == NULL) {
507 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n",
508 indent, (intmax_t)ms->labeloffset);
509 sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n",
510 indent, (intmax_t)ms->rawoffset);
511 sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n",
512 indent, (intmax_t)ms->mbroffset);
513 } else if (pp != NULL) {
514 if (indent == NULL)
515 sbuf_printf(sb, " ty %d",
516 ms->ondisk.d_partitions[pp->index].p_fstype);
517 else
518 sbuf_printf(sb, "%s<type>%d</type>\n", indent,
519 ms->ondisk.d_partitions[pp->index].p_fstype);
520 }
521 }
522
523 /*
524 * The taste function is called from the event-handler, with the topology
525 * lock already held and a provider to examine. The flags are unused.
526 *
527 * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and
528 * if we find valid, consistent magic on it, build a geom on it.
529 * any magic bits which indicate that we should automatically put a BSD
530 * geom on it.
531 *
532 * There may be cases where the operator would like to put a BSD-geom on
533 * providers which do not meet all of the requirements. This can be done
534 * by instead passing the G_TF_INSIST flag, which will override these
535 * checks.
536 *
537 * The final flags value is G_TF_TRANSPARENT, which instructs the method
538 * to put a geom on top of the provider and configure it to be as transparent
539 * as possible. This is not really relevant to the BSD method and therefore
540 * not implemented here.
541 */
542
543 static struct g_geom *
544 g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
545 {
546 struct g_geom *gp;
547 struct g_consumer *cp;
548 int error, i;
549 struct g_bsd_softc *ms;
550 u_int secsize;
551 struct g_slicer *gsp;
552 u_char hash[16];
553 MD5_CTX md5sum;
554
555 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
556 g_topology_assert();
557
558 /* We don't implement transparent inserts. */
559 if (flags == G_TF_TRANSPARENT)
560 return (NULL);
561
562 /*
563 * BSD labels are a subclass of the general "slicing" topology so
564 * a lot of the work can be done by the common "slice" code.
565 * Create a geom with space for MAXPARTITIONS providers, one consumer
566 * and a softc structure for us. Specify the provider to attach
567 * the consumer to and our "start" routine for special requests.
568 * The provider is opened with mode (1,0,0) so we can do reads
569 * from it.
570 */
571 gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms,
572 sizeof(*ms), g_bsd_start);
573 if (gp == NULL)
574 return (NULL);
575
576 /*
577 * Fill in the optional details, in our case we have a dumpconf
578 * routine which the "slice" code should call at the right time
579 */
580 gp->dumpconf = g_bsd_dumpconf;
581
582 /* Get the geom_slicer softc from the geom. */
583 gsp = gp->softc;
584
585 /*
586 * The do...while loop here allows us to have multiple escapes
587 * using a simple "break". This improves code clarity without
588 * ending up in deep nesting and without using goto or come from.
589 */
590 do {
591 /*
592 * If the provider is an MBR we will only auto attach
593 * to type 165 slices in the G_TF_NORMAL case. We will
594 * attach to any other type.
595 */
596 error = g_getattr("MBR::type", cp, &i);
597 if (!error) {
598 if (i != 165 && flags == G_TF_NORMAL)
599 break;
600 error = g_getattr("MBR::offset", cp, &ms->mbroffset);
601 if (error)
602 break;
603 }
604
605 /* Same thing if we are inside a PC98 */
606 error = g_getattr("PC98::type", cp, &i);
607 if (!error) {
608 if (i != 0xc494 && flags == G_TF_NORMAL)
609 break;
610 error = g_getattr("PC98::offset", cp, &ms->mbroffset);
611 if (error)
612 break;
613 }
614
615 /* Get sector size, we need it to read data. */
616 secsize = cp->provider->sectorsize;
617 if (secsize < 512)
618 break;
619
620 /* First look for a label at the start of the second sector. */
621 error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize);
622
623 /* Next, look for alpha labels */
624 if (error)
625 error = g_bsd_try(gp, gsp, cp, secsize, ms,
626 ALPHA_LABEL_OFFSET);
627
628 /* If we didn't find a label, punt. */
629 if (error)
630 break;
631
632 /*
633 * In order to avoid recursively attaching to the same
634 * on-disk label (it's usually visible through the 'c'
635 * partition) we calculate an MD5 and ask if other BSD's
636 * below us love that label. If they do, we don't.
637 */
638 MD5Init(&md5sum);
639 MD5Update(&md5sum, ms->label, sizeof(ms->label));
640 MD5Final(ms->labelsum, &md5sum);
641
642 error = g_getattr("BSD::labelsum", cp, &hash);
643 if (!error && !strncmp(ms->labelsum, hash, sizeof(hash)))
644 break;
645
646 /*
647 * Process the found disklabel, and modify our "slice"
648 * instance to match it, if possible.
649 */
650 error = g_bsd_modify(gp, ms->label);
651 } while (0);
652
653 /* Success or failure, we can close our provider now. */
654 error = g_access_rel(cp, -1, 0, 0);
655
656 /* If we have configured any providers, return the new geom. */
657 if (gsp->nprovider > 0) {
658 g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE,
659 G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL);
660 gsp->hot = g_bsd_hotwrite;
661 return (gp);
662 }
663 /*
664 * ...else push the "self-destruct" button, by spoiling our own
665 * consumer. This triggers a call to g_slice_spoiled which will
666 * dismantle what was setup.
667 */
668 g_slice_spoiled(cp);
669 return (NULL);
670 }
671
672 struct h0h0 {
673 struct g_geom *gp;
674 struct g_bsd_softc *ms;
675 u_char *label;
676 int error;
677 };
678
679 static void
680 g_bsd_callconfig(void *arg, int flag)
681 {
682 struct h0h0 *hp;
683
684 hp = arg;
685 hp->error = g_bsd_modify(hp->gp, hp->label);
686 if (!hp->error)
687 hp->error = g_bsd_writelabel(hp->gp, NULL);
688 }
689
690 /*
691 * NB! curthread is user process which GCTL'ed.
692 */
693 static int
694 g_bsd_config(struct gctl_req *req, struct g_geom *gp, const char *verb)
695 {
696 u_char *label;
697 int error, i;
698 struct h0h0 h0h0;
699 struct g_slicer *gsp;
700 struct g_consumer *cp;
701 struct g_bsd_softc *ms;
702
703 i = 0;
704 g_topology_assert();
705 cp = LIST_FIRST(&gp->consumer);
706 gsp = gp->softc;
707 ms = gsp->softc;
708 if (!strcmp(verb, "read mbroffset")) {
709 error = gctl_set_param(req, "mbroffset",
710 &ms->mbroffset, sizeof(ms->mbroffset));
711 return (error);
712 } else if (!strcmp(verb, "write label")) {
713 label = gctl_get_paraml(req, "label", LABELSIZE);
714 if (label == NULL)
715 return (EINVAL);
716 h0h0.gp = gp;
717 h0h0.ms = gsp->softc;
718 h0h0.label = label;
719 h0h0.error = -1;
720 /* XXX: Does this reference register with our selfdestruct code ? */
721 error = g_access_rel(cp, 1, 1, 1);
722 if (error) {
723 g_free(label);
724 return (error);
725 }
726 g_topology_unlock();
727 g_waitfor_event(g_bsd_callconfig, &h0h0, M_WAITOK, gp, NULL);
728 g_topology_lock();
729 error = h0h0.error;
730 g_access_rel(cp, -1, -1, -1);
731 g_free(label);
732 } else if (!strcmp(verb, "write bootcode")) {
733 label = gctl_get_paraml(req, "bootcode", BBSIZE);
734 if (label == NULL)
735 return (EINVAL);
736 /* XXX: Does this reference register with our selfdestruct code ? */
737 error = g_access_rel(cp, 1, 1, 1);
738 if (error) {
739 g_free(label);
740 return (error);
741 }
742 error = g_bsd_writelabel(gp, label);
743 g_access_rel(cp, -1, -1, -1);
744 g_free(label);
745 } else {
746 return (gctl_error(req, "Unknown verb parameter"));
747 }
748
749 return (error);
750 }
751
752 /* Finally, register with GEOM infrastructure. */
753 static struct g_class g_bsd_class = {
754 .name = BSD_CLASS_NAME,
755 .taste = g_bsd_taste,
756 .config_geom = g_bsd_config,
757 G_CLASS_INITIALIZER
758 };
759
760 DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);
Cache object: ba3de052c634993acf0f518a4a2a130a
|