1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2010 Edward Tomasz Napierala <trasz@FreeBSD.org>
5 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bio.h>
33 #include <sys/disk.h>
34 #include <sys/eventhandler.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/proc.h>
41 #include <sys/sbuf.h>
42 #include <sys/sysctl.h>
43
44 #include <geom/geom.h>
45 #include <geom/geom_dbg.h>
46 #include <geom/mountver/g_mountver.h>
47
48 SYSCTL_DECL(_kern_geom);
49 static SYSCTL_NODE(_kern_geom, OID_AUTO, mountver, CTLFLAG_RW | CTLFLAG_MPSAFE,
50 0, "GEOM_MOUNTVER stuff");
51 static u_int g_mountver_debug = 0;
52 static u_int g_mountver_check_ident = 1;
53 SYSCTL_UINT(_kern_geom_mountver, OID_AUTO, debug, CTLFLAG_RW,
54 &g_mountver_debug, 0, "Debug level");
55 SYSCTL_UINT(_kern_geom_mountver, OID_AUTO, check_ident, CTLFLAG_RW,
56 &g_mountver_check_ident, 0, "Check disk ident when reattaching");
57
58 static eventhandler_tag g_mountver_pre_sync = NULL;
59
60 static void g_mountver_queue(struct bio *bp);
61 static void g_mountver_orphan(struct g_consumer *cp);
62 static void g_mountver_resize(struct g_consumer *cp);
63 static int g_mountver_destroy(struct g_geom *gp, boolean_t force);
64 static g_taste_t g_mountver_taste;
65 static int g_mountver_destroy_geom(struct gctl_req *req, struct g_class *mp,
66 struct g_geom *gp);
67 static void g_mountver_config(struct gctl_req *req, struct g_class *mp,
68 const char *verb);
69 static void g_mountver_dumpconf(struct sbuf *sb, const char *indent,
70 struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp);
71 static void g_mountver_init(struct g_class *mp);
72 static void g_mountver_fini(struct g_class *mp);
73
74 struct g_class g_mountver_class = {
75 .name = G_MOUNTVER_CLASS_NAME,
76 .version = G_VERSION,
77 .ctlreq = g_mountver_config,
78 .taste = g_mountver_taste,
79 .destroy_geom = g_mountver_destroy_geom,
80 .init = g_mountver_init,
81 .fini = g_mountver_fini
82 };
83
84 static void
g_mountver_detach(void * arg,int flags __unused)85 g_mountver_detach(void *arg, int flags __unused)
86 {
87 struct g_consumer *cp = arg;
88
89 g_topology_assert();
90 if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
91 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
92 g_detach(cp);
93 }
94
95 static void
g_mountver_done(struct bio * bp)96 g_mountver_done(struct bio *bp)
97 {
98 struct g_mountver_softc *sc;
99 struct g_geom *gp;
100 struct g_consumer *cp;
101 struct bio *pbp;
102
103 cp = bp->bio_from;
104 gp = cp->geom;
105 if (bp->bio_error != ENXIO) {
106 g_std_done(bp);
107 goto done;
108 }
109
110 /*
111 * When the device goes away, it's possible that few requests
112 * will be completed with ENXIO before g_mountver_orphan()
113 * gets called. To work around that, we have to queue requests
114 * that failed with ENXIO, in order to send them later.
115 */
116 pbp = bp->bio_parent;
117 KASSERT(pbp->bio_to == LIST_FIRST(&gp->provider),
118 ("parent request was for someone else"));
119 g_destroy_bio(bp);
120 pbp->bio_inbed++;
121 g_mountver_queue(pbp);
122
123 done:
124 sc = gp->softc;
125 mtx_lock(&sc->sc_mtx);
126 if (--cp->index == 0 && sc->sc_orphaned)
127 g_post_event(g_mountver_detach, cp, M_NOWAIT, NULL);
128 mtx_unlock(&sc->sc_mtx);
129 }
130
131 /*
132 * Send the BIO down. The function is called with sc_mtx held to cover
133 * the race with orphan, but drops it before external calls.
134 */
135 static void
g_mountver_send(struct g_geom * gp,struct bio * bp)136 g_mountver_send(struct g_geom *gp, struct bio *bp)
137 {
138 struct g_mountver_softc *sc = gp->softc;
139 struct g_consumer *cp;
140 struct bio *cbp;
141
142 mtx_assert(&sc->sc_mtx, MA_OWNED);
143 cbp = g_clone_bio(bp);
144 if (cbp == NULL) {
145 mtx_unlock(&sc->sc_mtx);
146 g_io_deliver(bp, ENOMEM);
147 return;
148 }
149 cp = LIST_FIRST(&gp->consumer);
150 cp->index++;
151 mtx_unlock(&sc->sc_mtx);
152
153 cbp->bio_done = g_mountver_done;
154 g_io_request(cbp, cp);
155 }
156
157 static void
g_mountver_queue(struct bio * bp)158 g_mountver_queue(struct bio *bp)
159 {
160 struct g_mountver_softc *sc;
161 struct g_geom *gp;
162
163 gp = bp->bio_to->geom;
164 sc = gp->softc;
165
166 mtx_lock(&sc->sc_mtx);
167 TAILQ_INSERT_TAIL(&sc->sc_queue, bp, bio_queue);
168 mtx_unlock(&sc->sc_mtx);
169 }
170
171 static void
g_mountver_send_queued(struct g_geom * gp)172 g_mountver_send_queued(struct g_geom *gp)
173 {
174 struct g_mountver_softc *sc;
175 struct bio *bp;
176
177 sc = gp->softc;
178
179 mtx_lock(&sc->sc_mtx);
180 while ((bp = TAILQ_FIRST(&sc->sc_queue)) != NULL && !sc->sc_orphaned) {
181 TAILQ_REMOVE(&sc->sc_queue, bp, bio_queue);
182 G_MOUNTVER_LOGREQ(bp, "Sending queued request.");
183 /* sc_mtx is dropped inside */
184 g_mountver_send(gp, bp);
185 mtx_lock(&sc->sc_mtx);
186 }
187 mtx_unlock(&sc->sc_mtx);
188 }
189
190 static void
g_mountver_discard_queued(struct g_geom * gp)191 g_mountver_discard_queued(struct g_geom *gp)
192 {
193 struct g_mountver_softc *sc;
194 struct bio *bp;
195
196 sc = gp->softc;
197
198 mtx_lock(&sc->sc_mtx);
199 while ((bp = TAILQ_FIRST(&sc->sc_queue)) != NULL) {
200 TAILQ_REMOVE(&sc->sc_queue, bp, bio_queue);
201 mtx_unlock(&sc->sc_mtx);
202 G_MOUNTVER_LOGREQ(bp, "Discarding queued request.");
203 g_io_deliver(bp, ENXIO);
204 mtx_lock(&sc->sc_mtx);
205 }
206 mtx_unlock(&sc->sc_mtx);
207 }
208
209 static void
g_mountver_start(struct bio * bp)210 g_mountver_start(struct bio *bp)
211 {
212 struct g_mountver_softc *sc;
213 struct g_geom *gp;
214
215 gp = bp->bio_to->geom;
216 sc = gp->softc;
217 G_MOUNTVER_LOGREQ(bp, "Request received.");
218
219 /*
220 * It is possible that some bios were returned with ENXIO, even though
221 * orphaning didn't happen yet. In that case, queue all subsequent
222 * requests in order to maintain ordering.
223 */
224 mtx_lock(&sc->sc_mtx);
225 if (sc->sc_orphaned || !TAILQ_EMPTY(&sc->sc_queue)) {
226 mtx_unlock(&sc->sc_mtx);
227 if (sc->sc_shutting_down) {
228 G_MOUNTVER_LOGREQ(bp, "Discarding request due to shutdown.");
229 g_io_deliver(bp, ENXIO);
230 return;
231 }
232 G_MOUNTVER_LOGREQ(bp, "Queueing request.");
233 g_mountver_queue(bp);
234 if (!sc->sc_orphaned)
235 g_mountver_send_queued(gp);
236 } else {
237 G_MOUNTVER_LOGREQ(bp, "Sending request.");
238 /* sc_mtx is dropped inside */
239 g_mountver_send(gp, bp);
240 }
241 }
242
243 static int
g_mountver_access(struct g_provider * pp,int dr,int dw,int de)244 g_mountver_access(struct g_provider *pp, int dr, int dw, int de)
245 {
246 struct g_mountver_softc *sc;
247 struct g_geom *gp;
248 struct g_consumer *cp;
249
250 g_topology_assert();
251
252 gp = pp->geom;
253 cp = LIST_FIRST(&gp->consumer);
254 sc = gp->softc;
255 if (sc == NULL && dr <= 0 && dw <= 0 && de <= 0)
256 return (0);
257 KASSERT(sc != NULL, ("Trying to access withered provider \"%s\".", pp->name));
258
259 sc->sc_access_r += dr;
260 sc->sc_access_w += dw;
261 sc->sc_access_e += de;
262
263 if (sc->sc_orphaned)
264 return (0);
265
266 return (g_access(cp, dr, dw, de));
267 }
268
269 static int
g_mountver_create(struct gctl_req * req,struct g_class * mp,struct g_provider * pp)270 g_mountver_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp)
271 {
272 struct g_mountver_softc *sc;
273 struct g_geom *gp;
274 struct g_provider *newpp;
275 struct g_consumer *cp;
276 struct g_geom_alias *gap;
277 char name[64];
278 int error;
279 int identsize = DISK_IDENT_SIZE;
280
281 g_topology_assert();
282
283 gp = NULL;
284 newpp = NULL;
285 cp = NULL;
286
287 snprintf(name, sizeof(name), "%s%s", pp->name, G_MOUNTVER_SUFFIX);
288 LIST_FOREACH(gp, &mp->geom, geom) {
289 if (strcmp(gp->name, name) == 0) {
290 gctl_error(req, "Provider %s already exists.", name);
291 return (EEXIST);
292 }
293 }
294 gp = g_new_geomf(mp, "%s", name);
295 sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
296 mtx_init(&sc->sc_mtx, "gmountver", NULL, MTX_DEF | MTX_RECURSE);
297 TAILQ_INIT(&sc->sc_queue);
298 sc->sc_provider_name = strdup(pp->name, M_GEOM);
299 gp->softc = sc;
300 gp->start = g_mountver_start;
301 gp->orphan = g_mountver_orphan;
302 gp->resize = g_mountver_resize;
303 gp->access = g_mountver_access;
304 gp->dumpconf = g_mountver_dumpconf;
305
306 newpp = g_new_providerf(gp, "%s", gp->name);
307 newpp->mediasize = pp->mediasize;
308 newpp->sectorsize = pp->sectorsize;
309 newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
310 LIST_FOREACH(gap, &pp->aliases, ga_next)
311 g_provider_add_alias(newpp, "%s%s", gap->ga_alias, G_MOUNTVER_SUFFIX);
312
313 if ((pp->flags & G_PF_ACCEPT_UNMAPPED) != 0) {
314 G_MOUNTVER_DEBUG(0, "Unmapped supported for %s.", gp->name);
315 newpp->flags |= G_PF_ACCEPT_UNMAPPED;
316 } else {
317 G_MOUNTVER_DEBUG(0, "Unmapped unsupported for %s.", gp->name);
318 newpp->flags &= ~G_PF_ACCEPT_UNMAPPED;
319 }
320
321 cp = g_new_consumer(gp);
322 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
323 error = g_attach(cp, pp);
324 if (error != 0) {
325 gctl_error(req, "Cannot attach to provider %s.", pp->name);
326 goto fail;
327 }
328 error = g_access(cp, 1, 0, 0);
329 if (error != 0) {
330 gctl_error(req, "Cannot access provider %s.", pp->name);
331 goto fail;
332 }
333 error = g_io_getattr("GEOM::ident", cp, &identsize, sc->sc_ident);
334 g_access(cp, -1, 0, 0);
335 if (error != 0) {
336 if (g_mountver_check_ident) {
337 gctl_error(req, "Cannot get disk ident from %s; error = %d.", pp->name, error);
338 goto fail;
339 }
340
341 G_MOUNTVER_DEBUG(0, "Cannot get disk ident from %s; error = %d.", pp->name, error);
342 sc->sc_ident[0] = '\0';
343 }
344
345 g_error_provider(newpp, 0);
346 G_MOUNTVER_DEBUG(0, "Device %s created.", gp->name);
347 return (0);
348 fail:
349 g_free(sc->sc_provider_name);
350 if (cp->provider != NULL)
351 g_detach(cp);
352 g_destroy_consumer(cp);
353 g_destroy_provider(newpp);
354 g_free(gp->softc);
355 g_destroy_geom(gp);
356 return (error);
357 }
358
359 static int
g_mountver_destroy(struct g_geom * gp,boolean_t force)360 g_mountver_destroy(struct g_geom *gp, boolean_t force)
361 {
362 struct g_mountver_softc *sc;
363 struct g_provider *pp;
364
365 g_topology_assert();
366 if (gp->softc == NULL)
367 return (ENXIO);
368 sc = gp->softc;
369 pp = LIST_FIRST(&gp->provider);
370 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
371 if (force) {
372 G_MOUNTVER_DEBUG(0, "Device %s is still open, so it "
373 "can't be definitely removed.", pp->name);
374 } else {
375 G_MOUNTVER_DEBUG(1, "Device %s is still open (r%dw%de%d).",
376 pp->name, pp->acr, pp->acw, pp->ace);
377 return (EBUSY);
378 }
379 } else {
380 G_MOUNTVER_DEBUG(0, "Device %s removed.", gp->name);
381 }
382 if (pp != NULL)
383 g_wither_provider(pp, ENXIO);
384 g_mountver_discard_queued(gp);
385 g_free(sc->sc_provider_name);
386 g_free(gp->softc);
387 gp->softc = NULL;
388 g_wither_geom(gp, ENXIO);
389
390 return (0);
391 }
392
393 static int
g_mountver_destroy_geom(struct gctl_req * req,struct g_class * mp,struct g_geom * gp)394 g_mountver_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
395 {
396
397 return (g_mountver_destroy(gp, 0));
398 }
399
400 static void
g_mountver_ctl_create(struct gctl_req * req,struct g_class * mp)401 g_mountver_ctl_create(struct gctl_req *req, struct g_class *mp)
402 {
403 struct g_provider *pp;
404 char param[16];
405 int i, *nargs;
406
407 g_topology_assert();
408
409 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
410 if (nargs == NULL) {
411 gctl_error(req, "No '%s' argument", "nargs");
412 return;
413 }
414 if (*nargs <= 0) {
415 gctl_error(req, "Missing device(s).");
416 return;
417 }
418 for (i = 0; i < *nargs; i++) {
419 snprintf(param, sizeof(param), "arg%d", i);
420 pp = gctl_get_provider(req, param);
421 if (pp == NULL)
422 return;
423 if (g_mountver_create(req, mp, pp) != 0)
424 return;
425 }
426 }
427
428 static struct g_geom *
g_mountver_find_geom(struct g_class * mp,const char * name)429 g_mountver_find_geom(struct g_class *mp, const char *name)
430 {
431 struct g_geom *gp;
432
433 LIST_FOREACH(gp, &mp->geom, geom) {
434 if (strcmp(gp->name, name) == 0)
435 return (gp);
436 }
437 return (NULL);
438 }
439
440 static void
g_mountver_ctl_destroy(struct gctl_req * req,struct g_class * mp)441 g_mountver_ctl_destroy(struct gctl_req *req, struct g_class *mp)
442 {
443 int *nargs, *force, error, i;
444 struct g_geom *gp;
445 const char *name;
446 char param[16];
447
448 g_topology_assert();
449
450 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
451 if (nargs == NULL) {
452 gctl_error(req, "No '%s' argument", "nargs");
453 return;
454 }
455 if (*nargs <= 0) {
456 gctl_error(req, "Missing device(s).");
457 return;
458 }
459 force = gctl_get_paraml(req, "force", sizeof(*force));
460 if (force == NULL) {
461 gctl_error(req, "No 'force' argument");
462 return;
463 }
464
465 for (i = 0; i < *nargs; i++) {
466 snprintf(param, sizeof(param), "arg%d", i);
467 name = gctl_get_asciiparam(req, param);
468 if (name == NULL) {
469 gctl_error(req, "No 'arg%d' argument", i);
470 return;
471 }
472 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
473 name += strlen(_PATH_DEV);
474 gp = g_mountver_find_geom(mp, name);
475 if (gp == NULL) {
476 G_MOUNTVER_DEBUG(1, "Device %s is invalid.", name);
477 gctl_error(req, "Device %s is invalid.", name);
478 return;
479 }
480 error = g_mountver_destroy(gp, *force);
481 if (error != 0) {
482 gctl_error(req, "Cannot destroy device %s (error=%d).",
483 gp->name, error);
484 return;
485 }
486 }
487 }
488
489 static void
g_mountver_orphan(struct g_consumer * cp)490 g_mountver_orphan(struct g_consumer *cp)
491 {
492 struct g_mountver_softc *sc;
493 int done;
494
495 g_topology_assert();
496
497 sc = cp->geom->softc;
498 mtx_lock(&sc->sc_mtx);
499 sc->sc_orphaned = 1;
500 done = (cp->index == 0);
501 mtx_unlock(&sc->sc_mtx);
502 if (done)
503 g_mountver_detach(cp, 0);
504 G_MOUNTVER_DEBUG(0, "%s is offline. Mount verification in progress.", sc->sc_provider_name);
505 }
506
507 static void
g_mountver_resize(struct g_consumer * cp)508 g_mountver_resize(struct g_consumer *cp)
509 {
510 struct g_geom *gp;
511 struct g_provider *pp;
512
513 gp = cp->geom;
514
515 LIST_FOREACH(pp, &gp->provider, provider)
516 g_resize_provider(pp, cp->provider->mediasize);
517 }
518
519 static int
g_mountver_ident_matches(struct g_geom * gp)520 g_mountver_ident_matches(struct g_geom *gp)
521 {
522 struct g_consumer *cp;
523 struct g_mountver_softc *sc;
524 char ident[DISK_IDENT_SIZE];
525 int error, identsize = DISK_IDENT_SIZE;
526
527 sc = gp->softc;
528 cp = LIST_FIRST(&gp->consumer);
529
530 if (g_mountver_check_ident == 0)
531 return (0);
532
533 error = g_access(cp, 1, 0, 0);
534 if (error != 0) {
535 G_MOUNTVER_DEBUG(0, "Cannot access %s; "
536 "not attaching; error = %d.", gp->name, error);
537 return (1);
538 }
539 error = g_io_getattr("GEOM::ident", cp, &identsize, ident);
540 g_access(cp, -1, 0, 0);
541 if (error != 0) {
542 G_MOUNTVER_DEBUG(0, "Cannot get disk ident for %s; "
543 "not attaching; error = %d.", gp->name, error);
544 return (1);
545 }
546 if (strcmp(ident, sc->sc_ident) != 0) {
547 G_MOUNTVER_DEBUG(1, "Disk ident for %s (\"%s\") is different "
548 "from expected \"%s\", not attaching.", gp->name, ident,
549 sc->sc_ident);
550 return (1);
551 }
552
553 return (0);
554 }
555
556 static struct g_geom *
g_mountver_taste(struct g_class * mp,struct g_provider * pp,int flags __unused)557 g_mountver_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
558 {
559 struct g_mountver_softc *sc;
560 struct g_consumer *cp;
561 struct g_geom *gp;
562 int error;
563
564 g_topology_assert();
565 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
566 G_MOUNTVER_DEBUG(2, "Tasting %s.", pp->name);
567
568 /*
569 * Let's check if device already exists.
570 */
571 LIST_FOREACH(gp, &mp->geom, geom) {
572 sc = gp->softc;
573 if (sc == NULL)
574 continue;
575
576 /* Already attached? */
577 if (pp == LIST_FIRST(&gp->provider))
578 return (NULL);
579
580 if (sc->sc_orphaned && strcmp(pp->name, sc->sc_provider_name) == 0)
581 break;
582 }
583 if (gp == NULL)
584 return (NULL);
585
586 cp = LIST_FIRST(&gp->consumer);
587 error = g_attach(cp, pp);
588 if (error != 0) {
589 G_MOUNTVER_DEBUG(0, "Cannot attach to %s; error = %d.", pp->name, error);
590 return (NULL);
591 }
592
593 error = g_mountver_ident_matches(gp);
594 if (error != 0) {
595 g_detach(cp);
596 return (NULL);
597 }
598 if (sc->sc_access_r > 0 || sc->sc_access_w > 0 || sc->sc_access_e > 0) {
599 error = g_access(cp, sc->sc_access_r, sc->sc_access_w, sc->sc_access_e);
600 if (error != 0) {
601 G_MOUNTVER_DEBUG(0, "Cannot access %s; error = %d.", pp->name, error);
602 g_detach(cp);
603 return (NULL);
604 }
605 }
606 sc->sc_orphaned = 0;
607 g_mountver_send_queued(gp);
608 G_MOUNTVER_DEBUG(0, "%s has completed mount verification.", sc->sc_provider_name);
609
610 return (gp);
611 }
612
613 static void
g_mountver_config(struct gctl_req * req,struct g_class * mp,const char * verb)614 g_mountver_config(struct gctl_req *req, struct g_class *mp, const char *verb)
615 {
616 uint32_t *version;
617
618 g_topology_assert();
619
620 version = gctl_get_paraml(req, "version", sizeof(*version));
621 if (version == NULL) {
622 gctl_error(req, "No '%s' argument.", "version");
623 return;
624 }
625 if (*version != G_MOUNTVER_VERSION) {
626 gctl_error(req, "Userland and kernel parts are out of sync.");
627 return;
628 }
629
630 if (strcmp(verb, "create") == 0) {
631 g_mountver_ctl_create(req, mp);
632 return;
633 } else if (strcmp(verb, "destroy") == 0) {
634 g_mountver_ctl_destroy(req, mp);
635 return;
636 }
637
638 gctl_error(req, "Unknown verb.");
639 }
640
641 static void
g_mountver_dumpconf(struct sbuf * sb,const char * indent,struct g_geom * gp,struct g_consumer * cp,struct g_provider * pp)642 g_mountver_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
643 struct g_consumer *cp, struct g_provider *pp)
644 {
645 struct g_mountver_softc *sc;
646
647 if (pp != NULL || cp != NULL)
648 return;
649
650 sc = gp->softc;
651 sbuf_printf(sb, "%s<State>%s</State>\n", indent,
652 sc->sc_orphaned ? "OFFLINE" : "ONLINE");
653 sbuf_printf(sb, "%s<Provider-Name>%s</Provider-Name>\n", indent, sc->sc_provider_name);
654 sbuf_printf(sb, "%s<Disk-Ident>%s</Disk-Ident>\n", indent, sc->sc_ident);
655 }
656
657 static void
g_mountver_shutdown_pre_sync(void * arg,int howto)658 g_mountver_shutdown_pre_sync(void *arg, int howto)
659 {
660 struct g_mountver_softc *sc;
661 struct g_class *mp;
662 struct g_geom *gp, *gp2;
663
664 mp = arg;
665 g_topology_lock();
666 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
667 if (gp->softc == NULL)
668 continue;
669 sc = gp->softc;
670 sc->sc_shutting_down = 1;
671 if (sc->sc_orphaned)
672 g_mountver_destroy(gp, 1);
673 }
674 g_topology_unlock();
675 }
676
677 static void
g_mountver_init(struct g_class * mp)678 g_mountver_init(struct g_class *mp)
679 {
680
681 g_mountver_pre_sync = EVENTHANDLER_REGISTER(shutdown_pre_sync,
682 g_mountver_shutdown_pre_sync, mp, SHUTDOWN_PRI_FIRST);
683 if (g_mountver_pre_sync == NULL)
684 G_MOUNTVER_DEBUG(0, "Warning! Cannot register shutdown event.");
685 }
686
687 static void
g_mountver_fini(struct g_class * mp)688 g_mountver_fini(struct g_class *mp)
689 {
690
691 if (g_mountver_pre_sync != NULL)
692 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, g_mountver_pre_sync);
693 }
694
695 DECLARE_GEOM_CLASS(g_mountver_class, g_mountver);
696 MODULE_VERSION(geom_mountver, 0);
697