1202437Strasz/*- 2202437Strasz * Copyright (c) 2010 Edward Tomasz Napierala <trasz@FreeBSD.org> 3202437Strasz * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4202437Strasz * All rights reserved. 5202437Strasz * 6202437Strasz * Redistribution and use in source and binary forms, with or without 7202437Strasz * modification, are permitted provided that the following conditions 8202437Strasz * are met: 9202437Strasz * 1. Redistributions of source code must retain the above copyright 10202437Strasz * notice, this list of conditions and the following disclaimer. 11202437Strasz * 2. Redistributions in binary form must reproduce the above copyright 12202437Strasz * notice, this list of conditions and the following disclaimer in the 13202437Strasz * documentation and/or other materials provided with the distribution. 14202437Strasz * 15202437Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16202437Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17202437Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18202437Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19202437Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20202437Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21202437Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22202437Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23202437Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24202437Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25202437Strasz * SUCH DAMAGE. 26202437Strasz */ 27202437Strasz 28202437Strasz#include <sys/cdefs.h> 29202437Strasz__FBSDID("$FreeBSD$"); 30202437Strasz 31202437Strasz#include <sys/param.h> 32202437Strasz#include <sys/systm.h> 33202437Strasz#include <sys/kernel.h> 34202437Strasz#include <sys/module.h> 35202437Strasz#include <sys/lock.h> 36202437Strasz#include <sys/mutex.h> 37202437Strasz#include <sys/bio.h> 38202437Strasz#include <sys/disk.h> 39230643Sattilio#include <sys/proc.h> 40223921Sae#include <sys/sbuf.h> 41202437Strasz#include <sys/sysctl.h> 42202437Strasz#include <sys/malloc.h> 43202437Strasz#include <sys/eventhandler.h> 44202437Strasz#include <geom/geom.h> 45202437Strasz#include <geom/mountver/g_mountver.h> 46202437Strasz 47202437Strasz 48202437StraszSYSCTL_DECL(_kern_geom); 49227309Sedstatic SYSCTL_NODE(_kern_geom, OID_AUTO, mountver, CTLFLAG_RW, 50202437Strasz 0, "GEOM_MOUNTVER stuff"); 51202437Straszstatic u_int g_mountver_debug = 0; 52202437Straszstatic u_int g_mountver_check_ident = 1; 53202437StraszSYSCTL_UINT(_kern_geom_mountver, OID_AUTO, debug, CTLFLAG_RW, 54202437Strasz &g_mountver_debug, 0, "Debug level"); 55202437StraszSYSCTL_UINT(_kern_geom_mountver, OID_AUTO, check_ident, CTLFLAG_RW, 56202437Strasz &g_mountver_check_ident, 0, "Check disk ident when reattaching"); 57202437Strasz 58202437Straszstatic eventhandler_tag g_mountver_pre_sync = NULL; 59202437Strasz 60202437Straszstatic void g_mountver_queue(struct bio *bp); 61202437Straszstatic void g_mountver_orphan(struct g_consumer *cp); 62238218Straszstatic void g_mountver_resize(struct g_consumer *cp); 63202437Straszstatic int g_mountver_destroy(struct g_geom *gp, boolean_t force); 64202437Straszstatic g_taste_t g_mountver_taste; 65202437Straszstatic int g_mountver_destroy_geom(struct gctl_req *req, struct g_class *mp, 66202437Strasz struct g_geom *gp); 67202437Straszstatic void g_mountver_config(struct gctl_req *req, struct g_class *mp, 68202437Strasz const char *verb); 69202437Straszstatic void g_mountver_dumpconf(struct sbuf *sb, const char *indent, 70202437Strasz struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp); 71202437Straszstatic void g_mountver_init(struct g_class *mp); 72202437Straszstatic void g_mountver_fini(struct g_class *mp); 73202437Strasz 74202437Straszstruct g_class g_mountver_class = { 75202437Strasz .name = G_MOUNTVER_CLASS_NAME, 76202437Strasz .version = G_VERSION, 77202437Strasz .ctlreq = g_mountver_config, 78202437Strasz .taste = g_mountver_taste, 79202437Strasz .destroy_geom = g_mountver_destroy_geom, 80202437Strasz .init = g_mountver_init, 81202437Strasz .fini = g_mountver_fini 82202437Strasz}; 83202437Strasz 84202437Straszstatic void 85202437Straszg_mountver_done(struct bio *bp) 86202437Strasz{ 87202437Strasz struct g_geom *gp; 88202437Strasz struct bio *pbp; 89202437Strasz 90202437Strasz if (bp->bio_error != ENXIO) { 91202437Strasz g_std_done(bp); 92202437Strasz return; 93202437Strasz } 94202437Strasz 95202437Strasz /* 96202437Strasz * When the device goes away, it's possible that few requests 97202437Strasz * will be completed with ENXIO before g_mountver_orphan() 98202437Strasz * gets called. To work around that, we have to queue requests 99202437Strasz * that failed with ENXIO, in order to send them later. 100202437Strasz */ 101202437Strasz gp = bp->bio_from->geom; 102202437Strasz 103202437Strasz pbp = bp->bio_parent; 104202437Strasz KASSERT(pbp->bio_to == LIST_FIRST(&gp->provider), 105202437Strasz ("parent request was for someone else")); 106202437Strasz g_destroy_bio(bp); 107202437Strasz pbp->bio_inbed++; 108202437Strasz g_mountver_queue(pbp); 109202437Strasz} 110202437Strasz 111202437Straszstatic void 112202437Straszg_mountver_send(struct bio *bp) 113202437Strasz{ 114202437Strasz struct g_geom *gp; 115202437Strasz struct bio *cbp; 116202437Strasz 117202437Strasz gp = bp->bio_to->geom; 118202437Strasz 119202437Strasz cbp = g_clone_bio(bp); 120202437Strasz if (cbp == NULL) { 121202437Strasz g_io_deliver(bp, ENOMEM); 122202437Strasz return; 123202437Strasz } 124202437Strasz 125202437Strasz cbp->bio_done = g_mountver_done; 126202437Strasz g_io_request(cbp, LIST_FIRST(&gp->consumer)); 127202437Strasz} 128202437Strasz 129202437Straszstatic void 130202437Straszg_mountver_queue(struct bio *bp) 131202437Strasz{ 132202437Strasz struct g_mountver_softc *sc; 133202437Strasz struct g_geom *gp; 134202437Strasz 135202437Strasz gp = bp->bio_to->geom; 136202437Strasz sc = gp->softc; 137202437Strasz 138202437Strasz mtx_lock(&sc->sc_mtx); 139202437Strasz TAILQ_INSERT_TAIL(&sc->sc_queue, bp, bio_queue); 140202437Strasz mtx_unlock(&sc->sc_mtx); 141202437Strasz} 142202437Strasz 143202437Straszstatic void 144202437Straszg_mountver_send_queued(struct g_geom *gp) 145202437Strasz{ 146202437Strasz struct g_mountver_softc *sc; 147202437Strasz struct bio *bp; 148202437Strasz 149202437Strasz sc = gp->softc; 150202437Strasz 151202437Strasz mtx_lock(&sc->sc_mtx); 152202437Strasz while ((bp = TAILQ_FIRST(&sc->sc_queue)) != NULL) { 153202437Strasz TAILQ_REMOVE(&sc->sc_queue, bp, bio_queue); 154202437Strasz G_MOUNTVER_LOGREQ(bp, "Sending queued request."); 155202437Strasz g_mountver_send(bp); 156202437Strasz } 157202437Strasz mtx_unlock(&sc->sc_mtx); 158202437Strasz} 159202437Strasz 160202437Straszstatic void 161202437Straszg_mountver_discard_queued(struct g_geom *gp) 162202437Strasz{ 163202437Strasz struct g_mountver_softc *sc; 164202437Strasz struct bio *bp; 165202437Strasz 166202437Strasz sc = gp->softc; 167202437Strasz 168202437Strasz mtx_lock(&sc->sc_mtx); 169202437Strasz while ((bp = TAILQ_FIRST(&sc->sc_queue)) != NULL) { 170202437Strasz TAILQ_REMOVE(&sc->sc_queue, bp, bio_queue); 171202437Strasz G_MOUNTVER_LOGREQ(bp, "Discarding queued request."); 172202437Strasz g_io_deliver(bp, ENXIO); 173202437Strasz } 174202437Strasz mtx_unlock(&sc->sc_mtx); 175202437Strasz} 176202437Strasz 177202437Straszstatic void 178202437Straszg_mountver_start(struct bio *bp) 179202437Strasz{ 180202437Strasz struct g_mountver_softc *sc; 181202437Strasz struct g_geom *gp; 182202437Strasz 183202437Strasz gp = bp->bio_to->geom; 184202437Strasz sc = gp->softc; 185202437Strasz G_MOUNTVER_LOGREQ(bp, "Request received."); 186202437Strasz 187202437Strasz /* 188202437Strasz * It is possible that some bios were returned with ENXIO, even though 189202437Strasz * orphaning didn't happen yet. In that case, queue all subsequent 190202437Strasz * requests in order to maintain ordering. 191202437Strasz */ 192202437Strasz if (sc->sc_orphaned || !TAILQ_EMPTY(&sc->sc_queue)) { 193202437Strasz G_MOUNTVER_LOGREQ(bp, "Queueing request."); 194202437Strasz g_mountver_queue(bp); 195202437Strasz if (!sc->sc_orphaned) 196202437Strasz g_mountver_send_queued(gp); 197202437Strasz } else { 198202437Strasz G_MOUNTVER_LOGREQ(bp, "Sending request."); 199202437Strasz g_mountver_send(bp); 200202437Strasz } 201202437Strasz} 202202437Strasz 203202437Straszstatic int 204202437Straszg_mountver_access(struct g_provider *pp, int dr, int dw, int de) 205202437Strasz{ 206202437Strasz struct g_mountver_softc *sc; 207202437Strasz struct g_geom *gp; 208202437Strasz struct g_consumer *cp; 209202437Strasz 210202437Strasz g_topology_assert(); 211202437Strasz 212202437Strasz gp = pp->geom; 213202437Strasz cp = LIST_FIRST(&gp->consumer); 214202437Strasz sc = gp->softc; 215202437Strasz if (sc == NULL && dr <= 0 && dw <= 0 && de <= 0) 216202437Strasz return (0); 217202437Strasz KASSERT(sc != NULL, ("Trying to access withered provider \"%s\".", pp->name)); 218202437Strasz 219202437Strasz sc->sc_access_r += dr; 220202437Strasz sc->sc_access_w += dw; 221202437Strasz sc->sc_access_e += de; 222202437Strasz 223202437Strasz if (sc->sc_orphaned) 224202437Strasz return (0); 225202437Strasz 226202437Strasz return (g_access(cp, dr, dw, de)); 227202437Strasz} 228202437Strasz 229202437Straszstatic int 230202437Straszg_mountver_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp) 231202437Strasz{ 232202437Strasz struct g_mountver_softc *sc; 233202437Strasz struct g_geom *gp; 234202437Strasz struct g_provider *newpp; 235202437Strasz struct g_consumer *cp; 236202437Strasz char name[64]; 237202437Strasz int error; 238202437Strasz int identsize = DISK_IDENT_SIZE; 239202437Strasz 240202437Strasz g_topology_assert(); 241202437Strasz 242202437Strasz gp = NULL; 243202437Strasz newpp = NULL; 244202437Strasz cp = NULL; 245202437Strasz 246202437Strasz snprintf(name, sizeof(name), "%s%s", pp->name, G_MOUNTVER_SUFFIX); 247202437Strasz LIST_FOREACH(gp, &mp->geom, geom) { 248202437Strasz if (strcmp(gp->name, name) == 0) { 249202437Strasz gctl_error(req, "Provider %s already exists.", name); 250202437Strasz return (EEXIST); 251202437Strasz } 252202437Strasz } 253243333Sjh gp = g_new_geomf(mp, "%s", name); 254202437Strasz sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 255202437Strasz mtx_init(&sc->sc_mtx, "gmountver", NULL, MTX_DEF); 256202437Strasz TAILQ_INIT(&sc->sc_queue); 257202437Strasz sc->sc_provider_name = strdup(pp->name, M_GEOM); 258202437Strasz gp->softc = sc; 259202437Strasz gp->start = g_mountver_start; 260202437Strasz gp->orphan = g_mountver_orphan; 261238218Strasz gp->resize = g_mountver_resize; 262202437Strasz gp->access = g_mountver_access; 263202437Strasz gp->dumpconf = g_mountver_dumpconf; 264202437Strasz 265243333Sjh newpp = g_new_providerf(gp, "%s", gp->name); 266202437Strasz newpp->mediasize = pp->mediasize; 267202437Strasz newpp->sectorsize = pp->sectorsize; 268202437Strasz 269202437Strasz cp = g_new_consumer(gp); 270202437Strasz error = g_attach(cp, pp); 271202437Strasz if (error != 0) { 272202437Strasz gctl_error(req, "Cannot attach to provider %s.", pp->name); 273202437Strasz goto fail; 274202437Strasz } 275202437Strasz error = g_access(cp, 1, 0, 0); 276202437Strasz if (error != 0) { 277202437Strasz gctl_error(req, "Cannot access provider %s.", pp->name); 278202437Strasz goto fail; 279202437Strasz } 280202437Strasz error = g_io_getattr("GEOM::ident", cp, &identsize, sc->sc_ident); 281202437Strasz g_access(cp, -1, 0, 0); 282202437Strasz if (error != 0) { 283202437Strasz if (g_mountver_check_ident) { 284202437Strasz gctl_error(req, "Cannot get disk ident from %s; error = %d.", pp->name, error); 285202437Strasz goto fail; 286202437Strasz } 287202437Strasz 288202437Strasz G_MOUNTVER_DEBUG(0, "Cannot get disk ident from %s; error = %d.", pp->name, error); 289202437Strasz sc->sc_ident[0] = '\0'; 290202437Strasz } 291202437Strasz 292202437Strasz g_error_provider(newpp, 0); 293202437Strasz G_MOUNTVER_DEBUG(0, "Device %s created.", gp->name); 294202437Strasz return (0); 295202437Straszfail: 296221451Sae g_free(sc->sc_provider_name); 297221451Sae if (cp->provider != NULL) 298221451Sae g_detach(cp); 299221451Sae g_destroy_consumer(cp); 300221451Sae g_destroy_provider(newpp); 301221451Sae g_free(gp->softc); 302221451Sae g_destroy_geom(gp); 303202437Strasz return (error); 304202437Strasz} 305202437Strasz 306202437Straszstatic int 307202437Straszg_mountver_destroy(struct g_geom *gp, boolean_t force) 308202437Strasz{ 309202437Strasz struct g_mountver_softc *sc; 310202437Strasz struct g_provider *pp; 311202437Strasz 312202437Strasz g_topology_assert(); 313202437Strasz if (gp->softc == NULL) 314202437Strasz return (ENXIO); 315202437Strasz sc = gp->softc; 316202437Strasz pp = LIST_FIRST(&gp->provider); 317202437Strasz if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 318202437Strasz if (force) { 319202437Strasz G_MOUNTVER_DEBUG(0, "Device %s is still open, so it " 320202437Strasz "can't be definitely removed.", pp->name); 321202437Strasz } else { 322202437Strasz G_MOUNTVER_DEBUG(1, "Device %s is still open (r%dw%de%d).", 323202437Strasz pp->name, pp->acr, pp->acw, pp->ace); 324202437Strasz return (EBUSY); 325202437Strasz } 326202437Strasz } else { 327202437Strasz G_MOUNTVER_DEBUG(0, "Device %s removed.", gp->name); 328202437Strasz } 329208812Strasz if (pp != NULL) 330208812Strasz g_orphan_provider(pp, ENXIO); 331202437Strasz g_mountver_discard_queued(gp); 332202437Strasz g_free(sc->sc_provider_name); 333202437Strasz g_free(gp->softc); 334202437Strasz gp->softc = NULL; 335202437Strasz g_wither_geom(gp, ENXIO); 336202437Strasz 337202437Strasz return (0); 338202437Strasz} 339202437Strasz 340202437Straszstatic int 341202437Straszg_mountver_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) 342202437Strasz{ 343202437Strasz 344202437Strasz return (g_mountver_destroy(gp, 0)); 345202437Strasz} 346202437Strasz 347202437Straszstatic void 348202437Straszg_mountver_ctl_create(struct gctl_req *req, struct g_class *mp) 349202437Strasz{ 350202437Strasz struct g_provider *pp; 351202437Strasz const char *name; 352202437Strasz char param[16]; 353202437Strasz int i, *nargs; 354202437Strasz 355202437Strasz g_topology_assert(); 356202437Strasz 357202437Strasz nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 358202437Strasz if (nargs == NULL) { 359202437Strasz gctl_error(req, "No '%s' argument", "nargs"); 360202437Strasz return; 361202437Strasz } 362202437Strasz if (*nargs <= 0) { 363202437Strasz gctl_error(req, "Missing device(s)."); 364202437Strasz return; 365202437Strasz } 366202437Strasz for (i = 0; i < *nargs; i++) { 367202437Strasz snprintf(param, sizeof(param), "arg%d", i); 368202437Strasz name = gctl_get_asciiparam(req, param); 369202437Strasz if (name == NULL) { 370202437Strasz gctl_error(req, "No 'arg%d' argument", i); 371202437Strasz return; 372202437Strasz } 373202437Strasz if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 374202437Strasz name += strlen("/dev/"); 375202437Strasz pp = g_provider_by_name(name); 376202437Strasz if (pp == NULL) { 377202437Strasz G_MOUNTVER_DEBUG(1, "Provider %s is invalid.", name); 378202437Strasz gctl_error(req, "Provider %s is invalid.", name); 379202437Strasz return; 380202437Strasz } 381202437Strasz if (g_mountver_create(req, mp, pp) != 0) 382202437Strasz return; 383202437Strasz } 384202437Strasz} 385202437Strasz 386202437Straszstatic struct g_geom * 387202437Straszg_mountver_find_geom(struct g_class *mp, const char *name) 388202437Strasz{ 389202437Strasz struct g_geom *gp; 390202437Strasz 391202437Strasz LIST_FOREACH(gp, &mp->geom, geom) { 392202437Strasz if (strcmp(gp->name, name) == 0) 393202437Strasz return (gp); 394202437Strasz } 395202437Strasz return (NULL); 396202437Strasz} 397202437Strasz 398202437Straszstatic void 399202437Straszg_mountver_ctl_destroy(struct gctl_req *req, struct g_class *mp) 400202437Strasz{ 401202437Strasz int *nargs, *force, error, i; 402202437Strasz struct g_geom *gp; 403202437Strasz const char *name; 404202437Strasz char param[16]; 405202437Strasz 406202437Strasz g_topology_assert(); 407202437Strasz 408202437Strasz nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 409202437Strasz if (nargs == NULL) { 410202437Strasz gctl_error(req, "No '%s' argument", "nargs"); 411202437Strasz return; 412202437Strasz } 413202437Strasz if (*nargs <= 0) { 414202437Strasz gctl_error(req, "Missing device(s)."); 415202437Strasz return; 416202437Strasz } 417202437Strasz force = gctl_get_paraml(req, "force", sizeof(*force)); 418202437Strasz if (force == NULL) { 419202437Strasz gctl_error(req, "No 'force' argument"); 420202437Strasz return; 421202437Strasz } 422202437Strasz 423202437Strasz for (i = 0; i < *nargs; i++) { 424202437Strasz snprintf(param, sizeof(param), "arg%d", i); 425202437Strasz name = gctl_get_asciiparam(req, param); 426202437Strasz if (name == NULL) { 427202437Strasz gctl_error(req, "No 'arg%d' argument", i); 428202437Strasz return; 429202437Strasz } 430202437Strasz if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 431202437Strasz name += strlen("/dev/"); 432202437Strasz gp = g_mountver_find_geom(mp, name); 433202437Strasz if (gp == NULL) { 434202437Strasz G_MOUNTVER_DEBUG(1, "Device %s is invalid.", name); 435202437Strasz gctl_error(req, "Device %s is invalid.", name); 436202437Strasz return; 437202437Strasz } 438202437Strasz error = g_mountver_destroy(gp, *force); 439202437Strasz if (error != 0) { 440202437Strasz gctl_error(req, "Cannot destroy device %s (error=%d).", 441202437Strasz gp->name, error); 442202437Strasz return; 443202437Strasz } 444202437Strasz } 445202437Strasz} 446202437Strasz 447202437Straszstatic void 448202437Straszg_mountver_orphan(struct g_consumer *cp) 449202437Strasz{ 450202437Strasz struct g_mountver_softc *sc; 451202437Strasz 452202437Strasz g_topology_assert(); 453202437Strasz 454202437Strasz sc = cp->geom->softc; 455202437Strasz sc->sc_orphaned = 1; 456202437Strasz if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 457202437Strasz g_access(cp, -cp->acr, -cp->acw, -cp->ace); 458202437Strasz g_detach(cp); 459202437Strasz G_MOUNTVER_DEBUG(0, "%s is offline. Mount verification in progress.", sc->sc_provider_name); 460202437Strasz} 461202437Strasz 462238218Straszstatic void 463238218Straszg_mountver_resize(struct g_consumer *cp) 464238218Strasz{ 465238218Strasz struct g_geom *gp; 466238218Strasz struct g_provider *pp; 467238218Strasz 468238218Strasz gp = cp->geom; 469238218Strasz 470238218Strasz LIST_FOREACH(pp, &gp->provider, provider) 471238218Strasz g_resize_provider(pp, cp->provider->mediasize); 472238218Strasz} 473238218Strasz 474202437Straszstatic int 475202437Straszg_mountver_ident_matches(struct g_geom *gp) 476202437Strasz{ 477202437Strasz struct g_consumer *cp; 478202437Strasz struct g_mountver_softc *sc; 479202437Strasz char ident[DISK_IDENT_SIZE]; 480202437Strasz int error, identsize = DISK_IDENT_SIZE; 481202437Strasz 482202437Strasz sc = gp->softc; 483202437Strasz cp = LIST_FIRST(&gp->consumer); 484202437Strasz 485202437Strasz if (g_mountver_check_ident == 0) 486202437Strasz return (0); 487202437Strasz 488202437Strasz error = g_access(cp, 1, 0, 0); 489202437Strasz if (error != 0) { 490202437Strasz G_MOUNTVER_DEBUG(0, "Cannot access %s; " 491202437Strasz "not attaching; error = %d.", gp->name, error); 492202437Strasz return (1); 493202437Strasz } 494202437Strasz error = g_io_getattr("GEOM::ident", cp, &identsize, ident); 495202437Strasz g_access(cp, -1, 0, 0); 496202437Strasz if (error != 0) { 497202437Strasz G_MOUNTVER_DEBUG(0, "Cannot get disk ident for %s; " 498202437Strasz "not attaching; error = %d.", gp->name, error); 499202437Strasz return (1); 500202437Strasz } 501202437Strasz if (strcmp(ident, sc->sc_ident) != 0) { 502202437Strasz G_MOUNTVER_DEBUG(1, "Disk ident for %s (\"%s\") is different " 503202437Strasz "from expected \"%s\", not attaching.", gp->name, ident, 504202437Strasz sc->sc_ident); 505202437Strasz return (1); 506202437Strasz } 507202437Strasz 508202437Strasz return (0); 509202437Strasz} 510202437Strasz 511202437Straszstatic struct g_geom * 512202437Straszg_mountver_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 513202437Strasz{ 514202437Strasz struct g_mountver_softc *sc; 515202437Strasz struct g_consumer *cp; 516202437Strasz struct g_geom *gp; 517202437Strasz int error; 518202437Strasz 519202437Strasz g_topology_assert(); 520202437Strasz g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 521202437Strasz G_MOUNTVER_DEBUG(2, "Tasting %s.", pp->name); 522202437Strasz 523202437Strasz /* 524202437Strasz * Let's check if device already exists. 525202437Strasz */ 526202437Strasz LIST_FOREACH(gp, &mp->geom, geom) { 527202437Strasz sc = gp->softc; 528202437Strasz if (sc == NULL) 529202437Strasz continue; 530202437Strasz 531202437Strasz /* Already attached? */ 532202437Strasz if (pp == LIST_FIRST(&gp->provider)) 533202437Strasz return (NULL); 534202437Strasz 535202437Strasz if (sc->sc_orphaned && strcmp(pp->name, sc->sc_provider_name) == 0) 536202437Strasz break; 537202437Strasz } 538202437Strasz if (gp == NULL) 539202437Strasz return (NULL); 540202437Strasz 541202437Strasz cp = LIST_FIRST(&gp->consumer); 542202437Strasz g_attach(cp, pp); 543202437Strasz error = g_mountver_ident_matches(gp); 544202437Strasz if (error != 0) { 545202437Strasz g_detach(cp); 546202437Strasz return (NULL); 547202437Strasz } 548202437Strasz if (sc->sc_access_r > 0 || sc->sc_access_w > 0 || sc->sc_access_e > 0) { 549202437Strasz error = g_access(cp, sc->sc_access_r, sc->sc_access_w, sc->sc_access_e); 550202437Strasz if (error != 0) { 551202437Strasz G_MOUNTVER_DEBUG(0, "Cannot access %s; error = %d.", pp->name, error); 552202437Strasz g_detach(cp); 553202437Strasz return (NULL); 554202437Strasz } 555202437Strasz } 556202437Strasz g_mountver_send_queued(gp); 557202437Strasz sc->sc_orphaned = 0; 558202437Strasz G_MOUNTVER_DEBUG(0, "%s has completed mount verification.", sc->sc_provider_name); 559202437Strasz 560202437Strasz return (gp); 561202437Strasz} 562202437Strasz 563202437Straszstatic void 564202437Straszg_mountver_config(struct gctl_req *req, struct g_class *mp, const char *verb) 565202437Strasz{ 566202437Strasz uint32_t *version; 567202437Strasz 568202437Strasz g_topology_assert(); 569202437Strasz 570202437Strasz version = gctl_get_paraml(req, "version", sizeof(*version)); 571202437Strasz if (version == NULL) { 572202437Strasz gctl_error(req, "No '%s' argument.", "version"); 573202437Strasz return; 574202437Strasz } 575202437Strasz if (*version != G_MOUNTVER_VERSION) { 576202437Strasz gctl_error(req, "Userland and kernel parts are out of sync."); 577202437Strasz return; 578202437Strasz } 579202437Strasz 580202437Strasz if (strcmp(verb, "create") == 0) { 581202437Strasz g_mountver_ctl_create(req, mp); 582202437Strasz return; 583202437Strasz } else if (strcmp(verb, "destroy") == 0) { 584202437Strasz g_mountver_ctl_destroy(req, mp); 585202437Strasz return; 586202437Strasz } 587202437Strasz 588202437Strasz gctl_error(req, "Unknown verb."); 589202437Strasz} 590202437Strasz 591202437Straszstatic void 592202437Straszg_mountver_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 593202437Strasz struct g_consumer *cp, struct g_provider *pp) 594202437Strasz{ 595202437Strasz struct g_mountver_softc *sc; 596202437Strasz 597202437Strasz if (pp != NULL || cp != NULL) 598202437Strasz return; 599202437Strasz 600202437Strasz sc = gp->softc; 601202437Strasz sbuf_printf(sb, "%s<State>%s</State>\n", indent, 602202437Strasz sc->sc_orphaned ? "OFFLINE" : "ONLINE"); 603202437Strasz sbuf_printf(sb, "%s<Provider-Name>%s</Provider-Name>\n", indent, sc->sc_provider_name); 604202437Strasz sbuf_printf(sb, "%s<Disk-Ident>%s</Disk-Ident>\n", indent, sc->sc_ident); 605202437Strasz} 606202437Strasz 607202437Straszstatic void 608202437Straszg_mountver_shutdown_pre_sync(void *arg, int howto) 609202437Strasz{ 610202437Strasz struct g_class *mp; 611202437Strasz struct g_geom *gp, *gp2; 612202437Strasz 613202437Strasz mp = arg; 614202437Strasz DROP_GIANT(); 615202437Strasz g_topology_lock(); 616202437Strasz LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) 617202437Strasz g_mountver_destroy(gp, 1); 618202437Strasz g_topology_unlock(); 619202437Strasz PICKUP_GIANT(); 620202437Strasz} 621202437Strasz 622202437Straszstatic void 623202437Straszg_mountver_init(struct g_class *mp) 624202437Strasz{ 625202437Strasz 626202437Strasz g_mountver_pre_sync = EVENTHANDLER_REGISTER(shutdown_pre_sync, 627202437Strasz g_mountver_shutdown_pre_sync, mp, SHUTDOWN_PRI_FIRST); 628202437Strasz if (g_mountver_pre_sync == NULL) 629202437Strasz G_MOUNTVER_DEBUG(0, "Warning! Cannot register shutdown event."); 630202437Strasz} 631202437Strasz 632202437Straszstatic void 633202437Straszg_mountver_fini(struct g_class *mp) 634202437Strasz{ 635202437Strasz 636202437Strasz if (g_mountver_pre_sync != NULL) 637202437Strasz EVENTHANDLER_DEREGISTER(shutdown_pre_sync, g_mountver_pre_sync); 638202437Strasz} 639202437Strasz 640202437StraszDECLARE_GEOM_CLASS(g_mountver_class, g_mountver); 641