geom_subr.c revision 122888
1169689Skan/*- 2132718Skan * Copyright (c) 2002 Poul-Henning Kamp 3132718Skan * Copyright (c) 2002 Networks Associates Technology, Inc. 4132718Skan * All rights reserved. 5132718Skan * 6132718Skan * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7132718Skan * and NAI Labs, the Security Research Division of Network Associates, Inc. 8132718Skan * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9132718Skan * DARPA CHATS research program. 10132718Skan * 11132718Skan * Redistribution and use in source and binary forms, with or without 12132718Skan * modification, are permitted provided that the following conditions 13132718Skan * are met: 14132718Skan * 1. Redistributions of source code must retain the above copyright 15132718Skan * notice, this list of conditions and the following disclaimer. 16132718Skan * 2. Redistributions in binary form must reproduce the above copyright 17169689Skan * notice, this list of conditions and the following disclaimer in the 18169689Skan * documentation and/or other materials provided with the distribution. 19132718Skan * 3. The names of the authors may not be used to endorse or promote 20132718Skan * products derived from this software without specific prior written 21132718Skan * permission. 22132718Skan * 23132718Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33132718Skan * SUCH DAMAGE. 34169689Skan */ 35169689Skan 36169689Skan#include <sys/cdefs.h> 37132718Skan__FBSDID("$FreeBSD: head/sys/geom/geom_subr.c 122888 2003-11-18 18:17:39Z phk $"); 38132718Skan 39132718Skan#include <sys/param.h> 40132718Skan#include <sys/systm.h> 41132718Skan#include <sys/devicestat.h> 42132718Skan#include <sys/kernel.h> 43132718Skan#include <sys/malloc.h> 44132718Skan#include <sys/bio.h> 45132718Skan#include <sys/sysctl.h> 46132718Skan#include <sys/proc.h> 47132718Skan#include <sys/kthread.h> 48132718Skan#include <sys/lock.h> 49132718Skan#include <sys/mutex.h> 50132718Skan#include <sys/errno.h> 51132718Skan#include <sys/sbuf.h> 52132718Skan#include <geom/geom.h> 53132718Skan#include <geom/geom_int.h> 54132718Skan#include <machine/stdarg.h> 55132718Skan 56132718Skanstruct class_list_head g_classes = LIST_HEAD_INITIALIZER(g_classes); 57132718Skanstatic struct g_tailq_head geoms = TAILQ_HEAD_INITIALIZER(geoms); 58132718Skanchar *g_wait_event, *g_wait_up, *g_wait_down, *g_wait_sim; 59132718Skan 60132718Skanstatic int g_valid_obj(void const *ptr); 61132718Skan 62132718Skanstruct g_hh00 { 63132718Skan struct g_class *mp; 64132718Skan int error; 65132718Skan}; 66132718Skan 67132718Skan/* 68132718Skan * This event offers a new class a chance to taste all preexisting providers. 69132718Skan */ 70132718Skanstatic void 71132718Skang_load_class(void *arg, int flag) 72132718Skan{ 73132718Skan struct g_hh00 *hh; 74132718Skan struct g_class *mp2, *mp; 75132718Skan struct g_geom *gp; 76132718Skan struct g_provider *pp; 77132718Skan 78132718Skan g_topology_assert(); 79132718Skan if (flag == EV_CANCEL) /* XXX: can't happen ? */ 80132718Skan return; 81132718Skan if (g_shutdown) 82132718Skan return; 83132718Skan 84132718Skan hh = arg; 85132718Skan mp = hh->mp; 86132718Skan g_free(hh); 87132718Skan g_trace(G_T_TOPOLOGY, "g_load_class(%s)", mp->name); 88132718Skan LIST_FOREACH(mp2, &g_classes, class) { 89132718Skan KASSERT(mp2 != mp, 90132718Skan ("The GEOM class %s already loaded", mp2->name)); 91132718Skan KASSERT(strcmp(mp2->name, mp->name) != 0, 92132718Skan ("A GEOM class named %s is already loaded", mp2->name)); 93132718Skan } 94132718Skan 95132718Skan LIST_INIT(&mp->geom); 96132718Skan LIST_INSERT_HEAD(&g_classes, mp, class); 97132718Skan if (mp->init != NULL) 98132718Skan mp->init(mp); 99132718Skan if (mp->taste == NULL) 100132718Skan return; 101132718Skan LIST_FOREACH(mp2, &g_classes, class) { 102132718Skan if (mp == mp2) 103132718Skan continue; 104132718Skan LIST_FOREACH(gp, &mp2->geom, geom) { 105132718Skan LIST_FOREACH(pp, &gp->provider, provider) { 106132718Skan mp->taste(mp, pp, 0); 107132718Skan g_topology_assert(); 108132718Skan } 109132718Skan } 110132718Skan } 111132718Skan} 112132718Skan 113132718Skanstatic void 114132718Skang_unload_class(void *arg, int flag) 115132718Skan{ 116132718Skan struct g_hh00 *hh; 117132718Skan struct g_class *mp; 118132718Skan struct g_geom *gp; 119132718Skan struct g_provider *pp; 120132718Skan struct g_consumer *cp; 121132718Skan int error; 122132718Skan 123132718Skan g_topology_assert(); 124132718Skan hh = arg; 125132718Skan mp = hh->mp; 126132718Skan g_trace(G_T_TOPOLOGY, "g_unload_class(%s)", mp->name); 127132718Skan if (mp->destroy_geom == NULL) { 128132718Skan hh->error = EOPNOTSUPP; 129132718Skan return; 130132718Skan } 131132718Skan 132132718Skan /* We refuse to unload if anything is open */ 133132718Skan LIST_FOREACH(gp, &mp->geom, geom) { 134132718Skan LIST_FOREACH(pp, &gp->provider, provider) 135132718Skan if (pp->acr || pp->acw || pp->ace) { 136132718Skan hh->error = EBUSY; 137132718Skan return; 138132718Skan } 139132718Skan LIST_FOREACH(cp, &gp->consumer, consumer) 140132718Skan if (cp->acr || cp->acw || cp->ace) { 141132718Skan hh->error = EBUSY; 142132718Skan return; 143132718Skan } 144132718Skan } 145132718Skan 146132718Skan /* Bar new entries */ 147132718Skan mp->taste = NULL; 148132718Skan mp->config = NULL; 149132718Skan 150132718Skan error = 0; 151132718Skan LIST_FOREACH(gp, &mp->geom, geom) { 152132718Skan error = mp->destroy_geom(NULL, mp, gp); 153132718Skan if (error != 0) 154132718Skan break; 155132718Skan } 156132718Skan if (error == 0) { 157132718Skan if (mp->fini != NULL) 158132718Skan mp->fini(mp); 159132718Skan LIST_REMOVE(mp, class); 160132718Skan } 161132718Skan hh->error = error; 162132718Skan return; 163132718Skan} 164132718Skan 165132718Skanint 166132718Skang_modevent(module_t mod, int type, void *data) 167132718Skan{ 168132718Skan struct g_hh00 *hh; 169132718Skan int error; 170132718Skan static int g_ignition; 171132718Skan 172132718Skan if (!g_ignition) { 173132718Skan g_ignition++; 174132718Skan g_init(); 175132718Skan } 176132718Skan hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO); 177132718Skan hh->mp = data; 178132718Skan error = EOPNOTSUPP; 179132718Skan switch (type) { 180132718Skan case MOD_LOAD: 181132718Skan g_trace(G_T_TOPOLOGY, "g_modevent(%s, LOAD)", hh->mp->name); 182132718Skan g_post_event(g_load_class, hh, M_WAITOK, NULL); 183132718Skan error = 0; 184132718Skan break; 185132718Skan case MOD_UNLOAD: 186132718Skan g_trace(G_T_TOPOLOGY, "g_modevent(%s, UNLOAD)", hh->mp->name); 187132718Skan error = g_waitfor_event(g_unload_class, hh, M_WAITOK, NULL); 188132718Skan if (error == 0) 189132718Skan error = hh->error; 190132718Skan if (error == 0) { 191132718Skan g_waitidle(); 192132718Skan KASSERT(LIST_EMPTY(&hh->mp->geom), 193132718Skan ("Unloaded class (%s) still has geom", hh->mp->name)); 194132718Skan } 195132718Skan g_free(hh); 196132718Skan break; 197132718Skan } 198132718Skan return (error); 199132718Skan} 200132718Skan 201132718Skanstruct g_geom * 202132718Skang_new_geomf(struct g_class *mp, const char *fmt, ...) 203132718Skan{ 204132718Skan struct g_geom *gp; 205132718Skan va_list ap; 206132718Skan struct sbuf *sb; 207132718Skan 208132718Skan g_topology_assert(); 209132718Skan KASSERT(g_valid_obj(mp), ("g_new_geom_f() on alien class %p", mp)); 210132718Skan sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 211132718Skan va_start(ap, fmt); 212132718Skan sbuf_vprintf(sb, fmt, ap); 213132718Skan va_end(ap); 214132718Skan sbuf_finish(sb); 215132718Skan gp = g_malloc(sizeof *gp, M_WAITOK | M_ZERO); 216132718Skan gp->name = g_malloc(sbuf_len(sb) + 1, M_WAITOK | M_ZERO); 217132718Skan gp->class = mp; 218132718Skan gp->rank = 1; 219132718Skan LIST_INIT(&gp->consumer); 220132718Skan LIST_INIT(&gp->provider); 221132718Skan LIST_INSERT_HEAD(&mp->geom, gp, geom); 222132718Skan TAILQ_INSERT_HEAD(&geoms, gp, geoms); 223132718Skan strcpy(gp->name, sbuf_data(sb)); 224132718Skan sbuf_delete(sb); 225132718Skan return (gp); 226132718Skan} 227132718Skan 228132718Skanvoid 229132718Skang_destroy_geom(struct g_geom *gp) 230132718Skan{ 231132718Skan 232132718Skan g_trace(G_T_TOPOLOGY, "g_destroy_geom(%p(%s))", gp, gp->name); 233132718Skan g_topology_assert(); 234132718Skan KASSERT(LIST_EMPTY(&gp->consumer), 235132718Skan ("g_destroy_geom(%s) with consumer(s) [%p]", 236132718Skan gp->name, LIST_FIRST(&gp->consumer))); 237132718Skan KASSERT(LIST_EMPTY(&gp->provider), 238132718Skan ("g_destroy_geom(%s) with provider(s) [%p]", 239132718Skan gp->name, LIST_FIRST(&gp->consumer))); 240132718Skan g_cancel_event(gp); 241132718Skan LIST_REMOVE(gp, geom); 242132718Skan TAILQ_REMOVE(&geoms, gp, geoms); 243132718Skan g_free(gp->name); 244132718Skan g_free(gp); 245132718Skan} 246132718Skan 247132718Skan/* 248132718Skan * This function is called (repeatedly) until has withered away. 249132718Skan */ 250132718Skanvoid 251132718Skang_wither_geom(struct g_geom *gp, int error) 252132718Skan{ 253132718Skan struct g_provider *pp, *pp2; 254132718Skan struct g_consumer *cp, *cp2; 255132718Skan static int once_is_enough; 256132718Skan 257132718Skan if (once_is_enough) 258132718Skan return; 259132718Skan once_is_enough = 1; 260132718Skan g_trace(G_T_TOPOLOGY, "g_wither_geom(%p(%s))", gp, gp->name); 261132718Skan g_topology_assert(); 262132718Skan if (!(gp->flags & G_GEOM_WITHER)) { 263132718Skan gp->flags |= G_GEOM_WITHER; 264132718Skan LIST_FOREACH(pp, &gp->provider, provider) 265132718Skan g_orphan_provider(pp, error); 266132718Skan } 267132718Skan for (pp = LIST_FIRST(&gp->provider); pp != NULL; pp = pp2) { 268132718Skan pp2 = LIST_NEXT(pp, provider); 269132718Skan if (!LIST_EMPTY(&pp->consumers)) 270132718Skan continue; 271132718Skan g_destroy_provider(pp); 272132718Skan } 273132718Skan for (cp = LIST_FIRST(&gp->consumer); cp != NULL; cp = cp2) { 274132718Skan cp2 = LIST_NEXT(cp, consumer); 275132718Skan if (cp->acr || cp->acw || cp->ace) 276132718Skan continue; 277132718Skan g_detach(cp); 278132718Skan g_destroy_consumer(cp); 279132718Skan } 280132718Skan if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer)) 281132718Skan g_destroy_geom(gp); 282132718Skan once_is_enough = 0; 283132718Skan} 284132718Skan 285132718Skanstruct g_consumer * 286132718Skang_new_consumer(struct g_geom *gp) 287132718Skan{ 288132718Skan struct g_consumer *cp; 289132718Skan 290132718Skan g_topology_assert(); 291132718Skan KASSERT(gp->orphan != NULL, 292132718Skan ("g_new_consumer on geom(%s) (class %s) without orphan", 293132718Skan gp->name, gp->class->name)); 294132718Skan 295132718Skan cp = g_malloc(sizeof *cp, M_WAITOK | M_ZERO); 296132718Skan cp->geom = gp; 297132718Skan cp->stat = devstat_new_entry(cp, -1, 0, DEVSTAT_ALL_SUPPORTED, 298132718Skan DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); 299132718Skan LIST_INSERT_HEAD(&gp->consumer, cp, consumer); 300132718Skan return(cp); 301132718Skan} 302132718Skan 303132718Skanvoid 304132718Skang_destroy_consumer(struct g_consumer *cp) 305132718Skan{ 306132718Skan struct g_geom *gp; 307132718Skan 308132718Skan g_trace(G_T_TOPOLOGY, "g_destroy_consumer(%p)", cp); 309132718Skan g_topology_assert(); 310132718Skan KASSERT (cp->provider == NULL, ("g_destroy_consumer but attached")); 311132718Skan KASSERT (cp->acr == 0, ("g_destroy_consumer with acr")); 312132718Skan KASSERT (cp->acw == 0, ("g_destroy_consumer with acw")); 313132718Skan KASSERT (cp->ace == 0, ("g_destroy_consumer with ace")); 314132718Skan g_cancel_event(cp); 315132718Skan gp = cp->geom; 316132718Skan LIST_REMOVE(cp, consumer); 317132718Skan devstat_remove_entry(cp->stat); 318132718Skan g_free(cp); 319132718Skan if (gp->flags & G_GEOM_WITHER) 320132718Skan g_wither_geom(gp, 0); 321132718Skan} 322132718Skan 323132718Skanstatic void 324132718Skang_new_provider_event(void *arg, int flag) 325132718Skan{ 326132718Skan struct g_class *mp; 327132718Skan struct g_provider *pp; 328132718Skan struct g_consumer *cp; 329132718Skan int i; 330132718Skan 331132718Skan g_topology_assert(); 332132718Skan if (flag == EV_CANCEL) 333132718Skan return; 334132718Skan if (g_shutdown) 335132718Skan return; 336132718Skan pp = arg; 337132718Skan LIST_FOREACH(mp, &g_classes, class) { 338132718Skan if (mp->taste == NULL) 339132718Skan continue; 340132718Skan i = 1; 341132718Skan LIST_FOREACH(cp, &pp->consumers, consumers) 342132718Skan if (cp->geom->class == mp) 343132718Skan i = 0; 344132718Skan if (!i) 345132718Skan continue; 346132718Skan mp->taste(mp, pp, 0); 347132718Skan g_topology_assert(); 348132718Skan /* 349132718Skan * XXX: Bandaid for 5.2-RELEASE 350132718Skan * XXX: DO NOT REPLICATE THIS CODE! 351132718Skan */ 352132718Skan if (!g_valid_obj(pp)) { 353132718Skan printf("g_provider %p disappeared while tasting\n", pp); 354132718Skan return; 355132718Skan } 356132718Skan } 357132718Skan} 358132718Skan 359132718Skan 360132718Skanstruct g_provider * 361132718Skang_new_providerf(struct g_geom *gp, const char *fmt, ...) 362132718Skan{ 363132718Skan struct g_provider *pp; 364132718Skan struct sbuf *sb; 365132718Skan va_list ap; 366132718Skan 367132718Skan g_topology_assert(); 368132718Skan sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 369132718Skan va_start(ap, fmt); 370132718Skan sbuf_vprintf(sb, fmt, ap); 371132718Skan va_end(ap); 372132718Skan sbuf_finish(sb); 373132718Skan pp = g_malloc(sizeof *pp + sbuf_len(sb) + 1, M_WAITOK | M_ZERO); 374132718Skan pp->name = (char *)(pp + 1); 375132718Skan strcpy(pp->name, sbuf_data(sb)); 376132718Skan sbuf_delete(sb); 377132718Skan LIST_INIT(&pp->consumers); 378132718Skan pp->error = ENXIO; 379132718Skan pp->geom = gp; 380132718Skan pp->stat = devstat_new_entry(pp, -1, 0, DEVSTAT_ALL_SUPPORTED, 381132718Skan DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); 382132718Skan LIST_INSERT_HEAD(&gp->provider, pp, provider); 383132718Skan g_post_event(g_new_provider_event, pp, M_WAITOK, pp, NULL); 384132718Skan return (pp); 385132718Skan} 386132718Skan 387132718Skanvoid 388132718Skang_error_provider(struct g_provider *pp, int error) 389132718Skan{ 390132718Skan 391132718Skan pp->error = error; 392132718Skan} 393132718Skan 394132718Skanstruct g_provider * 395132718Skang_provider_by_name(char const *arg) 396132718Skan{ 397132718Skan struct g_class *cp; 398132718Skan struct g_geom *gp; 399132718Skan struct g_provider *pp; 400132718Skan 401132718Skan LIST_FOREACH(cp, &g_classes, class) { 402132718Skan LIST_FOREACH(gp, &cp->geom, geom) { 403132718Skan LIST_FOREACH(pp, &gp->provider, provider) { 404132718Skan if (!strcmp(arg, pp->name)) 405132718Skan return (pp); 406132718Skan } 407132718Skan } 408132718Skan } 409132718Skan return (NULL); 410132718Skan} 411132718Skan 412132718Skanvoid 413132718Skang_destroy_provider(struct g_provider *pp) 414132718Skan{ 415132718Skan struct g_geom *gp; 416132718Skan 417132718Skan g_topology_assert(); 418132718Skan KASSERT(LIST_EMPTY(&pp->consumers), 419132718Skan ("g_destroy_provider but attached")); 420132718Skan KASSERT (pp->acr == 0, ("g_destroy_provider with acr")); 421132718Skan KASSERT (pp->acw == 0, ("g_destroy_provider with acw")); 422169689Skan KASSERT (pp->acw == 0, ("g_destroy_provider with ace")); 423132718Skan g_cancel_event(pp); 424132718Skan LIST_REMOVE(pp, provider); 425132718Skan gp = pp->geom; 426132718Skan devstat_remove_entry(pp->stat); 427132718Skan g_free(pp); 428132718Skan if ((gp->flags & G_GEOM_WITHER)) 429132718Skan g_wither_geom(gp, 0); 430169689Skan} 431132718Skan 432132718Skan/* 433132718Skan * We keep the "geoms" list sorted by topological order (== increasing 434132718Skan * numerical rank) at all times. 435132718Skan * When an attach is done, the attaching geoms rank is invalidated 436132718Skan * and it is moved to the tail of the list. 437132718Skan * All geoms later in the sequence has their ranks reevaluated in 438132718Skan * sequence. If we cannot assign rank to a geom because it's 439132718Skan * prerequisites do not have rank, we move that element to the tail 440132718Skan * of the sequence with invalid rank as well. 441132718Skan * At some point we encounter our original geom and if we stil fail 442132718Skan * to assign it a rank, there must be a loop and we fail back to 443132718Skan * g_attach() which detach again and calls redo_rank again 444132718Skan * to fix up the damage. 445132718Skan * It would be much simpler code wise to do it recursively, but we 446132718Skan * can't risk that on the kernel stack. 447132718Skan */ 448132718Skan 449132718Skanstatic int 450132718Skanredo_rank(struct g_geom *gp) 451132718Skan{ 452132718Skan struct g_consumer *cp; 453132718Skan struct g_geom *gp1, *gp2; 454132718Skan int n, m; 455132718Skan 456132718Skan g_topology_assert(); 457132718Skan 458132718Skan /* Invalidate this geoms rank and move it to the tail */ 459132718Skan gp1 = TAILQ_NEXT(gp, geoms); 460132718Skan if (gp1 != NULL) { 461132718Skan gp->rank = 0; 462132718Skan TAILQ_REMOVE(&geoms, gp, geoms); 463132718Skan TAILQ_INSERT_TAIL(&geoms, gp, geoms); 464132718Skan } else { 465132718Skan gp1 = gp; 466132718Skan } 467132718Skan 468132718Skan /* re-rank the rest of the sequence */ 469132718Skan for (; gp1 != NULL; gp1 = gp2) { 470132718Skan gp1->rank = 0; 471132718Skan m = 1; 472132718Skan LIST_FOREACH(cp, &gp1->consumer, consumer) { 473132718Skan if (cp->provider == NULL) 474132718Skan continue; 475132718Skan n = cp->provider->geom->rank; 476132718Skan if (n == 0) { 477132718Skan m = 0; 478132718Skan break; 479132718Skan } else if (n >= m) 480132718Skan m = n + 1; 481132718Skan } 482132718Skan gp1->rank = m; 483132718Skan gp2 = TAILQ_NEXT(gp1, geoms); 484132718Skan 485132718Skan /* got a rank, moving on */ 486132718Skan if (m != 0) 487132718Skan continue; 488132718Skan 489132718Skan /* no rank to original geom means loop */ 490132718Skan if (gp == gp1) 491132718Skan return (ELOOP); 492132718Skan 493132718Skan /* no rank, put it at the end move on */ 494132718Skan TAILQ_REMOVE(&geoms, gp1, geoms); 495132718Skan TAILQ_INSERT_TAIL(&geoms, gp1, geoms); 496132718Skan } 497132718Skan return (0); 498132718Skan} 499132718Skan 500132718Skanint 501132718Skang_attach(struct g_consumer *cp, struct g_provider *pp) 502132718Skan{ 503132718Skan int error; 504132718Skan 505132718Skan g_topology_assert(); 506132718Skan KASSERT(cp->provider == NULL, ("attach but attached")); 507132718Skan cp->provider = pp; 508132718Skan LIST_INSERT_HEAD(&pp->consumers, cp, consumers); 509132718Skan error = redo_rank(cp->geom); 510132718Skan if (error) { 511132718Skan LIST_REMOVE(cp, consumers); 512132718Skan cp->provider = NULL; 513132718Skan redo_rank(cp->geom); 514132718Skan } 515132718Skan return (error); 516132718Skan} 517132718Skan 518132718Skanvoid 519132718Skang_detach(struct g_consumer *cp) 520132718Skan{ 521132718Skan struct g_provider *pp; 522132718Skan 523132718Skan g_trace(G_T_TOPOLOGY, "g_detach(%p)", cp); 524132718Skan KASSERT(cp != (void*)0xd0d0d0d0, ("ARGH!")); 525132718Skan g_topology_assert(); 526132718Skan KASSERT(cp->provider != NULL, ("detach but not attached")); 527132718Skan KASSERT(cp->acr == 0, ("detach but nonzero acr")); 528132718Skan KASSERT(cp->acw == 0, ("detach but nonzero acw")); 529132718Skan KASSERT(cp->ace == 0, ("detach but nonzero ace")); 530132718Skan KASSERT(cp->nstart == cp->nend, 531132718Skan ("detach with active requests")); 532132718Skan pp = cp->provider; 533132718Skan LIST_REMOVE(cp, consumers); 534132718Skan cp->provider = NULL; 535132718Skan if (pp->geom->flags & G_GEOM_WITHER) 536132718Skan g_wither_geom(pp->geom, 0); 537132718Skan else if (pp->flags & G_PF_WITHER) 538132718Skan g_destroy_provider(pp); 539132718Skan redo_rank(cp->geom); 540132718Skan} 541132718Skan 542132718Skan 543132718Skan/* 544132718Skan * g_access_abs() 545132718Skan * 546132718Skan * Access-check with absolute new values: Just fall through 547132718Skan * and use the relative version. 548132718Skan */ 549132718Skanint 550132718Skang_access_abs(struct g_consumer *cp, int acr, int acw, int ace) 551132718Skan{ 552132718Skan 553132718Skan g_topology_assert(); 554132718Skan return(g_access_rel(cp, 555132718Skan acr - cp->acr, 556132718Skan acw - cp->acw, 557132718Skan ace - cp->ace)); 558132718Skan} 559132718Skan 560132718Skan/* 561132718Skan * g_access_rel() 562132718Skan * 563132718Skan * Access-check with delta values. The question asked is "can provider 564132718Skan * "cp" change the access counters by the relative amounts dc[rwe] ?" 565132718Skan */ 566132718Skan 567132718Skanint 568132718Skang_access_rel(struct g_consumer *cp, int dcr, int dcw, int dce) 569132718Skan{ 570132718Skan struct g_provider *pp; 571132718Skan int pr,pw,pe; 572132718Skan int error; 573132718Skan 574132718Skan pp = cp->provider; 575132718Skan 576132718Skan g_trace(G_T_ACCESS, "g_access_rel(%p(%s), %d, %d, %d)", 577132718Skan cp, pp->name, dcr, dcw, dce); 578132718Skan 579132718Skan g_topology_assert(); 580132718Skan KASSERT(cp->provider != NULL, ("access but not attached")); 581132718Skan KASSERT(cp->acr + dcr >= 0, ("access resulting in negative acr")); 582132718Skan KASSERT(cp->acw + dcw >= 0, ("access resulting in negative acw")); 583132718Skan KASSERT(cp->ace + dce >= 0, ("access resulting in negative ace")); 584132718Skan KASSERT(pp->geom->access != NULL, ("NULL geom->access")); 585132718Skan 586132718Skan /* 587132718Skan * If our class cares about being spoiled, and we have been, we 588132718Skan * are probably just ahead of the event telling us that. Fail 589132718Skan * now rather than having to unravel this later. 590132718Skan */ 591132718Skan if (cp->geom->spoiled != NULL && cp->spoiled) { 592132718Skan KASSERT(dcr <= 0, ("spoiled but dcr = %d", dcr)); 593132718Skan KASSERT(dcw <= 0, ("spoiled but dce = %d", dcw)); 594132718Skan KASSERT(dce <= 0, ("spoiled but dcw = %d", dce)); 595132718Skan } 596132718Skan 597132718Skan /* 598132718Skan * Figure out what counts the provider would have had, if this 599132718Skan * consumer had (r0w0e0) at this time. 600132718Skan */ 601132718Skan pr = pp->acr - cp->acr; 602132718Skan pw = pp->acw - cp->acw; 603132718Skan pe = pp->ace - cp->ace; 604132718Skan 605132718Skan g_trace(G_T_ACCESS, 606132718Skan "open delta:[r%dw%de%d] old:[r%dw%de%d] provider:[r%dw%de%d] %p(%s)", 607132718Skan dcr, dcw, dce, 608132718Skan cp->acr, cp->acw, cp->ace, 609132718Skan pp->acr, pp->acw, pp->ace, 610132718Skan pp, pp->name); 611132718Skan 612132718Skan /* If foot-shooting is enabled, any open on rank#1 is OK */ 613132718Skan if ((g_debugflags & 16) && pp->geom->rank == 1) 614132718Skan ; 615132718Skan /* If we try exclusive but already write: fail */ 616132718Skan else if (dce > 0 && pw > 0) 617132718Skan return (EPERM); 618132718Skan /* If we try write but already exclusive: fail */ 619132718Skan else if (dcw > 0 && pe > 0) 620132718Skan return (EPERM); 621132718Skan /* If we try to open more but provider is error'ed: fail */ 622132718Skan else if ((dcr > 0 || dcw > 0 || dce > 0) && pp->error != 0) 623132718Skan return (pp->error); 624132718Skan 625132718Skan /* Ok then... */ 626132718Skan 627132718Skan error = pp->geom->access(pp, dcr, dcw, dce); 628132718Skan if (!error) { 629132718Skan /* 630132718Skan * If we open first write, spoil any partner consumers. 631132718Skan * If we close last write, trigger re-taste. 632132718Skan */ 633132718Skan if (pp->acw == 0 && dcw != 0) 634132718Skan g_spoil(pp, cp); 635132718Skan else if (pp->acw != 0 && pp->acw == -dcw && 636132718Skan !(pp->geom->flags & G_GEOM_WITHER)) 637132718Skan g_post_event(g_new_provider_event, pp, M_WAITOK, 638132718Skan pp, NULL); 639132718Skan 640132718Skan pp->acr += dcr; 641132718Skan pp->acw += dcw; 642132718Skan pp->ace += dce; 643132718Skan cp->acr += dcr; 644132718Skan cp->acw += dcw; 645132718Skan cp->ace += dce; 646132718Skan } 647132718Skan return (error); 648132718Skan} 649132718Skan 650132718Skanint 651132718Skang_handleattr_int(struct bio *bp, const char *attribute, int val) 652132718Skan{ 653132718Skan 654132718Skan return (g_handleattr(bp, attribute, &val, sizeof val)); 655132718Skan} 656132718Skan 657132718Skanint 658132718Skang_handleattr_off_t(struct bio *bp, const char *attribute, off_t val) 659132718Skan{ 660132718Skan 661132718Skan return (g_handleattr(bp, attribute, &val, sizeof val)); 662132718Skan} 663132718Skan 664132718Skanint 665132718Skang_handleattr(struct bio *bp, const char *attribute, void *val, int len) 666132718Skan{ 667132718Skan int error; 668132718Skan 669132718Skan if (strcmp(bp->bio_attribute, attribute)) 670132718Skan return (0); 671132718Skan if (bp->bio_length != len) { 672132718Skan printf("bio_length %jd len %d -> EFAULT\n", 673132718Skan (intmax_t)bp->bio_length, len); 674132718Skan error = EFAULT; 675132718Skan } else { 676132718Skan error = 0; 677132718Skan bcopy(val, bp->bio_data, len); 678132718Skan bp->bio_completed = len; 679132718Skan } 680132718Skan g_io_deliver(bp, error); 681132718Skan return (1); 682132718Skan} 683132718Skan 684132718Skanint 685132718Skang_std_access(struct g_provider *pp __unused, 686132718Skan int dr __unused, int dw __unused, int de __unused) 687132718Skan{ 688132718Skan 689132718Skan return (0); 690132718Skan} 691132718Skan 692132718Skanvoid 693132718Skang_std_done(struct bio *bp) 694132718Skan{ 695132718Skan struct bio *bp2; 696132718Skan 697132718Skan bp2 = bp->bio_parent; 698132718Skan if (bp2->bio_error == 0) 699132718Skan bp2->bio_error = bp->bio_error; 700132718Skan bp2->bio_completed += bp->bio_completed; 701132718Skan g_destroy_bio(bp); 702132718Skan bp2->bio_inbed++; 703132718Skan if (bp2->bio_children == bp2->bio_inbed) 704132718Skan g_io_deliver(bp2, bp2->bio_error); 705132718Skan} 706132718Skan 707132718Skan/* XXX: maybe this is only g_slice_spoiled */ 708132718Skan 709132718Skanvoid 710132718Skang_std_spoiled(struct g_consumer *cp) 711132718Skan{ 712132718Skan struct g_geom *gp; 713132718Skan struct g_provider *pp; 714132718Skan 715132718Skan g_trace(G_T_TOPOLOGY, "g_std_spoiled(%p)", cp); 716132718Skan g_topology_assert(); 717132718Skan g_detach(cp); 718132718Skan gp = cp->geom; 719132718Skan LIST_FOREACH(pp, &gp->provider, provider) 720132718Skan g_orphan_provider(pp, ENXIO); 721132718Skan g_destroy_consumer(cp); 722132718Skan if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer)) 723132718Skan g_destroy_geom(gp); 724132718Skan else 725132718Skan gp->flags |= G_GEOM_WITHER; 726132718Skan} 727132718Skan 728132718Skan/* 729132718Skan * Spoiling happens when a provider is opened for writing, but consumers 730132718Skan * which are configured by in-band data are attached (slicers for instance). 731132718Skan * Since the write might potentially change the in-band data, such consumers 732132718Skan * need to re-evaluate their existence after the writing session closes. 733132718Skan * We do this by (offering to) tear them down when the open for write happens 734132718Skan * in return for a re-taste when it closes again. 735132718Skan * Together with the fact that such consumers grab an 'e' bit whenever they 736132718Skan * are open, regardless of mode, this ends up DTRT. 737132718Skan */ 738132718Skan 739132718Skanstatic void 740132718Skang_spoil_event(void *arg, int flag) 741132718Skan{ 742132718Skan struct g_provider *pp; 743132718Skan struct g_consumer *cp, *cp2; 744132718Skan 745132718Skan g_topology_assert(); 746132718Skan if (flag == EV_CANCEL) 747132718Skan return; 748132718Skan pp = arg; 749132718Skan for (cp = LIST_FIRST(&pp->consumers); cp != NULL; cp = cp2) { 750132718Skan cp2 = LIST_NEXT(cp, consumers); 751132718Skan if (!cp->spoiled) 752132718Skan continue; 753132718Skan cp->spoiled = 0; 754132718Skan if (cp->geom->spoiled == NULL) 755132718Skan continue; 756132718Skan cp->geom->spoiled(cp); 757132718Skan g_topology_assert(); 758132718Skan } 759132718Skan} 760132718Skan 761132718Skanvoid 762132718Skang_spoil(struct g_provider *pp, struct g_consumer *cp) 763132718Skan{ 764132718Skan struct g_consumer *cp2; 765132718Skan 766132718Skan g_topology_assert(); 767132718Skan 768132718Skan LIST_FOREACH(cp2, &pp->consumers, consumers) { 769132718Skan if (cp2 == cp) 770132718Skan continue; 771132718Skan/* 772132718Skan KASSERT(cp2->acr == 0, ("spoiling cp->acr = %d", cp2->acr)); 773132718Skan KASSERT(cp2->acw == 0, ("spoiling cp->acw = %d", cp2->acw)); 774132718Skan*/ 775132718Skan KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace)); 776132718Skan cp2->spoiled++; 777132718Skan } 778132718Skan g_post_event(g_spoil_event, pp, M_WAITOK, pp, NULL); 779132718Skan} 780132718Skan 781132718Skanint 782132718Skang_getattr__(const char *attr, struct g_consumer *cp, void *var, int len) 783132718Skan{ 784132718Skan int error, i; 785132718Skan 786132718Skan i = len; 787132718Skan error = g_io_getattr(attr, cp, &i, var); 788132718Skan if (error) 789132718Skan return (error); 790132718Skan if (i != len) 791132718Skan return (EINVAL); 792132718Skan return (0); 793132718Skan} 794132718Skan 795132718Skan/* 796132718Skan * XXX: Bandaid for 5.2. 797132718Skan * XXX: DO NOT EVEN THINK ABOUT CALLING THIS FUNCTION! 798132718Skan */ 799132718Skanstatic int 800132718Skang_valid_obj(void const *ptr) 801132718Skan{ 802132718Skan struct g_class *mp; 803132718Skan struct g_geom *gp; 804132718Skan struct g_consumer *cp; 805132718Skan struct g_provider *pp; 806132718Skan 807132718Skan g_topology_assert(); 808132718Skan LIST_FOREACH(mp, &g_classes, class) { 809132718Skan if (ptr == mp) 810132718Skan return (1); 811132718Skan LIST_FOREACH(gp, &mp->geom, geom) { 812132718Skan if (ptr == gp) 813132718Skan return (1); 814132718Skan LIST_FOREACH(cp, &gp->consumer, consumer) 815132718Skan if (ptr == cp) 816132718Skan return (1); 817132718Skan LIST_FOREACH(pp, &gp->provider, provider) 818132718Skan if (ptr == pp) 819132718Skan return (1); 820132718Skan } 821132718Skan } 822132718Skan return(0); 823132718Skan} 824132718Skan 825132718Skan/* 826132718Skan * Check if the given pointer is a live object 827132718Skan */ 828132718Skan 829132718Skanvoid 830132718Skang_sanity(void const *ptr) 831132718Skan{ 832132718Skan struct g_class *mp; 833132718Skan struct g_geom *gp; 834132718Skan struct g_consumer *cp; 835132718Skan struct g_provider *pp; 836132718Skan 837132718Skan if (!(g_debugflags & 0x8)) 838132718Skan return; 839132718Skan LIST_FOREACH(mp, &g_classes, class) { 840132718Skan KASSERT(mp != ptr, ("Ptr is live class")); 841132718Skan LIST_FOREACH(gp, &mp->geom, geom) { 842132718Skan KASSERT(gp != ptr, ("Ptr is live geom")); 843132718Skan KASSERT(gp->name != ptr, ("Ptr is live geom's name")); 844132718Skan LIST_FOREACH(cp, &gp->consumer, consumer) { 845132718Skan KASSERT(cp != ptr, ("Ptr is live consumer")); 846132718Skan } 847132718Skan LIST_FOREACH(pp, &gp->provider, provider) { 848132718Skan KASSERT(pp != ptr, ("Ptr is live provider")); 849132718Skan } 850132718Skan } 851132718Skan } 852132718Skan} 853132718Skan 854132718Skan