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