1 /*- 2 * Copyright (c) 2010 Edward Tomasz Napierala <trasz@FreeBSD.org> 3 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@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 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 #include <sys/bio.h> 38 #include <sys/disk.h> 39 #include <sys/proc.h> 40 #include <sys/sbuf.h> 41 #include <sys/sysctl.h> 42 #include <sys/malloc.h> 43 #include <sys/eventhandler.h> 44 #include <geom/geom.h> 45 #include <geom/mountver/g_mountver.h> 46 47 48 SYSCTL_DECL(_kern_geom); 49 static SYSCTL_NODE(_kern_geom, OID_AUTO, mountver, CTLFLAG_RW, 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 85 g_mountver_done(struct bio *bp) 86 { 87 struct g_geom *gp; 88 struct bio *pbp; 89 90 if (bp->bio_error != ENXIO) { 91 g_std_done(bp); 92 return; 93 } 94 95 /* 96 * When the device goes away, it's possible that few requests 97 * will be completed with ENXIO before g_mountver_orphan() 98 * gets called. To work around that, we have to queue requests 99 * that failed with ENXIO, in order to send them later. 100 */ 101 gp = bp->bio_from->geom; 102 103 pbp = bp->bio_parent; 104 KASSERT(pbp->bio_to == LIST_FIRST(&gp->provider), 105 ("parent request was for someone else")); 106 g_destroy_bio(bp); 107 pbp->bio_inbed++; 108 g_mountver_queue(pbp); 109 } 110 111 static void 112 g_mountver_send(struct bio *bp) 113 { 114 struct g_geom *gp; 115 struct bio *cbp; 116 117 gp = bp->bio_to->geom; 118 119 cbp = g_clone_bio(bp); 120 if (cbp == NULL) { 121 g_io_deliver(bp, ENOMEM); 122 return; 123 } 124 125 cbp->bio_done = g_mountver_done; 126 g_io_request(cbp, LIST_FIRST(&gp->consumer)); 127 } 128 129 static void 130 g_mountver_queue(struct bio *bp) 131 { 132 struct g_mountver_softc *sc; 133 struct g_geom *gp; 134 135 gp = bp->bio_to->geom; 136 sc = gp->softc; 137 138 mtx_lock(&sc->sc_mtx); 139 TAILQ_INSERT_TAIL(&sc->sc_queue, bp, bio_queue); 140 mtx_unlock(&sc->sc_mtx); 141 } 142 143 static void 144 g_mountver_send_queued(struct g_geom *gp) 145 { 146 struct g_mountver_softc *sc; 147 struct bio *bp; 148 149 sc = gp->softc; 150 151 mtx_lock(&sc->sc_mtx); 152 while ((bp = TAILQ_FIRST(&sc->sc_queue)) != NULL) { 153 TAILQ_REMOVE(&sc->sc_queue, bp, bio_queue); 154 G_MOUNTVER_LOGREQ(bp, "Sending queued request."); 155 g_mountver_send(bp); 156 } 157 mtx_unlock(&sc->sc_mtx); 158 } 159 160 static void 161 g_mountver_discard_queued(struct g_geom *gp) 162 { 163 struct g_mountver_softc *sc; 164 struct bio *bp; 165 166 sc = gp->softc; 167 168 mtx_lock(&sc->sc_mtx); 169 while ((bp = TAILQ_FIRST(&sc->sc_queue)) != NULL) { 170 TAILQ_REMOVE(&sc->sc_queue, bp, bio_queue); 171 G_MOUNTVER_LOGREQ(bp, "Discarding queued request."); 172 g_io_deliver(bp, ENXIO); 173 } 174 mtx_unlock(&sc->sc_mtx); 175 } 176 177 static void 178 g_mountver_start(struct bio *bp) 179 { 180 struct g_mountver_softc *sc; 181 struct g_geom *gp; 182 183 gp = bp->bio_to->geom; 184 sc = gp->softc; 185 G_MOUNTVER_LOGREQ(bp, "Request received."); 186 187 /* 188 * It is possible that some bios were returned with ENXIO, even though 189 * orphaning didn't happen yet. In that case, queue all subsequent 190 * requests in order to maintain ordering. 191 */ 192 if (sc->sc_orphaned || !TAILQ_EMPTY(&sc->sc_queue)) { 193 if (sc->sc_shutting_down) { 194 G_MOUNTVER_LOGREQ(bp, "Discarding request due to shutdown."); 195 g_io_deliver(bp, ENXIO); 196 return; 197 } 198 G_MOUNTVER_LOGREQ(bp, "Queueing request."); 199 g_mountver_queue(bp); 200 if (!sc->sc_orphaned) 201 g_mountver_send_queued(gp); 202 } else { 203 G_MOUNTVER_LOGREQ(bp, "Sending request."); 204 g_mountver_send(bp); 205 } 206 } 207 208 static int 209 g_mountver_access(struct g_provider *pp, int dr, int dw, int de) 210 { 211 struct g_mountver_softc *sc; 212 struct g_geom *gp; 213 struct g_consumer *cp; 214 215 g_topology_assert(); 216 217 gp = pp->geom; 218 cp = LIST_FIRST(&gp->consumer); 219 sc = gp->softc; 220 if (sc == NULL && dr <= 0 && dw <= 0 && de <= 0) 221 return (0); 222 KASSERT(sc != NULL, ("Trying to access withered provider \"%s\".", pp->name)); 223 224 sc->sc_access_r += dr; 225 sc->sc_access_w += dw; 226 sc->sc_access_e += de; 227 228 if (sc->sc_orphaned) 229 return (0); 230 231 return (g_access(cp, dr, dw, de)); 232 } 233 234 static int 235 g_mountver_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp) 236 { 237 struct g_mountver_softc *sc; 238 struct g_geom *gp; 239 struct g_provider *newpp; 240 struct g_consumer *cp; 241 char name[64]; 242 int error; 243 int identsize = DISK_IDENT_SIZE; 244 245 g_topology_assert(); 246 247 gp = NULL; 248 newpp = NULL; 249 cp = NULL; 250 251 snprintf(name, sizeof(name), "%s%s", pp->name, G_MOUNTVER_SUFFIX); 252 LIST_FOREACH(gp, &mp->geom, geom) { 253 if (strcmp(gp->name, name) == 0) { 254 gctl_error(req, "Provider %s already exists.", name); 255 return (EEXIST); 256 } 257 } 258 gp = g_new_geomf(mp, "%s", name); 259 sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 260 mtx_init(&sc->sc_mtx, "gmountver", NULL, MTX_DEF); 261 TAILQ_INIT(&sc->sc_queue); 262 sc->sc_provider_name = strdup(pp->name, M_GEOM); 263 gp->softc = sc; 264 gp->start = g_mountver_start; 265 gp->orphan = g_mountver_orphan; 266 gp->resize = g_mountver_resize; 267 gp->access = g_mountver_access; 268 gp->dumpconf = g_mountver_dumpconf; 269 270 newpp = g_new_providerf(gp, "%s", gp->name); 271 newpp->mediasize = pp->mediasize; 272 newpp->sectorsize = pp->sectorsize; 273 274 if ((pp->flags & G_PF_ACCEPT_UNMAPPED) != 0) { 275 G_MOUNTVER_DEBUG(0, "Unmapped supported for %s.", gp->name); 276 newpp->flags |= G_PF_ACCEPT_UNMAPPED; 277 } else { 278 G_MOUNTVER_DEBUG(0, "Unmapped unsupported for %s.", gp->name); 279 newpp->flags &= ~G_PF_ACCEPT_UNMAPPED; 280 } 281 282 cp = g_new_consumer(gp); 283 error = g_attach(cp, pp); 284 if (error != 0) { 285 gctl_error(req, "Cannot attach to provider %s.", pp->name); 286 goto fail; 287 } 288 error = g_access(cp, 1, 0, 0); 289 if (error != 0) { 290 gctl_error(req, "Cannot access provider %s.", pp->name); 291 goto fail; 292 } 293 error = g_io_getattr("GEOM::ident", cp, &identsize, sc->sc_ident); 294 g_access(cp, -1, 0, 0); 295 if (error != 0) { 296 if (g_mountver_check_ident) { 297 gctl_error(req, "Cannot get disk ident from %s; error = %d.", pp->name, error); 298 goto fail; 299 } 300 301 G_MOUNTVER_DEBUG(0, "Cannot get disk ident from %s; error = %d.", pp->name, error); 302 sc->sc_ident[0] = '\0'; 303 } 304 305 g_error_provider(newpp, 0); 306 G_MOUNTVER_DEBUG(0, "Device %s created.", gp->name); 307 return (0); 308 fail: 309 g_free(sc->sc_provider_name); 310 if (cp->provider != NULL) 311 g_detach(cp); 312 g_destroy_consumer(cp); 313 g_destroy_provider(newpp); 314 g_free(gp->softc); 315 g_destroy_geom(gp); 316 return (error); 317 } 318 319 static int 320 g_mountver_destroy(struct g_geom *gp, boolean_t force) 321 { 322 struct g_mountver_softc *sc; 323 struct g_provider *pp; 324 325 g_topology_assert(); 326 if (gp->softc == NULL) 327 return (ENXIO); 328 sc = gp->softc; 329 pp = LIST_FIRST(&gp->provider); 330 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 331 if (force) { 332 G_MOUNTVER_DEBUG(0, "Device %s is still open, so it " 333 "can't be definitely removed.", pp->name); 334 } else { 335 G_MOUNTVER_DEBUG(1, "Device %s is still open (r%dw%de%d).", 336 pp->name, pp->acr, pp->acw, pp->ace); 337 return (EBUSY); 338 } 339 } else { 340 G_MOUNTVER_DEBUG(0, "Device %s removed.", gp->name); 341 } 342 if (pp != NULL) 343 g_wither_provider(pp, ENXIO); 344 g_mountver_discard_queued(gp); 345 g_free(sc->sc_provider_name); 346 g_free(gp->softc); 347 gp->softc = NULL; 348 g_wither_geom(gp, ENXIO); 349 350 return (0); 351 } 352 353 static int 354 g_mountver_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) 355 { 356 357 return (g_mountver_destroy(gp, 0)); 358 } 359 360 static void 361 g_mountver_ctl_create(struct gctl_req *req, struct g_class *mp) 362 { 363 struct g_provider *pp; 364 const char *name; 365 char param[16]; 366 int i, *nargs; 367 368 g_topology_assert(); 369 370 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 371 if (nargs == NULL) { 372 gctl_error(req, "No '%s' argument", "nargs"); 373 return; 374 } 375 if (*nargs <= 0) { 376 gctl_error(req, "Missing device(s)."); 377 return; 378 } 379 for (i = 0; i < *nargs; i++) { 380 snprintf(param, sizeof(param), "arg%d", i); 381 name = gctl_get_asciiparam(req, param); 382 if (name == NULL) { 383 gctl_error(req, "No 'arg%d' argument", i); 384 return; 385 } 386 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 387 name += strlen("/dev/"); 388 pp = g_provider_by_name(name); 389 if (pp == NULL) { 390 G_MOUNTVER_DEBUG(1, "Provider %s is invalid.", name); 391 gctl_error(req, "Provider %s is invalid.", name); 392 return; 393 } 394 if (g_mountver_create(req, mp, pp) != 0) 395 return; 396 } 397 } 398 399 static struct g_geom * 400 g_mountver_find_geom(struct g_class *mp, const char *name) 401 { 402 struct g_geom *gp; 403 404 LIST_FOREACH(gp, &mp->geom, geom) { 405 if (strcmp(gp->name, name) == 0) 406 return (gp); 407 } 408 return (NULL); 409 } 410 411 static void 412 g_mountver_ctl_destroy(struct gctl_req *req, struct g_class *mp) 413 { 414 int *nargs, *force, error, i; 415 struct g_geom *gp; 416 const char *name; 417 char param[16]; 418 419 g_topology_assert(); 420 421 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 422 if (nargs == NULL) { 423 gctl_error(req, "No '%s' argument", "nargs"); 424 return; 425 } 426 if (*nargs <= 0) { 427 gctl_error(req, "Missing device(s)."); 428 return; 429 } 430 force = gctl_get_paraml(req, "force", sizeof(*force)); 431 if (force == NULL) { 432 gctl_error(req, "No 'force' argument"); 433 return; 434 } 435 436 for (i = 0; i < *nargs; i++) { 437 snprintf(param, sizeof(param), "arg%d", i); 438 name = gctl_get_asciiparam(req, param); 439 if (name == NULL) { 440 gctl_error(req, "No 'arg%d' argument", i); 441 return; 442 } 443 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 444 name += strlen("/dev/"); 445 gp = g_mountver_find_geom(mp, name); 446 if (gp == NULL) { 447 G_MOUNTVER_DEBUG(1, "Device %s is invalid.", name); 448 gctl_error(req, "Device %s is invalid.", name); 449 return; 450 } 451 error = g_mountver_destroy(gp, *force); 452 if (error != 0) { 453 gctl_error(req, "Cannot destroy device %s (error=%d).", 454 gp->name, error); 455 return; 456 } 457 } 458 } 459 460 static void 461 g_mountver_orphan(struct g_consumer *cp) 462 { 463 struct g_mountver_softc *sc; 464 465 g_topology_assert(); 466 467 sc = cp->geom->softc; 468 sc->sc_orphaned = 1; 469 if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 470 g_access(cp, -cp->acr, -cp->acw, -cp->ace); 471 g_detach(cp); 472 G_MOUNTVER_DEBUG(0, "%s is offline. Mount verification in progress.", sc->sc_provider_name); 473 } 474 475 static void 476 g_mountver_resize(struct g_consumer *cp) 477 { 478 struct g_geom *gp; 479 struct g_provider *pp; 480 481 gp = cp->geom; 482 483 LIST_FOREACH(pp, &gp->provider, provider) 484 g_resize_provider(pp, cp->provider->mediasize); 485 } 486 487 static int 488 g_mountver_ident_matches(struct g_geom *gp) 489 { 490 struct g_consumer *cp; 491 struct g_mountver_softc *sc; 492 char ident[DISK_IDENT_SIZE]; 493 int error, identsize = DISK_IDENT_SIZE; 494 495 sc = gp->softc; 496 cp = LIST_FIRST(&gp->consumer); 497 498 if (g_mountver_check_ident == 0) 499 return (0); 500 501 error = g_access(cp, 1, 0, 0); 502 if (error != 0) { 503 G_MOUNTVER_DEBUG(0, "Cannot access %s; " 504 "not attaching; error = %d.", gp->name, error); 505 return (1); 506 } 507 error = g_io_getattr("GEOM::ident", cp, &identsize, ident); 508 g_access(cp, -1, 0, 0); 509 if (error != 0) { 510 G_MOUNTVER_DEBUG(0, "Cannot get disk ident for %s; " 511 "not attaching; error = %d.", gp->name, error); 512 return (1); 513 } 514 if (strcmp(ident, sc->sc_ident) != 0) { 515 G_MOUNTVER_DEBUG(1, "Disk ident for %s (\"%s\") is different " 516 "from expected \"%s\", not attaching.", gp->name, ident, 517 sc->sc_ident); 518 return (1); 519 } 520 521 return (0); 522 } 523 524 static struct g_geom * 525 g_mountver_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 526 { 527 struct g_mountver_softc *sc; 528 struct g_consumer *cp; 529 struct g_geom *gp; 530 int error; 531 532 g_topology_assert(); 533 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 534 G_MOUNTVER_DEBUG(2, "Tasting %s.", pp->name); 535 536 /* 537 * Let's check if device already exists. 538 */ 539 LIST_FOREACH(gp, &mp->geom, geom) { 540 sc = gp->softc; 541 if (sc == NULL) 542 continue; 543 544 /* Already attached? */ 545 if (pp == LIST_FIRST(&gp->provider)) 546 return (NULL); 547 548 if (sc->sc_orphaned && strcmp(pp->name, sc->sc_provider_name) == 0) 549 break; 550 } 551 if (gp == NULL) 552 return (NULL); 553 554 cp = LIST_FIRST(&gp->consumer); 555 g_attach(cp, pp); 556 error = g_mountver_ident_matches(gp); 557 if (error != 0) { 558 g_detach(cp); 559 return (NULL); 560 } 561 if (sc->sc_access_r > 0 || sc->sc_access_w > 0 || sc->sc_access_e > 0) { 562 error = g_access(cp, sc->sc_access_r, sc->sc_access_w, sc->sc_access_e); 563 if (error != 0) { 564 G_MOUNTVER_DEBUG(0, "Cannot access %s; error = %d.", pp->name, error); 565 g_detach(cp); 566 return (NULL); 567 } 568 } 569 g_mountver_send_queued(gp); 570 sc->sc_orphaned = 0; 571 G_MOUNTVER_DEBUG(0, "%s has completed mount verification.", sc->sc_provider_name); 572 573 return (gp); 574 } 575 576 static void 577 g_mountver_config(struct gctl_req *req, struct g_class *mp, const char *verb) 578 { 579 uint32_t *version; 580 581 g_topology_assert(); 582 583 version = gctl_get_paraml(req, "version", sizeof(*version)); 584 if (version == NULL) { 585 gctl_error(req, "No '%s' argument.", "version"); 586 return; 587 } 588 if (*version != G_MOUNTVER_VERSION) { 589 gctl_error(req, "Userland and kernel parts are out of sync."); 590 return; 591 } 592 593 if (strcmp(verb, "create") == 0) { 594 g_mountver_ctl_create(req, mp); 595 return; 596 } else if (strcmp(verb, "destroy") == 0) { 597 g_mountver_ctl_destroy(req, mp); 598 return; 599 } 600 601 gctl_error(req, "Unknown verb."); 602 } 603 604 static void 605 g_mountver_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 606 struct g_consumer *cp, struct g_provider *pp) 607 { 608 struct g_mountver_softc *sc; 609 610 if (pp != NULL || cp != NULL) 611 return; 612 613 sc = gp->softc; 614 sbuf_printf(sb, "%s<State>%s</State>\n", indent, 615 sc->sc_orphaned ? "OFFLINE" : "ONLINE"); 616 sbuf_printf(sb, "%s<Provider-Name>%s</Provider-Name>\n", indent, sc->sc_provider_name); 617 sbuf_printf(sb, "%s<Disk-Ident>%s</Disk-Ident>\n", indent, sc->sc_ident); 618 } 619 620 static void 621 g_mountver_shutdown_pre_sync(void *arg, int howto) 622 { 623 struct g_mountver_softc *sc; 624 struct g_class *mp; 625 struct g_geom *gp, *gp2; 626 627 mp = arg; 628 g_topology_lock(); 629 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 630 if (gp->softc == NULL) 631 continue; 632 sc = gp->softc; 633 sc->sc_shutting_down = 1; 634 if (sc->sc_orphaned) 635 g_mountver_destroy(gp, 1); 636 } 637 g_topology_unlock(); 638 } 639 640 static void 641 g_mountver_init(struct g_class *mp) 642 { 643 644 g_mountver_pre_sync = EVENTHANDLER_REGISTER(shutdown_pre_sync, 645 g_mountver_shutdown_pre_sync, mp, SHUTDOWN_PRI_FIRST); 646 if (g_mountver_pre_sync == NULL) 647 G_MOUNTVER_DEBUG(0, "Warning! Cannot register shutdown event."); 648 } 649 650 static void 651 g_mountver_fini(struct g_class *mp) 652 { 653 654 if (g_mountver_pre_sync != NULL) 655 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, g_mountver_pre_sync); 656 } 657 658 DECLARE_GEOM_CLASS(g_mountver_class, g_mountver); 659