1 /*-
2 * Copyright (c) 2011 Alexander Motin <mav@FreeBSD.org>
3 * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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 AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27 /*
28 * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the
29 * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM
30 * itself, all of which is most gratefully acknowledged.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: releng/8.3/sys/geom/multipath/g_multipath.c 229309 2012-01-02 19:27:23Z mav $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/bio.h>
42 #include <sys/sysctl.h>
43 #include <sys/kthread.h>
44 #include <sys/malloc.h>
45 #include <geom/geom.h>
46 #include <geom/multipath/g_multipath.h>
47
48
49 SYSCTL_DECL(_kern_geom);
50 SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0,
51 "GEOM_MULTIPATH tunables");
52 static u_int g_multipath_debug = 0;
53 SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW,
54 &g_multipath_debug, 0, "Debug level");
55 static u_int g_multipath_exclusive = 1;
56 SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW,
57 &g_multipath_exclusive, 0, "Exclusively open providers");
58
59 static enum {
60 GKT_NIL,
61 GKT_RUN,
62 GKT_DIE
63 } g_multipath_kt_state;
64 static struct bio_queue_head gmtbq;
65 static struct mtx gmtbq_mtx;
66
67 static void g_multipath_orphan(struct g_consumer *);
68 static void g_multipath_start(struct bio *);
69 static void g_multipath_done(struct bio *);
70 static void g_multipath_done_error(struct bio *);
71 static void g_multipath_kt(void *);
72
73 static int g_multipath_destroy(struct g_geom *);
74 static int
75 g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
76
77 static struct g_geom *g_multipath_find_geom(struct g_class *, const char *);
78 static int g_multipath_rotate(struct g_geom *);
79
80 static g_taste_t g_multipath_taste;
81 static g_ctl_req_t g_multipath_config;
82 static g_init_t g_multipath_init;
83 static g_fini_t g_multipath_fini;
84 static g_dumpconf_t g_multipath_dumpconf;
85
86 struct g_class g_multipath_class = {
87 .name = G_MULTIPATH_CLASS_NAME,
88 .version = G_VERSION,
89 .ctlreq = g_multipath_config,
90 .taste = g_multipath_taste,
91 .destroy_geom = g_multipath_destroy_geom,
92 .init = g_multipath_init,
93 .fini = g_multipath_fini
94 };
95
96 #define MP_FAIL 0x00000001
97 #define MP_LOST 0x00000002
98 #define MP_NEW 0x00000004
99 #define MP_POSTED 0x00000008
100 #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW)
101 #define MP_IDLE 0x00000010
102 #define MP_IDLE_MASK 0xfffffff0
103
104 static int
105 g_multipath_good(struct g_geom *gp)
106 {
107 struct g_consumer *cp;
108 int n = 0;
109
110 LIST_FOREACH(cp, &gp->consumer, consumer) {
111 if ((cp->index & MP_BAD) == 0)
112 n++;
113 }
114 return (n);
115 }
116
117 static void
118 g_multipath_fault(struct g_consumer *cp, int cause)
119 {
120 struct g_multipath_softc *sc;
121 struct g_consumer *lcp;
122 struct g_geom *gp;
123
124 gp = cp->geom;
125 sc = gp->softc;
126 cp->index |= cause;
127 if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) {
128 LIST_FOREACH(lcp, &gp->consumer, consumer) {
129 if (lcp->provider == NULL ||
130 (lcp->index & (MP_LOST | MP_NEW)))
131 continue;
132 if (sc->sc_ndisks > 1 && lcp == cp)
133 continue;
134 printf("GEOM_MULTIPATH: "
135 "all paths in %s were marked FAIL, restore %s\n",
136 sc->sc_name, lcp->provider->name);
137 lcp->index &= ~MP_FAIL;
138 }
139 }
140 if (cp != sc->sc_active)
141 return;
142 sc->sc_active = NULL;
143 LIST_FOREACH(lcp, &gp->consumer, consumer) {
144 if ((lcp->index & MP_BAD) == 0) {
145 sc->sc_active = lcp;
146 break;
147 }
148 }
149 if (sc->sc_active == NULL) {
150 printf("GEOM_MULTIPATH: out of providers for %s\n",
151 sc->sc_name);
152 } else if (!sc->sc_active_active) {
153 printf("GEOM_MULTIPATH: %s is now active path in %s\n",
154 sc->sc_active->provider->name, sc->sc_name);
155 }
156 }
157
158 static struct g_consumer *
159 g_multipath_choose(struct g_geom *gp)
160 {
161 struct g_multipath_softc *sc;
162 struct g_consumer *best, *cp;
163
164 sc = gp->softc;
165 if (!sc->sc_active_active)
166 return (sc->sc_active);
167 best = NULL;
168 LIST_FOREACH(cp, &gp->consumer, consumer) {
169 if (cp->index & MP_BAD)
170 continue;
171 cp->index += MP_IDLE;
172 if (best == NULL || cp->private < best->private ||
173 (cp->private == best->private && cp->index > best->index))
174 best = cp;
175 }
176 if (best != NULL)
177 best->index &= ~MP_IDLE_MASK;
178 return (best);
179 }
180
181 static void
182 g_mpd(void *arg, int flags __unused)
183 {
184 struct g_geom *gp;
185 struct g_multipath_softc *sc;
186 struct g_consumer *cp;
187 int w;
188
189 g_topology_assert();
190 cp = arg;
191 gp = cp->geom;
192 if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) {
193 w = cp->acw;
194 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
195 if (w > 0 && cp->provider != NULL &&
196 (cp->provider->geom->flags & G_GEOM_WITHER) == 0) {
197 g_post_event(g_mpd, cp, M_WAITOK, NULL);
198 return;
199 }
200 }
201 sc = gp->softc;
202 mtx_lock(&sc->sc_mtx);
203 if (cp->provider) {
204 printf("GEOM_MULTIPATH: %s removed from %s\n",
205 cp->provider->name, gp->name);
206 g_detach(cp);
207 }
208 g_destroy_consumer(cp);
209 mtx_unlock(&sc->sc_mtx);
210 if (LIST_EMPTY(&gp->consumer))
211 g_multipath_destroy(gp);
212 }
213
214 static void
215 g_multipath_orphan(struct g_consumer *cp)
216 {
217 struct g_multipath_softc *sc;
218 uintptr_t *cnt;
219
220 g_topology_assert();
221 printf("GEOM_MULTIPATH: %s in %s was disconnected\n",
222 cp->provider->name, cp->geom->name);
223 sc = cp->geom->softc;
224 cnt = (uintptr_t *)&cp->private;
225 mtx_lock(&sc->sc_mtx);
226 sc->sc_ndisks--;
227 g_multipath_fault(cp, MP_LOST);
228 if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
229 cp->index |= MP_POSTED;
230 mtx_unlock(&sc->sc_mtx);
231 g_mpd(cp, 0);
232 } else
233 mtx_unlock(&sc->sc_mtx);
234 }
235
236 static void
237 g_multipath_start(struct bio *bp)
238 {
239 struct g_multipath_softc *sc;
240 struct g_geom *gp;
241 struct g_consumer *cp;
242 struct bio *cbp;
243 uintptr_t *cnt;
244
245 gp = bp->bio_to->geom;
246 sc = gp->softc;
247 KASSERT(sc != NULL, ("NULL sc"));
248 cbp = g_clone_bio(bp);
249 if (cbp == NULL) {
250 g_io_deliver(bp, ENOMEM);
251 return;
252 }
253 mtx_lock(&sc->sc_mtx);
254 cp = g_multipath_choose(gp);
255 if (cp == NULL) {
256 mtx_unlock(&sc->sc_mtx);
257 g_destroy_bio(cbp);
258 g_io_deliver(bp, ENXIO);
259 return;
260 }
261 if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks)
262 bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks;
263 cnt = (uintptr_t *)&cp->private;
264 (*cnt)++;
265 mtx_unlock(&sc->sc_mtx);
266 cbp->bio_done = g_multipath_done;
267 g_io_request(cbp, cp);
268 }
269
270 static void
271 g_multipath_done(struct bio *bp)
272 {
273 struct g_multipath_softc *sc;
274 struct g_consumer *cp;
275 uintptr_t *cnt;
276
277 if (bp->bio_error == ENXIO || bp->bio_error == EIO) {
278 mtx_lock(&gmtbq_mtx);
279 bioq_insert_tail(&gmtbq, bp);
280 mtx_unlock(&gmtbq_mtx);
281 wakeup(&g_multipath_kt_state);
282 } else {
283 cp = bp->bio_from;
284 sc = cp->geom->softc;
285 cnt = (uintptr_t *)&cp->private;
286 mtx_lock(&sc->sc_mtx);
287 (*cnt)--;
288 if (*cnt == 0 && (cp->index & MP_LOST)) {
289 cp->index |= MP_POSTED;
290 mtx_unlock(&sc->sc_mtx);
291 g_post_event(g_mpd, cp, M_WAITOK, NULL);
292 } else
293 mtx_unlock(&sc->sc_mtx);
294 g_std_done(bp);
295 }
296 }
297
298 static void
299 g_multipath_done_error(struct bio *bp)
300 {
301 struct bio *pbp;
302 struct g_geom *gp;
303 struct g_multipath_softc *sc;
304 struct g_consumer *cp;
305 struct g_provider *pp;
306 uintptr_t *cnt;
307
308 /*
309 * If we had a failure, we have to check first to see
310 * whether the consumer it failed on was the currently
311 * active consumer (i.e., this is the first in perhaps
312 * a number of failures). If so, we then switch consumers
313 * to the next available consumer.
314 */
315
316 pbp = bp->bio_parent;
317 gp = pbp->bio_to->geom;
318 sc = gp->softc;
319 cp = bp->bio_from;
320 pp = cp->provider;
321 cnt = (uintptr_t *)&cp->private;
322
323 mtx_lock(&sc->sc_mtx);
324 printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n",
325 bp->bio_error, pp->name, sc->sc_name);
326 g_multipath_fault(cp, MP_FAIL);
327 (*cnt)--;
328 if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) {
329 cp->index |= MP_POSTED;
330 mtx_unlock(&sc->sc_mtx);
331 g_post_event(g_mpd, cp, M_WAITOK, NULL);
332 } else
333 mtx_unlock(&sc->sc_mtx);
334
335 /*
336 * If we can fruitfully restart the I/O, do so.
337 */
338 if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) {
339 pbp->bio_inbed++;
340 g_destroy_bio(bp);
341 g_multipath_start(pbp);
342 } else {
343 g_std_done(bp);
344 }
345 }
346
347 static void
348 g_multipath_kt(void *arg)
349 {
350
351 g_multipath_kt_state = GKT_RUN;
352 mtx_lock(&gmtbq_mtx);
353 while (g_multipath_kt_state == GKT_RUN) {
354 for (;;) {
355 struct bio *bp;
356
357 bp = bioq_takefirst(&gmtbq);
358 if (bp == NULL)
359 break;
360 mtx_unlock(&gmtbq_mtx);
361 g_multipath_done_error(bp);
362 mtx_lock(&gmtbq_mtx);
363 }
364 msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
365 "gkt:wait", hz / 10);
366 }
367 mtx_unlock(&gmtbq_mtx);
368 wakeup(&g_multipath_kt_state);
369 kproc_exit(0);
370 }
371
372
373 static int
374 g_multipath_access(struct g_provider *pp, int dr, int dw, int de)
375 {
376 struct g_geom *gp;
377 struct g_consumer *cp, *badcp = NULL;
378 struct g_multipath_softc *sc;
379 int error;
380
381 gp = pp->geom;
382
383 LIST_FOREACH(cp, &gp->consumer, consumer) {
384 error = g_access(cp, dr, dw, de);
385 if (error) {
386 badcp = cp;
387 goto fail;
388 }
389 }
390 sc = gp->softc;
391 sc->sc_opened += dr + dw + de;
392 if (sc->sc_stopping && sc->sc_opened == 0)
393 g_multipath_destroy(gp);
394 return (0);
395
396 fail:
397 LIST_FOREACH(cp, &gp->consumer, consumer) {
398 if (cp == badcp)
399 break;
400 (void) g_access(cp, -dr, -dw, -de);
401 }
402 return (error);
403 }
404
405 static struct g_geom *
406 g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
407 {
408 struct g_multipath_softc *sc;
409 struct g_geom *gp;
410 struct g_provider *pp;
411
412 g_topology_assert();
413
414 LIST_FOREACH(gp, &mp->geom, geom) {
415 sc = gp->softc;
416 if (sc == NULL || sc->sc_stopping)
417 continue;
418 if (strcmp(gp->name, md->md_name) == 0) {
419 printf("GEOM_MULTIPATH: name %s already exists\n",
420 md->md_name);
421 return (NULL);
422 }
423 }
424
425 gp = g_new_geomf(mp, md->md_name);
426 sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
427 mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF);
428 memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
429 memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
430 sc->sc_active_active = md->md_active_active;
431 gp->softc = sc;
432 gp->start = g_multipath_start;
433 gp->orphan = g_multipath_orphan;
434 gp->access = g_multipath_access;
435 gp->dumpconf = g_multipath_dumpconf;
436
437 pp = g_new_providerf(gp, "multipath/%s", md->md_name);
438 if (md->md_size != 0) {
439 pp->mediasize = md->md_size -
440 ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0);
441 pp->sectorsize = md->md_sectorsize;
442 }
443 sc->sc_pp = pp;
444 g_error_provider(pp, 0);
445 printf("GEOM_MULTIPATH: %s created\n", gp->name);
446 return (gp);
447 }
448
449 static int
450 g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
451 {
452 struct g_multipath_softc *sc;
453 struct g_consumer *cp, *nxtcp;
454 int error, acr, acw, ace;
455
456 g_topology_assert();
457
458 sc = gp->softc;
459 KASSERT(sc, ("no softc"));
460
461 /*
462 * Make sure that the passed provider isn't already attached
463 */
464 LIST_FOREACH(cp, &gp->consumer, consumer) {
465 if (cp->provider == pp)
466 break;
467 }
468 if (cp) {
469 printf("GEOM_MULTIPATH: provider %s already attached to %s\n",
470 pp->name, gp->name);
471 return (EEXIST);
472 }
473 nxtcp = LIST_FIRST(&gp->consumer);
474 cp = g_new_consumer(gp);
475 cp->private = NULL;
476 cp->index = MP_NEW;
477 error = g_attach(cp, pp);
478 if (error != 0) {
479 printf("GEOM_MULTIPATH: cannot attach %s to %s",
480 pp->name, sc->sc_name);
481 g_destroy_consumer(cp);
482 return (error);
483 }
484
485 /*
486 * Set access permissions on new consumer to match other consumers
487 */
488 if (sc->sc_pp) {
489 acr = sc->sc_pp->acr;
490 acw = sc->sc_pp->acw;
491 ace = sc->sc_pp->ace;
492 } else
493 acr = acw = ace = 0;
494 if (g_multipath_exclusive) {
495 acr++;
496 acw++;
497 ace++;
498 }
499 error = g_access(cp, acr, acw, ace);
500 if (error) {
501 printf("GEOM_MULTIPATH: cannot set access in "
502 "attaching %s to %s (%d)\n",
503 pp->name, sc->sc_name, error);
504 g_detach(cp);
505 g_destroy_consumer(cp);
506 return (error);
507 }
508 if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) {
509 sc->sc_pp->mediasize = pp->mediasize -
510 ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0);
511 sc->sc_pp->sectorsize = pp->sectorsize;
512 }
513 if (sc->sc_pp != NULL &&
514 sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) {
515 sc->sc_pp->stripesize = pp->stripesize;
516 sc->sc_pp->stripeoffset = pp->stripeoffset;
517 }
518 mtx_lock(&sc->sc_mtx);
519 cp->index = 0;
520 sc->sc_ndisks++;
521 mtx_unlock(&sc->sc_mtx);
522 printf("GEOM_MULTIPATH: %s added to %s\n",
523 pp->name, sc->sc_name);
524 if (sc->sc_active == NULL) {
525 sc->sc_active = cp;
526 if (!sc->sc_active_active)
527 printf("GEOM_MULTIPATH: %s is now active path in %s\n",
528 pp->name, sc->sc_name);
529 }
530 return (0);
531 }
532
533 static int
534 g_multipath_destroy(struct g_geom *gp)
535 {
536 struct g_multipath_softc *sc;
537 struct g_consumer *cp, *cp1;
538
539 g_topology_assert();
540 if (gp->softc == NULL)
541 return (ENXIO);
542 sc = gp->softc;
543 if (!sc->sc_stopping) {
544 printf("GEOM_MULTIPATH: destroying %s\n", gp->name);
545 sc->sc_stopping = 1;
546 }
547 if (sc->sc_opened != 0) {
548 if (sc->sc_pp != NULL) {
549 g_wither_provider(sc->sc_pp, ENXIO);
550 sc->sc_pp = NULL;
551 }
552 return (EINPROGRESS);
553 }
554 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
555 mtx_lock(&sc->sc_mtx);
556 if ((cp->index & MP_POSTED) == 0) {
557 cp->index |= MP_POSTED;
558 mtx_unlock(&sc->sc_mtx);
559 g_mpd(cp, 0);
560 if (cp1 == NULL)
561 return(0); /* Recursion happened. */
562 } else
563 mtx_unlock(&sc->sc_mtx);
564 }
565 if (!LIST_EMPTY(&gp->consumer))
566 return (EINPROGRESS);
567 mtx_destroy(&sc->sc_mtx);
568 g_free(gp->softc);
569 gp->softc = NULL;
570 printf("GEOM_MULTIPATH: %s destroyed\n", gp->name);
571 g_wither_geom(gp, ENXIO);
572 return (0);
573 }
574
575 static int
576 g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp,
577 struct g_geom *gp)
578 {
579
580 return (g_multipath_destroy(gp));
581 }
582
583 static int
584 g_multipath_rotate(struct g_geom *gp)
585 {
586 struct g_consumer *lcp;
587 struct g_multipath_softc *sc = gp->softc;
588
589 g_topology_assert();
590 if (sc == NULL)
591 return (ENXIO);
592 LIST_FOREACH(lcp, &gp->consumer, consumer) {
593 if ((lcp->index & MP_BAD) == 0) {
594 if (sc->sc_active != lcp)
595 break;
596 }
597 }
598 if (lcp) {
599 sc->sc_active = lcp;
600 if (!sc->sc_active_active)
601 printf("GEOM_MULTIPATH: %s is now active path in %s\n",
602 lcp->provider->name, sc->sc_name);
603 }
604 return (0);
605 }
606
607 static void
608 g_multipath_init(struct g_class *mp)
609 {
610 bioq_init(&gmtbq);
611 mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF);
612 if (kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt") == 0)
613 g_multipath_kt_state = GKT_RUN;
614 }
615
616 static void
617 g_multipath_fini(struct g_class *mp)
618 {
619 if (g_multipath_kt_state == GKT_RUN) {
620 mtx_lock(&gmtbq_mtx);
621 g_multipath_kt_state = GKT_DIE;
622 wakeup(&g_multipath_kt_state);
623 msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
624 "gmp:fini", 0);
625 mtx_unlock(&gmtbq_mtx);
626 }
627 }
628
629 static int
630 g_multipath_read_metadata(struct g_consumer *cp,
631 struct g_multipath_metadata *md)
632 {
633 struct g_provider *pp;
634 u_char *buf;
635 int error;
636
637 g_topology_assert();
638 error = g_access(cp, 1, 0, 0);
639 if (error != 0)
640 return (error);
641 pp = cp->provider;
642 g_topology_unlock();
643 buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
644 pp->sectorsize, &error);
645 g_topology_lock();
646 g_access(cp, -1, 0, 0);
647 if (buf == NULL)
648 return (error);
649 multipath_metadata_decode(buf, md);
650 g_free(buf);
651 return (0);
652 }
653
654 static struct g_geom *
655 g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
656 {
657 struct g_multipath_metadata md;
658 struct g_multipath_softc *sc;
659 struct g_consumer *cp;
660 struct g_geom *gp, *gp1;
661 int error, isnew;
662
663 g_topology_assert();
664
665 gp = g_new_geomf(mp, "multipath:taste");
666 gp->start = g_multipath_start;
667 gp->access = g_multipath_access;
668 gp->orphan = g_multipath_orphan;
669 cp = g_new_consumer(gp);
670 g_attach(cp, pp);
671 error = g_multipath_read_metadata(cp, &md);
672 g_detach(cp);
673 g_destroy_consumer(cp);
674 g_destroy_geom(gp);
675 if (error != 0)
676 return (NULL);
677 gp = NULL;
678
679 if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
680 if (g_multipath_debug)
681 printf("%s is not MULTIPATH\n", pp->name);
682 return (NULL);
683 }
684 if (md.md_version != G_MULTIPATH_VERSION) {
685 printf("%s has version %d multipath id- this module is version "
686 " %d: rejecting\n", pp->name, md.md_version,
687 G_MULTIPATH_VERSION);
688 return (NULL);
689 }
690 if (md.md_size != 0 && md.md_size != pp->mediasize)
691 return (NULL);
692 if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize)
693 return (NULL);
694 if (g_multipath_debug)
695 printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid);
696
697 /*
698 * Let's check if such a device already is present. We check against
699 * uuid alone first because that's the true distinguishor. If that
700 * passes, then we check for name conflicts. If there are conflicts,
701 * modify the name.
702 *
703 * The whole purpose of this is to solve the problem that people don't
704 * pick good unique names, but good unique names (like uuids) are a
705 * pain to use. So, we allow people to build GEOMs with friendly names
706 * and uuids, and modify the names in case there's a collision.
707 */
708 sc = NULL;
709 LIST_FOREACH(gp, &mp->geom, geom) {
710 sc = gp->softc;
711 if (sc == NULL || sc->sc_stopping)
712 continue;
713 if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0)
714 break;
715 }
716
717 LIST_FOREACH(gp1, &mp->geom, geom) {
718 if (gp1 == gp)
719 continue;
720 sc = gp1->softc;
721 if (sc == NULL || sc->sc_stopping)
722 continue;
723 if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0)
724 break;
725 }
726
727 /*
728 * If gp is NULL, we had no extant MULTIPATH geom with this uuid.
729 *
730 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant
731 * with the same name (but a different UUID).
732 *
733 * If gp is NULL, then modify the name with a random number and
734 * complain, but allow the creation of the geom to continue.
735 *
736 * If gp is *not* NULL, just use the geom's name as we're attaching
737 * this disk to the (previously generated) name.
738 */
739
740 if (gp1) {
741 sc = gp1->softc;
742 if (gp == NULL) {
743 char buf[16];
744 u_long rand = random();
745
746 snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand);
747 printf("GEOM_MULTIPATH: geom %s/%s exists already\n",
748 sc->sc_name, sc->sc_uuid);
749 printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
750 md.md_uuid, buf);
751 strlcpy(md.md_name, buf, sizeof(md.md_name));
752 } else {
753 strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
754 }
755 }
756
757 if (gp == NULL) {
758 gp = g_multipath_create(mp, &md);
759 if (gp == NULL) {
760 printf("GEOM_MULTIPATH: cannot create geom %s/%s\n",
761 md.md_name, md.md_uuid);
762 return (NULL);
763 }
764 isnew = 1;
765 } else {
766 isnew = 0;
767 }
768
769 sc = gp->softc;
770 KASSERT(sc != NULL, ("sc is NULL"));
771 error = g_multipath_add_disk(gp, pp);
772 if (error != 0) {
773 if (isnew)
774 g_multipath_destroy(gp);
775 return (NULL);
776 }
777 return (gp);
778 }
779
780 static void
781 g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp,
782 const char *name)
783 {
784 struct g_multipath_softc *sc;
785 struct g_geom *gp;
786 struct g_consumer *cp;
787 struct g_provider *pp;
788 const char *mpname;
789 static const char devpf[6] = "/dev/";
790
791 g_topology_assert();
792
793 mpname = gctl_get_asciiparam(req, "arg0");
794 if (mpname == NULL) {
795 gctl_error(req, "No 'arg0' argument");
796 return;
797 }
798 gp = g_multipath_find_geom(mp, mpname);
799 if (gp == NULL) {
800 gctl_error(req, "Device %s is invalid", mpname);
801 return;
802 }
803 sc = gp->softc;
804
805 if (strncmp(name, devpf, 5) == 0)
806 name += 5;
807 pp = g_provider_by_name(name);
808 if (pp == NULL) {
809 gctl_error(req, "Provider %s is invalid", name);
810 return;
811 }
812
813 /*
814 * Check to make sure parameters match.
815 */
816 LIST_FOREACH(cp, &gp->consumer, consumer) {
817 if (cp->provider == pp) {
818 gctl_error(req, "provider %s is already there",
819 pp->name);
820 return;
821 }
822 }
823 if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 &&
824 sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0)
825 != pp->mediasize) {
826 gctl_error(req, "Providers size mismatch %jd != %jd",
827 (intmax_t) sc->sc_pp->mediasize +
828 (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0),
829 (intmax_t) pp->mediasize);
830 return;
831 }
832 if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 &&
833 sc->sc_pp->sectorsize != pp->sectorsize) {
834 gctl_error(req, "Providers sectorsize mismatch %u != %u",
835 sc->sc_pp->sectorsize, pp->sectorsize);
836 return;
837 }
838
839 /*
840 * Now add....
841 */
842 (void) g_multipath_add_disk(gp, pp);
843 }
844
845 static void
846 g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp)
847 {
848 struct g_multipath_softc *sc;
849 struct g_geom *gp;
850 const char *mpname, *name;
851
852 mpname = gctl_get_asciiparam(req, "arg0");
853 if (mpname == NULL) {
854 gctl_error(req, "No 'arg0' argument");
855 return;
856 }
857 gp = g_multipath_find_geom(mp, mpname);
858 if (gp == NULL) {
859 gctl_error(req, "Device %s not found", mpname);
860 return;
861 }
862 sc = gp->softc;
863
864 name = gctl_get_asciiparam(req, "arg1");
865 if (name == NULL) {
866 gctl_error(req, "No 'arg1' argument");
867 return;
868 }
869 g_multipath_ctl_add_name(req, mp, name);
870 }
871
872 static void
873 g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
874 {
875 struct g_multipath_metadata md;
876 struct g_multipath_softc *sc;
877 struct g_geom *gp;
878 const char *mpname, *name;
879 char param[16];
880 int *nargs, i, *active_active;
881
882 g_topology_assert();
883
884 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
885 if (*nargs < 2) {
886 gctl_error(req, "wrong number of arguments.");
887 return;
888 }
889
890 mpname = gctl_get_asciiparam(req, "arg0");
891 if (mpname == NULL) {
892 gctl_error(req, "No 'arg0' argument");
893 return;
894 }
895 gp = g_multipath_find_geom(mp, mpname);
896 if (gp != NULL) {
897 gctl_error(req, "Device %s already exist", mpname);
898 return;
899 }
900 sc = gp->softc;
901
902 memset(&md, 0, sizeof(md));
903 strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
904 md.md_version = G_MULTIPATH_VERSION;
905 strlcpy(md.md_name, mpname, sizeof(md.md_name));
906 md.md_size = 0;
907 md.md_sectorsize = 0;
908 md.md_uuid[0] = 0;
909 active_active = gctl_get_paraml(req, "active_active",
910 sizeof(*active_active));
911 md.md_active_active =
912 (active_active == NULL || *active_active == 0) ? 0 : 1;
913 gp = g_multipath_create(mp, &md);
914 if (gp == NULL) {
915 gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n",
916 md.md_name, md.md_uuid);
917 return;
918 }
919 sc = gp->softc;
920
921 for (i = 1; i < *nargs; i++) {
922 snprintf(param, sizeof(param), "arg%d", i);
923 name = gctl_get_asciiparam(req, param);
924 g_multipath_ctl_add_name(req, mp, name);
925 }
926
927 if (sc->sc_ndisks != (*nargs - 1))
928 g_multipath_destroy(gp);
929 }
930
931 static void
932 g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail)
933 {
934 struct g_multipath_softc *sc;
935 struct g_geom *gp;
936 struct g_consumer *cp;
937 const char *mpname, *name;
938 int found;
939
940 mpname = gctl_get_asciiparam(req, "arg0");
941 if (mpname == NULL) {
942 gctl_error(req, "No 'arg0' argument");
943 return;
944 }
945 gp = g_multipath_find_geom(mp, mpname);
946 if (gp == NULL) {
947 gctl_error(req, "Device %s not found", mpname);
948 return;
949 }
950 sc = gp->softc;
951
952 name = gctl_get_asciiparam(req, "arg1");
953 if (name == NULL) {
954 gctl_error(req, "No 'arg1' argument");
955 return;
956 }
957
958 found = 0;
959 mtx_lock(&sc->sc_mtx);
960 LIST_FOREACH(cp, &gp->consumer, consumer) {
961 if (cp->provider != NULL &&
962 strcmp(cp->provider->name, name) == 0 &&
963 (cp->index & MP_LOST) == 0) {
964 found = 1;
965 printf("GEOM_MULTIPATH: %s in %s is marked %s.\n",
966 name, sc->sc_name, fail ? "FAIL" : "OK");
967 if (fail) {
968 g_multipath_fault(cp, MP_FAIL);
969 } else {
970 cp->index &= ~MP_FAIL;
971 }
972 }
973 }
974 mtx_unlock(&sc->sc_mtx);
975 if (found == 0)
976 gctl_error(req, "Provider %s not found", name);
977 }
978
979 static void
980 g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp)
981 {
982 struct g_multipath_softc *sc;
983 struct g_geom *gp;
984 struct g_consumer *cp, *cp1;
985 const char *mpname, *name;
986 uintptr_t *cnt;
987 int found;
988
989 mpname = gctl_get_asciiparam(req, "arg0");
990 if (mpname == NULL) {
991 gctl_error(req, "No 'arg0' argument");
992 return;
993 }
994 gp = g_multipath_find_geom(mp, mpname);
995 if (gp == NULL) {
996 gctl_error(req, "Device %s not found", mpname);
997 return;
998 }
999 sc = gp->softc;
1000
1001 name = gctl_get_asciiparam(req, "arg1");
1002 if (name == NULL) {
1003 gctl_error(req, "No 'arg1' argument");
1004 return;
1005 }
1006
1007 found = 0;
1008 mtx_lock(&sc->sc_mtx);
1009 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
1010 if (cp->provider != NULL &&
1011 strcmp(cp->provider->name, name) == 0 &&
1012 (cp->index & MP_LOST) == 0) {
1013 found = 1;
1014 printf("GEOM_MULTIPATH: removing %s from %s\n",
1015 cp->provider->name, cp->geom->name);
1016 sc->sc_ndisks--;
1017 g_multipath_fault(cp, MP_LOST);
1018 cnt = (uintptr_t *)&cp->private;
1019 if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
1020 cp->index |= MP_POSTED;
1021 mtx_unlock(&sc->sc_mtx);
1022 g_mpd(cp, 0);
1023 if (cp1 == NULL)
1024 return; /* Recursion happened. */
1025 mtx_lock(&sc->sc_mtx);
1026 }
1027 }
1028 }
1029 mtx_unlock(&sc->sc_mtx);
1030 if (found == 0)
1031 gctl_error(req, "Provider %s not found", name);
1032 }
1033
1034 static struct g_geom *
1035 g_multipath_find_geom(struct g_class *mp, const char *name)
1036 {
1037 struct g_geom *gp;
1038 struct g_multipath_softc *sc;
1039
1040 LIST_FOREACH(gp, &mp->geom, geom) {
1041 sc = gp->softc;
1042 if (sc == NULL || sc->sc_stopping)
1043 continue;
1044 if (strcmp(gp->name, name) == 0)
1045 return (gp);
1046 }
1047 return (NULL);
1048 }
1049
1050 static void
1051 g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp)
1052 {
1053 struct g_geom *gp;
1054 const char *name;
1055 int error;
1056
1057 g_topology_assert();
1058
1059 name = gctl_get_asciiparam(req, "arg0");
1060 if (name == NULL) {
1061 gctl_error(req, "No 'arg0' argument");
1062 return;
1063 }
1064 gp = g_multipath_find_geom(mp, name);
1065 if (gp == NULL) {
1066 gctl_error(req, "Device %s is invalid", name);
1067 return;
1068 }
1069 error = g_multipath_destroy(gp);
1070 if (error != 0 && error != EINPROGRESS)
1071 gctl_error(req, "failed to stop %s (err=%d)", name, error);
1072 }
1073
1074 static void
1075 g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp)
1076 {
1077 struct g_geom *gp;
1078 struct g_multipath_softc *sc;
1079 struct g_consumer *cp;
1080 struct g_provider *pp;
1081 const char *name;
1082 uint8_t *buf;
1083 int error;
1084
1085 g_topology_assert();
1086
1087 name = gctl_get_asciiparam(req, "arg0");
1088 if (name == NULL) {
1089 gctl_error(req, "No 'arg0' argument");
1090 return;
1091 }
1092 gp = g_multipath_find_geom(mp, name);
1093 if (gp == NULL) {
1094 gctl_error(req, "Device %s is invalid", name);
1095 return;
1096 }
1097 sc = gp->softc;
1098
1099 if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
1100 cp = sc->sc_active;
1101 pp = cp->provider;
1102 error = g_access(cp, 1, 1, 1);
1103 if (error != 0) {
1104 gctl_error(req, "Can't open %s (%d)", pp->name, error);
1105 goto destroy;
1106 }
1107 g_topology_unlock();
1108 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1109 error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1110 buf, pp->sectorsize);
1111 g_topology_lock();
1112 g_access(cp, -1, -1, -1);
1113 if (error != 0)
1114 gctl_error(req, "Can't erase metadata on %s (%d)",
1115 pp->name, error);
1116 }
1117
1118 destroy:
1119 error = g_multipath_destroy(gp);
1120 if (error != 0 && error != EINPROGRESS)
1121 gctl_error(req, "failed to destroy %s (err=%d)", name, error);
1122 }
1123
1124 static void
1125 g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp)
1126 {
1127 struct g_geom *gp;
1128 const char *name;
1129 int error;
1130
1131 g_topology_assert();
1132
1133 name = gctl_get_asciiparam(req, "arg0");
1134 if (name == NULL) {
1135 gctl_error(req, "No 'arg0' argument");
1136 return;
1137 }
1138 gp = g_multipath_find_geom(mp, name);
1139 if (gp == NULL) {
1140 gctl_error(req, "Device %s is invalid", name);
1141 return;
1142 }
1143 error = g_multipath_rotate(gp);
1144 if (error != 0) {
1145 gctl_error(req, "failed to rotate %s (err=%d)", name, error);
1146 }
1147 }
1148
1149 static void
1150 g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp)
1151 {
1152 struct sbuf *sb;
1153 struct g_geom *gp;
1154 struct g_multipath_softc *sc;
1155 struct g_consumer *cp;
1156 const char *name;
1157 int empty;
1158
1159 sb = sbuf_new_auto();
1160
1161 g_topology_assert();
1162 name = gctl_get_asciiparam(req, "arg0");
1163 if (name == NULL) {
1164 gctl_error(req, "No 'arg0' argument");
1165 return;
1166 }
1167 gp = g_multipath_find_geom(mp, name);
1168 if (gp == NULL) {
1169 gctl_error(req, "Device %s is invalid", name);
1170 return;
1171 }
1172 sc = gp->softc;
1173 if (sc->sc_active_active) {
1174 empty = 1;
1175 LIST_FOREACH(cp, &gp->consumer, consumer) {
1176 if (cp->index & MP_BAD)
1177 continue;
1178 if (!empty)
1179 sbuf_cat(sb, " ");
1180 sbuf_cat(sb, cp->provider->name);
1181 empty = 0;
1182 }
1183 if (empty)
1184 sbuf_cat(sb, "none");
1185 sbuf_cat(sb, "\n");
1186 } else if (sc->sc_active && sc->sc_active->provider) {
1187 sbuf_printf(sb, "%s\n", sc->sc_active->provider->name);
1188 } else {
1189 sbuf_printf(sb, "none\n");
1190 }
1191 sbuf_finish(sb);
1192 gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1193 sbuf_delete(sb);
1194 }
1195
1196 static void
1197 g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1198 {
1199 uint32_t *version;
1200 g_topology_assert();
1201 version = gctl_get_paraml(req, "version", sizeof(*version));
1202 if (version == NULL) {
1203 gctl_error(req, "No 'version' argument");
1204 } else if (*version != G_MULTIPATH_VERSION) {
1205 gctl_error(req, "Userland and kernel parts are out of sync");
1206 } else if (strcmp(verb, "add") == 0) {
1207 g_multipath_ctl_add(req, mp);
1208 } else if (strcmp(verb, "create") == 0) {
1209 g_multipath_ctl_create(req, mp);
1210 } else if (strcmp(verb, "stop") == 0) {
1211 g_multipath_ctl_stop(req, mp);
1212 } else if (strcmp(verb, "destroy") == 0) {
1213 g_multipath_ctl_destroy(req, mp);
1214 } else if (strcmp(verb, "fail") == 0) {
1215 g_multipath_ctl_fail(req, mp, 1);
1216 } else if (strcmp(verb, "restore") == 0) {
1217 g_multipath_ctl_fail(req, mp, 0);
1218 } else if (strcmp(verb, "remove") == 0) {
1219 g_multipath_ctl_remove(req, mp);
1220 } else if (strcmp(verb, "rotate") == 0) {
1221 g_multipath_ctl_rotate(req, mp);
1222 } else if (strcmp(verb, "getactive") == 0) {
1223 g_multipath_ctl_getactive(req, mp);
1224 } else {
1225 gctl_error(req, "Unknown verb %s", verb);
1226 }
1227 }
1228
1229 static void
1230 g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1231 struct g_consumer *cp, struct g_provider *pp)
1232 {
1233 struct g_multipath_softc *sc;
1234 int good;
1235
1236 g_topology_assert();
1237
1238 sc = gp->softc;
1239 if (sc == NULL)
1240 return;
1241 if (cp != NULL) {
1242 sbuf_printf(sb, "%s<State>%s</State>", indent,
1243 (cp->index & MP_NEW) ? "NEW" :
1244 (cp->index & MP_LOST) ? "LOST" :
1245 (cp->index & MP_FAIL) ? "FAIL" :
1246 (sc->sc_active_active || sc->sc_active == cp) ?
1247 "ACTIVE" : "PASSIVE");
1248 } else {
1249 good = g_multipath_good(gp);
1250 sbuf_printf(sb, "%s<State>%s</State>", indent,
1251 good == 0 ? "BROKEN" :
1252 (good != sc->sc_ndisks || sc->sc_ndisks == 1) ?
1253 "DEGRADED" : "OPTIMAL");
1254 }
1255 if (cp == NULL && pp == NULL) {
1256 sbuf_printf(sb, "%s<UUID>%s</UUID>", indent, sc->sc_uuid);
1257 sbuf_printf(sb, "%s<Mode>Active/%s</Mode>", indent,
1258 sc->sc_active_active ? "Active" : "Passive");
1259 sbuf_printf(sb, "%s<Type>%s</Type>", indent,
1260 sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC");
1261 }
1262 }
1263
1264 DECLARE_GEOM_CLASS(g_multipath_class, g_multipath);
Cache object: 828d9fe07cd09785b6b92526760d0bd5
|