1 /*-
2 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/bio.h>
37 #include <sys/sbuf.h>
38 #include <sys/sysctl.h>
39 #include <sys/malloc.h>
40 #include <vm/uma.h>
41 #include <geom/geom.h>
42 #include <geom/shsec/g_shsec.h>
43
44 FEATURE(geom_shsec, "GEOM shared secret device support");
45
46 static MALLOC_DEFINE(M_SHSEC, "shsec_data", "GEOM_SHSEC Data");
47
48 static uma_zone_t g_shsec_zone;
49
50 static int g_shsec_destroy(struct g_shsec_softc *sc, boolean_t force);
51 static int g_shsec_destroy_geom(struct gctl_req *req, struct g_class *mp,
52 struct g_geom *gp);
53
54 static g_taste_t g_shsec_taste;
55 static g_ctl_req_t g_shsec_config;
56 static g_dumpconf_t g_shsec_dumpconf;
57 static g_init_t g_shsec_init;
58 static g_fini_t g_shsec_fini;
59
60 struct g_class g_shsec_class = {
61 .name = G_SHSEC_CLASS_NAME,
62 .version = G_VERSION,
63 .ctlreq = g_shsec_config,
64 .taste = g_shsec_taste,
65 .destroy_geom = g_shsec_destroy_geom,
66 .init = g_shsec_init,
67 .fini = g_shsec_fini
68 };
69
70 SYSCTL_DECL(_kern_geom);
71 static SYSCTL_NODE(_kern_geom, OID_AUTO, shsec, CTLFLAG_RW, 0,
72 "GEOM_SHSEC stuff");
73 static u_int g_shsec_debug = 0;
74 SYSCTL_UINT(_kern_geom_shsec, OID_AUTO, debug, CTLFLAG_RWTUN, &g_shsec_debug, 0,
75 "Debug level");
76 static u_int g_shsec_maxmem = MAXPHYS * 100;
77 SYSCTL_UINT(_kern_geom_shsec, OID_AUTO, maxmem, CTLFLAG_RDTUN, &g_shsec_maxmem,
78 0, "Maximum memory that can be allocated for I/O (in bytes)");
79 static u_int g_shsec_alloc_failed = 0;
80 SYSCTL_UINT(_kern_geom_shsec, OID_AUTO, alloc_failed, CTLFLAG_RD,
81 &g_shsec_alloc_failed, 0, "How many times I/O allocation failed");
82
83 /*
84 * Greatest Common Divisor.
85 */
86 static u_int
87 gcd(u_int a, u_int b)
88 {
89 u_int c;
90
91 while (b != 0) {
92 c = a;
93 a = b;
94 b = (c % b);
95 }
96 return (a);
97 }
98
99 /*
100 * Least Common Multiple.
101 */
102 static u_int
103 lcm(u_int a, u_int b)
104 {
105
106 return ((a * b) / gcd(a, b));
107 }
108
109 static void
110 g_shsec_init(struct g_class *mp __unused)
111 {
112
113 g_shsec_zone = uma_zcreate("g_shsec_zone", MAXPHYS, NULL, NULL, NULL,
114 NULL, 0, 0);
115 g_shsec_maxmem -= g_shsec_maxmem % MAXPHYS;
116 uma_zone_set_max(g_shsec_zone, g_shsec_maxmem / MAXPHYS);
117 }
118
119 static void
120 g_shsec_fini(struct g_class *mp __unused)
121 {
122
123 uma_zdestroy(g_shsec_zone);
124 }
125
126 /*
127 * Return the number of valid disks.
128 */
129 static u_int
130 g_shsec_nvalid(struct g_shsec_softc *sc)
131 {
132 u_int i, no;
133
134 no = 0;
135 for (i = 0; i < sc->sc_ndisks; i++) {
136 if (sc->sc_disks[i] != NULL)
137 no++;
138 }
139
140 return (no);
141 }
142
143 static void
144 g_shsec_remove_disk(struct g_consumer *cp)
145 {
146 struct g_shsec_softc *sc;
147 u_int no;
148
149 KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__));
150 sc = (struct g_shsec_softc *)cp->private;
151 KASSERT(sc != NULL, ("NULL sc in %s.", __func__));
152 no = cp->index;
153
154 G_SHSEC_DEBUG(0, "Disk %s removed from %s.", cp->provider->name,
155 sc->sc_name);
156
157 sc->sc_disks[no] = NULL;
158 if (sc->sc_provider != NULL) {
159 g_wither_provider(sc->sc_provider, ENXIO);
160 sc->sc_provider = NULL;
161 G_SHSEC_DEBUG(0, "Device %s removed.", sc->sc_name);
162 }
163
164 if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
165 return;
166 g_detach(cp);
167 g_destroy_consumer(cp);
168 }
169
170 static void
171 g_shsec_orphan(struct g_consumer *cp)
172 {
173 struct g_shsec_softc *sc;
174 struct g_geom *gp;
175
176 g_topology_assert();
177 gp = cp->geom;
178 sc = gp->softc;
179 if (sc == NULL)
180 return;
181
182 g_shsec_remove_disk(cp);
183 /* If there are no valid disks anymore, remove device. */
184 if (LIST_EMPTY(&gp->consumer))
185 g_shsec_destroy(sc, 1);
186 }
187
188 static int
189 g_shsec_access(struct g_provider *pp, int dr, int dw, int de)
190 {
191 struct g_consumer *cp1, *cp2, *tmp;
192 struct g_shsec_softc *sc;
193 struct g_geom *gp;
194 int error;
195
196 gp = pp->geom;
197 sc = gp->softc;
198
199 /* On first open, grab an extra "exclusive" bit */
200 if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
201 de++;
202 /* ... and let go of it on last close */
203 if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0)
204 de--;
205
206 error = ENXIO;
207 LIST_FOREACH_SAFE(cp1, &gp->consumer, consumer, tmp) {
208 error = g_access(cp1, dr, dw, de);
209 if (error != 0)
210 goto fail;
211 if (cp1->acr == 0 && cp1->acw == 0 && cp1->ace == 0 &&
212 cp1->flags & G_CF_ORPHAN) {
213 g_detach(cp1);
214 g_destroy_consumer(cp1);
215 }
216 }
217
218 /* If there are no valid disks anymore, remove device. */
219 if (LIST_EMPTY(&gp->consumer))
220 g_shsec_destroy(sc, 1);
221
222 return (error);
223
224 fail:
225 /* If we fail here, backout all previous changes. */
226 LIST_FOREACH(cp2, &gp->consumer, consumer) {
227 if (cp1 == cp2)
228 break;
229 g_access(cp2, -dr, -dw, -de);
230 }
231 return (error);
232 }
233
234 static void
235 g_shsec_xor1(uint32_t *src, uint32_t *dst, ssize_t len)
236 {
237
238 for (; len > 0; len -= sizeof(uint32_t), dst++)
239 *dst = *dst ^ *src++;
240 KASSERT(len == 0, ("len != 0 (len=%zd)", len));
241 }
242
243 static void
244 g_shsec_done(struct bio *bp)
245 {
246 struct g_shsec_softc *sc;
247 struct bio *pbp;
248
249 pbp = bp->bio_parent;
250 sc = pbp->bio_to->geom->softc;
251 if (bp->bio_error == 0)
252 G_SHSEC_LOGREQ(2, bp, "Request done.");
253 else {
254 G_SHSEC_LOGREQ(0, bp, "Request failed (error=%d).",
255 bp->bio_error);
256 if (pbp->bio_error == 0)
257 pbp->bio_error = bp->bio_error;
258 }
259 if (pbp->bio_cmd == BIO_READ) {
260 if ((pbp->bio_pflags & G_SHSEC_BFLAG_FIRST) != 0) {
261 bcopy(bp->bio_data, pbp->bio_data, pbp->bio_length);
262 pbp->bio_pflags = 0;
263 } else {
264 g_shsec_xor1((uint32_t *)bp->bio_data,
265 (uint32_t *)pbp->bio_data,
266 (ssize_t)pbp->bio_length);
267 }
268 }
269 bzero(bp->bio_data, bp->bio_length);
270 uma_zfree(g_shsec_zone, bp->bio_data);
271 g_destroy_bio(bp);
272 pbp->bio_inbed++;
273 if (pbp->bio_children == pbp->bio_inbed) {
274 pbp->bio_completed = pbp->bio_length;
275 g_io_deliver(pbp, pbp->bio_error);
276 }
277 }
278
279 static void
280 g_shsec_xor2(uint32_t *rand, uint32_t *dst, ssize_t len)
281 {
282
283 for (; len > 0; len -= sizeof(uint32_t), dst++) {
284 *rand = arc4random();
285 *dst = *dst ^ *rand++;
286 }
287 KASSERT(len == 0, ("len != 0 (len=%zd)", len));
288 }
289
290 static void
291 g_shsec_start(struct bio *bp)
292 {
293 TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
294 struct g_shsec_softc *sc;
295 struct bio *cbp;
296 uint32_t *dst;
297 ssize_t len;
298 u_int no;
299 int error;
300
301 sc = bp->bio_to->geom->softc;
302 /*
303 * If sc == NULL, provider's error should be set and g_shsec_start()
304 * should not be called at all.
305 */
306 KASSERT(sc != NULL,
307 ("Provider's error should be set (error=%d)(device=%s).",
308 bp->bio_to->error, bp->bio_to->name));
309
310 G_SHSEC_LOGREQ(2, bp, "Request received.");
311
312 switch (bp->bio_cmd) {
313 case BIO_READ:
314 case BIO_WRITE:
315 case BIO_FLUSH:
316 /*
317 * Only those requests are supported.
318 */
319 break;
320 case BIO_DELETE:
321 case BIO_GETATTR:
322 /* To which provider it should be delivered? */
323 default:
324 g_io_deliver(bp, EOPNOTSUPP);
325 return;
326 }
327
328 /*
329 * Allocate all bios first and calculate XOR.
330 */
331 dst = NULL;
332 len = bp->bio_length;
333 if (bp->bio_cmd == BIO_READ)
334 bp->bio_pflags = G_SHSEC_BFLAG_FIRST;
335 for (no = 0; no < sc->sc_ndisks; no++) {
336 cbp = g_clone_bio(bp);
337 if (cbp == NULL) {
338 error = ENOMEM;
339 goto failure;
340 }
341 TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
342
343 /*
344 * Fill in the component buf structure.
345 */
346 cbp->bio_done = g_shsec_done;
347 cbp->bio_data = uma_zalloc(g_shsec_zone, M_NOWAIT);
348 if (cbp->bio_data == NULL) {
349 g_shsec_alloc_failed++;
350 error = ENOMEM;
351 goto failure;
352 }
353 cbp->bio_caller2 = sc->sc_disks[no];
354 if (bp->bio_cmd == BIO_WRITE) {
355 if (no == 0) {
356 dst = (uint32_t *)cbp->bio_data;
357 bcopy(bp->bio_data, dst, len);
358 } else {
359 g_shsec_xor2((uint32_t *)cbp->bio_data, dst,
360 len);
361 }
362 }
363 }
364 /*
365 * Fire off all allocated requests!
366 */
367 while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
368 struct g_consumer *cp;
369
370 TAILQ_REMOVE(&queue, cbp, bio_queue);
371 cp = cbp->bio_caller2;
372 cbp->bio_caller2 = NULL;
373 cbp->bio_to = cp->provider;
374 G_SHSEC_LOGREQ(2, cbp, "Sending request.");
375 g_io_request(cbp, cp);
376 }
377 return;
378 failure:
379 while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
380 TAILQ_REMOVE(&queue, cbp, bio_queue);
381 bp->bio_children--;
382 if (cbp->bio_data != NULL) {
383 bzero(cbp->bio_data, cbp->bio_length);
384 uma_zfree(g_shsec_zone, cbp->bio_data);
385 }
386 g_destroy_bio(cbp);
387 }
388 if (bp->bio_error == 0)
389 bp->bio_error = error;
390 g_io_deliver(bp, bp->bio_error);
391 }
392
393 static void
394 g_shsec_check_and_run(struct g_shsec_softc *sc)
395 {
396 off_t mediasize, ms;
397 u_int no, sectorsize = 0;
398
399 if (g_shsec_nvalid(sc) != sc->sc_ndisks)
400 return;
401
402 sc->sc_provider = g_new_providerf(sc->sc_geom, "shsec/%s", sc->sc_name);
403 /*
404 * Find the smallest disk.
405 */
406 mediasize = sc->sc_disks[0]->provider->mediasize;
407 mediasize -= sc->sc_disks[0]->provider->sectorsize;
408 sectorsize = sc->sc_disks[0]->provider->sectorsize;
409 for (no = 1; no < sc->sc_ndisks; no++) {
410 ms = sc->sc_disks[no]->provider->mediasize;
411 ms -= sc->sc_disks[no]->provider->sectorsize;
412 if (ms < mediasize)
413 mediasize = ms;
414 sectorsize = lcm(sectorsize,
415 sc->sc_disks[no]->provider->sectorsize);
416 }
417 sc->sc_provider->sectorsize = sectorsize;
418 sc->sc_provider->mediasize = mediasize;
419 g_error_provider(sc->sc_provider, 0);
420
421 G_SHSEC_DEBUG(0, "Device %s activated.", sc->sc_name);
422 }
423
424 static int
425 g_shsec_read_metadata(struct g_consumer *cp, struct g_shsec_metadata *md)
426 {
427 struct g_provider *pp;
428 u_char *buf;
429 int error;
430
431 g_topology_assert();
432
433 error = g_access(cp, 1, 0, 0);
434 if (error != 0)
435 return (error);
436 pp = cp->provider;
437 g_topology_unlock();
438 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
439 &error);
440 g_topology_lock();
441 g_access(cp, -1, 0, 0);
442 if (buf == NULL)
443 return (error);
444
445 /* Decode metadata. */
446 shsec_metadata_decode(buf, md);
447 g_free(buf);
448
449 return (0);
450 }
451
452 /*
453 * Add disk to given device.
454 */
455 static int
456 g_shsec_add_disk(struct g_shsec_softc *sc, struct g_provider *pp, u_int no)
457 {
458 struct g_consumer *cp, *fcp;
459 struct g_geom *gp;
460 struct g_shsec_metadata md;
461 int error;
462
463 /* Metadata corrupted? */
464 if (no >= sc->sc_ndisks)
465 return (EINVAL);
466
467 /* Check if disk is not already attached. */
468 if (sc->sc_disks[no] != NULL)
469 return (EEXIST);
470
471 gp = sc->sc_geom;
472 fcp = LIST_FIRST(&gp->consumer);
473
474 cp = g_new_consumer(gp);
475 error = g_attach(cp, pp);
476 if (error != 0) {
477 g_destroy_consumer(cp);
478 return (error);
479 }
480
481 if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) {
482 error = g_access(cp, fcp->acr, fcp->acw, fcp->ace);
483 if (error != 0) {
484 g_detach(cp);
485 g_destroy_consumer(cp);
486 return (error);
487 }
488 }
489
490 /* Reread metadata. */
491 error = g_shsec_read_metadata(cp, &md);
492 if (error != 0)
493 goto fail;
494
495 if (strcmp(md.md_magic, G_SHSEC_MAGIC) != 0 ||
496 strcmp(md.md_name, sc->sc_name) != 0 || md.md_id != sc->sc_id) {
497 G_SHSEC_DEBUG(0, "Metadata on %s changed.", pp->name);
498 goto fail;
499 }
500
501 cp->private = sc;
502 cp->index = no;
503 sc->sc_disks[no] = cp;
504
505 G_SHSEC_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name);
506
507 g_shsec_check_and_run(sc);
508
509 return (0);
510 fail:
511 if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0))
512 g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace);
513 g_detach(cp);
514 g_destroy_consumer(cp);
515 return (error);
516 }
517
518 static struct g_geom *
519 g_shsec_create(struct g_class *mp, const struct g_shsec_metadata *md)
520 {
521 struct g_shsec_softc *sc;
522 struct g_geom *gp;
523 u_int no;
524
525 G_SHSEC_DEBUG(1, "Creating device %s (id=%u).", md->md_name, md->md_id);
526
527 /* Two disks is minimum. */
528 if (md->md_all < 2) {
529 G_SHSEC_DEBUG(0, "Too few disks defined for %s.", md->md_name);
530 return (NULL);
531 }
532
533 /* Check for duplicate unit */
534 LIST_FOREACH(gp, &mp->geom, geom) {
535 sc = gp->softc;
536 if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) {
537 G_SHSEC_DEBUG(0, "Device %s already configured.",
538 sc->sc_name);
539 return (NULL);
540 }
541 }
542 gp = g_new_geomf(mp, "%s", md->md_name);
543 sc = malloc(sizeof(*sc), M_SHSEC, M_WAITOK | M_ZERO);
544 gp->start = g_shsec_start;
545 gp->spoiled = g_shsec_orphan;
546 gp->orphan = g_shsec_orphan;
547 gp->access = g_shsec_access;
548 gp->dumpconf = g_shsec_dumpconf;
549
550 sc->sc_id = md->md_id;
551 sc->sc_ndisks = md->md_all;
552 sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks,
553 M_SHSEC, M_WAITOK | M_ZERO);
554 for (no = 0; no < sc->sc_ndisks; no++)
555 sc->sc_disks[no] = NULL;
556
557 gp->softc = sc;
558 sc->sc_geom = gp;
559 sc->sc_provider = NULL;
560
561 G_SHSEC_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id);
562
563 return (gp);
564 }
565
566 static int
567 g_shsec_destroy(struct g_shsec_softc *sc, boolean_t force)
568 {
569 struct g_provider *pp;
570 struct g_geom *gp;
571 u_int no;
572
573 g_topology_assert();
574
575 if (sc == NULL)
576 return (ENXIO);
577
578 pp = sc->sc_provider;
579 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
580 if (force) {
581 G_SHSEC_DEBUG(0, "Device %s is still open, so it "
582 "can't be definitely removed.", pp->name);
583 } else {
584 G_SHSEC_DEBUG(1,
585 "Device %s is still open (r%dw%de%d).", pp->name,
586 pp->acr, pp->acw, pp->ace);
587 return (EBUSY);
588 }
589 }
590
591 for (no = 0; no < sc->sc_ndisks; no++) {
592 if (sc->sc_disks[no] != NULL)
593 g_shsec_remove_disk(sc->sc_disks[no]);
594 }
595
596 gp = sc->sc_geom;
597 gp->softc = NULL;
598 KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)",
599 gp->name));
600 free(sc->sc_disks, M_SHSEC);
601 free(sc, M_SHSEC);
602
603 pp = LIST_FIRST(&gp->provider);
604 if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0))
605 G_SHSEC_DEBUG(0, "Device %s destroyed.", gp->name);
606
607 g_wither_geom(gp, ENXIO);
608
609 return (0);
610 }
611
612 static int
613 g_shsec_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused,
614 struct g_geom *gp)
615 {
616 struct g_shsec_softc *sc;
617
618 sc = gp->softc;
619 return (g_shsec_destroy(sc, 0));
620 }
621
622 static struct g_geom *
623 g_shsec_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
624 {
625 struct g_shsec_metadata md;
626 struct g_shsec_softc *sc;
627 struct g_consumer *cp;
628 struct g_geom *gp;
629 int error;
630
631 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
632 g_topology_assert();
633
634 /* Skip providers that are already open for writing. */
635 if (pp->acw > 0)
636 return (NULL);
637
638 G_SHSEC_DEBUG(3, "Tasting %s.", pp->name);
639
640 gp = g_new_geomf(mp, "shsec:taste");
641 gp->start = g_shsec_start;
642 gp->access = g_shsec_access;
643 gp->orphan = g_shsec_orphan;
644 cp = g_new_consumer(gp);
645 g_attach(cp, pp);
646 error = g_shsec_read_metadata(cp, &md);
647 g_detach(cp);
648 g_destroy_consumer(cp);
649 g_destroy_geom(gp);
650 if (error != 0)
651 return (NULL);
652 gp = NULL;
653
654 if (strcmp(md.md_magic, G_SHSEC_MAGIC) != 0)
655 return (NULL);
656 if (md.md_version > G_SHSEC_VERSION) {
657 G_SHSEC_DEBUG(0, "Kernel module is too old to handle %s.\n",
658 pp->name);
659 return (NULL);
660 }
661 /*
662 * Backward compatibility:
663 */
664 /* There was no md_provsize field in earlier versions of metadata. */
665 if (md.md_version < 1)
666 md.md_provsize = pp->mediasize;
667
668 if (md.md_provider[0] != '\0' &&
669 !g_compare_names(md.md_provider, pp->name))
670 return (NULL);
671 if (md.md_provsize != pp->mediasize)
672 return (NULL);
673
674 /*
675 * Let's check if device already exists.
676 */
677 sc = NULL;
678 LIST_FOREACH(gp, &mp->geom, geom) {
679 sc = gp->softc;
680 if (sc == NULL)
681 continue;
682 if (strcmp(md.md_name, sc->sc_name) != 0)
683 continue;
684 if (md.md_id != sc->sc_id)
685 continue;
686 break;
687 }
688 if (gp != NULL) {
689 G_SHSEC_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
690 error = g_shsec_add_disk(sc, pp, md.md_no);
691 if (error != 0) {
692 G_SHSEC_DEBUG(0, "Cannot add disk %s to %s (error=%d).",
693 pp->name, gp->name, error);
694 return (NULL);
695 }
696 } else {
697 gp = g_shsec_create(mp, &md);
698 if (gp == NULL) {
699 G_SHSEC_DEBUG(0, "Cannot create device %s.", md.md_name);
700 return (NULL);
701 }
702 sc = gp->softc;
703 G_SHSEC_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
704 error = g_shsec_add_disk(sc, pp, md.md_no);
705 if (error != 0) {
706 G_SHSEC_DEBUG(0, "Cannot add disk %s to %s (error=%d).",
707 pp->name, gp->name, error);
708 g_shsec_destroy(sc, 1);
709 return (NULL);
710 }
711 }
712 return (gp);
713 }
714
715 static struct g_shsec_softc *
716 g_shsec_find_device(struct g_class *mp, const char *name)
717 {
718 struct g_shsec_softc *sc;
719 struct g_geom *gp;
720
721 LIST_FOREACH(gp, &mp->geom, geom) {
722 sc = gp->softc;
723 if (sc == NULL)
724 continue;
725 if (strcmp(sc->sc_name, name) == 0)
726 return (sc);
727 }
728 return (NULL);
729 }
730
731 static void
732 g_shsec_ctl_destroy(struct gctl_req *req, struct g_class *mp)
733 {
734 struct g_shsec_softc *sc;
735 int *force, *nargs, error;
736 const char *name;
737 char param[16];
738 u_int i;
739
740 g_topology_assert();
741
742 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
743 if (nargs == NULL) {
744 gctl_error(req, "No '%s' argument.", "nargs");
745 return;
746 }
747 if (*nargs <= 0) {
748 gctl_error(req, "Missing device(s).");
749 return;
750 }
751 force = gctl_get_paraml(req, "force", sizeof(*force));
752 if (force == NULL) {
753 gctl_error(req, "No '%s' argument.", "force");
754 return;
755 }
756
757 for (i = 0; i < (u_int)*nargs; i++) {
758 snprintf(param, sizeof(param), "arg%u", i);
759 name = gctl_get_asciiparam(req, param);
760 if (name == NULL) {
761 gctl_error(req, "No 'arg%u' argument.", i);
762 return;
763 }
764 sc = g_shsec_find_device(mp, name);
765 if (sc == NULL) {
766 gctl_error(req, "No such device: %s.", name);
767 return;
768 }
769 error = g_shsec_destroy(sc, *force);
770 if (error != 0) {
771 gctl_error(req, "Cannot destroy device %s (error=%d).",
772 sc->sc_name, error);
773 return;
774 }
775 }
776 }
777
778 static void
779 g_shsec_config(struct gctl_req *req, struct g_class *mp, const char *verb)
780 {
781 uint32_t *version;
782
783 g_topology_assert();
784
785 version = gctl_get_paraml(req, "version", sizeof(*version));
786 if (version == NULL) {
787 gctl_error(req, "No '%s' argument.", "version");
788 return;
789 }
790 if (*version != G_SHSEC_VERSION) {
791 gctl_error(req, "Userland and kernel parts are out of sync.");
792 return;
793 }
794
795 if (strcmp(verb, "stop") == 0) {
796 g_shsec_ctl_destroy(req, mp);
797 return;
798 }
799
800 gctl_error(req, "Unknown verb.");
801 }
802
803 static void
804 g_shsec_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
805 struct g_consumer *cp, struct g_provider *pp)
806 {
807 struct g_shsec_softc *sc;
808
809 sc = gp->softc;
810 if (sc == NULL)
811 return;
812 if (pp != NULL) {
813 /* Nothing here. */
814 } else if (cp != NULL) {
815 sbuf_printf(sb, "%s<Number>%u</Number>\n", indent,
816 (u_int)cp->index);
817 } else {
818 sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id);
819 sbuf_printf(sb, "%s<Status>Total=%u, Online=%u</Status>\n",
820 indent, sc->sc_ndisks, g_shsec_nvalid(sc));
821 sbuf_printf(sb, "%s<State>", indent);
822 if (sc->sc_provider != NULL && sc->sc_provider->error == 0)
823 sbuf_printf(sb, "UP");
824 else
825 sbuf_printf(sb, "DOWN");
826 sbuf_printf(sb, "</State>\n");
827 }
828 }
829
830 DECLARE_GEOM_CLASS(g_shsec_class, g_shsec);
831 MODULE_VERSION(geom_shsec, 0);
Cache object: e9f9bbd9818945233bcb89a66835852d
|