geom_subr.c revision 113432
1177633Sdfr/*- 2177633Sdfr * Copyright (c) 2002 Poul-Henning Kamp 3177633Sdfr * Copyright (c) 2002 Networks Associates Technology, Inc. 4177633Sdfr * All rights reserved. 5177633Sdfr * 6177633Sdfr * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7177633Sdfr * and NAI Labs, the Security Research Division of Network Associates, Inc. 8177633Sdfr * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9177633Sdfr * DARPA CHATS research program. 10177633Sdfr * 11177633Sdfr * Redistribution and use in source and binary forms, with or without 12177633Sdfr * modification, are permitted provided that the following conditions 13177633Sdfr * are met: 14177633Sdfr * 1. Redistributions of source code must retain the above copyright 15177633Sdfr * notice, this list of conditions and the following disclaimer. 16177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 17177633Sdfr * notice, this list of conditions and the following disclaimer in the 18177633Sdfr * documentation and/or other materials provided with the distribution. 19177633Sdfr * 3. The names of the authors may not be used to endorse or promote 20177633Sdfr * products derived from this software without specific prior written 21177633Sdfr * permission. 22177633Sdfr * 23177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33177633Sdfr * SUCH DAMAGE. 34177633Sdfr * 35177633Sdfr * $FreeBSD: head/sys/geom/geom_subr.c 113432 2003-04-13 09:02:06Z phk $ 36177633Sdfr */ 37177633Sdfr 38177633Sdfr 39177633Sdfr#include <sys/param.h> 40177633Sdfr#include <sys/systm.h> 41177633Sdfr#include <sys/devicestat.h> 42177633Sdfr#include <sys/kernel.h> 43177633Sdfr#include <sys/malloc.h> 44177633Sdfr#include <sys/bio.h> 45177633Sdfr#include <sys/sysctl.h> 46177633Sdfr#include <sys/proc.h> 47177633Sdfr#include <sys/kthread.h> 48177633Sdfr#include <sys/lock.h> 49177633Sdfr#include <sys/mutex.h> 50177633Sdfr#include <sys/errno.h> 51177633Sdfr#include <sys/sbuf.h> 52184588Sdfr#include <geom/geom.h> 53177633Sdfr#include <geom/geom_int.h> 54184588Sdfr#include <machine/stdarg.h> 55177633Sdfr 56184588Sdfrstruct class_list_head g_classes = LIST_HEAD_INITIALIZER(g_classes); 57177633Sdfrstatic struct g_tailq_head geoms = TAILQ_HEAD_INITIALIZER(geoms); 58184588Sdfrstatic int g_nproviders; 59177633Sdfrchar *g_wait_event, *g_wait_up, *g_wait_down, *g_wait_sim; 60177633Sdfr 61177633Sdfrstatic int g_ignition; 62177633Sdfr 63177633Sdfrvoid 64184588Sdfrg_add_class(struct g_class *mp) 65177633Sdfr{ 66177685Sdfr 67177633Sdfr if (!g_ignition) { 68177633Sdfr g_ignition++; 69184588Sdfr g_init(); 70177633Sdfr } 71177633Sdfr mp->protect = 0x020016600; 72177633Sdfr g_topology_lock(); 73184588Sdfr g_trace(G_T_TOPOLOGY, "g_add_class(%s)", mp->name); 74184588Sdfr LIST_INIT(&mp->geom); 75177633Sdfr LIST_INSERT_HEAD(&g_classes, mp, class); 76177633Sdfr if (g_nproviders > 0) 77177633Sdfr g_post_event(EV_NEW_CLASS, mp, NULL); 78184588Sdfr g_topology_unlock(); 79184588Sdfr} 80184588Sdfr 81177633Sdfrstruct g_geom * 82184588Sdfrg_new_geomf(struct g_class *mp, const char *fmt, ...) 83177633Sdfr{ 84177633Sdfr struct g_geom *gp; 85177633Sdfr va_list ap; 86177633Sdfr struct sbuf *sb; 87177633Sdfr 88177633Sdfr g_topology_assert(); 89184588Sdfr va_start(ap, fmt); 90184588Sdfr sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 91184588Sdfr sbuf_vprintf(sb, fmt, ap); 92177633Sdfr sbuf_finish(sb); 93177633Sdfr gp = g_malloc(sizeof *gp, M_WAITOK | M_ZERO); 94177633Sdfr gp->protect = 0x020016601; 95184588Sdfr gp->name = g_malloc(sbuf_len(sb) + 1, M_WAITOK | M_ZERO); 96184588Sdfr gp->class = mp; 97184588Sdfr gp->rank = 1; 98184588Sdfr LIST_INIT(&gp->consumer); 99184588Sdfr LIST_INIT(&gp->provider); 100177633Sdfr LIST_INSERT_HEAD(&mp->geom, gp, geom); 101184588Sdfr TAILQ_INSERT_HEAD(&geoms, gp, geoms); 102184588Sdfr strcpy(gp->name, sbuf_data(sb)); 103184588Sdfr sbuf_delete(sb); 104184588Sdfr return (gp); 105184588Sdfr} 106184588Sdfr 107184588Sdfrvoid 108184588Sdfrg_destroy_geom(struct g_geom *gp) 109184588Sdfr{ 110184588Sdfr 111184588Sdfr g_trace(G_T_TOPOLOGY, "g_destroy_geom(%p(%s))", gp, gp->name); 112184588Sdfr g_topology_assert(); 113184588Sdfr KASSERT(gp->event == NULL, ("g_destroy_geom() with event")); 114184588Sdfr KASSERT(LIST_EMPTY(&gp->consumer), 115184588Sdfr ("g_destroy_geom(%s) with consumer(s) [%p]", 116184588Sdfr gp->name, LIST_FIRST(&gp->consumer))); 117184588Sdfr KASSERT(LIST_EMPTY(&gp->provider), 118184588Sdfr ("g_destroy_geom(%s) with provider(s) [%p]", 119184588Sdfr gp->name, LIST_FIRST(&gp->consumer))); 120184588Sdfr g_cancel_event(gp); 121184588Sdfr LIST_REMOVE(gp, geom); 122184588Sdfr TAILQ_REMOVE(&geoms, gp, geoms); 123184588Sdfr g_free(gp->name); 124184588Sdfr g_free(gp); 125184588Sdfr} 126184588Sdfr 127184588Sdfrstruct g_consumer * 128184588Sdfrg_new_consumer(struct g_geom *gp) 129184588Sdfr{ 130184588Sdfr struct g_consumer *cp; 131184588Sdfr 132184588Sdfr g_topology_assert(); 133184588Sdfr KASSERT(gp->orphan != NULL, 134184588Sdfr ("g_new_consumer on geom(%s) (class %s) without orphan", 135184588Sdfr gp->name, gp->class->name)); 136184588Sdfr 137184588Sdfr cp = g_malloc(sizeof *cp, M_WAITOK | M_ZERO); 138184588Sdfr cp->protect = 0x020016602; 139184588Sdfr cp->geom = gp; 140184588Sdfr cp->stat = devstat_new_entry(cp, -1, 0, DEVSTAT_ALL_SUPPORTED, 141184588Sdfr DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); 142184588Sdfr LIST_INSERT_HEAD(&gp->consumer, cp, consumer); 143184588Sdfr return(cp); 144184588Sdfr} 145184588Sdfr 146184588Sdfrvoid 147184588Sdfrg_destroy_consumer(struct g_consumer *cp) 148184588Sdfr{ 149184588Sdfr 150184588Sdfr g_trace(G_T_TOPOLOGY, "g_destroy_consumer(%p)", cp); 151184588Sdfr g_topology_assert(); 152177633Sdfr KASSERT(cp->event == NULL, ("g_destroy_consumer() with event")); 153177633Sdfr KASSERT (cp->provider == NULL, ("g_destroy_consumer but attached")); 154177633Sdfr KASSERT (cp->acr == 0, ("g_destroy_consumer with acr")); 155177633Sdfr KASSERT (cp->acw == 0, ("g_destroy_consumer with acw")); 156177633Sdfr KASSERT (cp->ace == 0, ("g_destroy_consumer with ace")); 157177633Sdfr g_cancel_event(cp); 158184588Sdfr LIST_REMOVE(cp, consumer); 159177633Sdfr devstat_remove_entry(cp->stat); 160184588Sdfr g_free(cp); 161177633Sdfr} 162184588Sdfr 163177633Sdfrstruct g_provider * 164177633Sdfrg_new_providerf(struct g_geom *gp, const char *fmt, ...) 165177633Sdfr{ 166177633Sdfr struct g_provider *pp; 167184588Sdfr struct sbuf *sb; 168184588Sdfr va_list ap; 169177633Sdfr 170177633Sdfr g_topology_assert(); 171177633Sdfr va_start(ap, fmt); 172177633Sdfr sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 173177633Sdfr sbuf_vprintf(sb, fmt, ap); 174177633Sdfr sbuf_finish(sb); 175177633Sdfr pp = g_malloc(sizeof *pp + sbuf_len(sb) + 1, M_WAITOK | M_ZERO); 176177633Sdfr pp->protect = 0x020016603; 177177633Sdfr pp->name = (char *)(pp + 1); 178177633Sdfr strcpy(pp->name, sbuf_data(sb)); 179184588Sdfr sbuf_delete(sb); 180184588Sdfr LIST_INIT(&pp->consumers); 181184588Sdfr pp->error = ENXIO; 182184588Sdfr pp->geom = gp; 183184588Sdfr pp->stat = devstat_new_entry(pp, -1, 0, DEVSTAT_ALL_SUPPORTED, 184184588Sdfr DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); 185184588Sdfr LIST_INSERT_HEAD(&gp->provider, pp, provider); 186184588Sdfr g_nproviders++; 187184588Sdfr g_post_event(EV_NEW_PROVIDER, pp, NULL); 188177633Sdfr return (pp); 189177633Sdfr} 190177633Sdfr 191184588Sdfrvoid 192184588Sdfrg_error_provider(struct g_provider *pp, int error) 193184588Sdfr{ 194184588Sdfr 195184588Sdfr pp->error = error; 196184588Sdfr} 197184588Sdfr 198184588Sdfr 199184588Sdfrvoid 200184588Sdfrg_destroy_provider(struct g_provider *pp) 201177633Sdfr{ 202184588Sdfr struct g_geom *gp; 203184588Sdfr struct g_consumer *cp; 204184588Sdfr 205184588Sdfr g_topology_assert(); 206184588Sdfr KASSERT(pp->event == NULL, ("g_destroy_provider() with event")); 207184588Sdfr KASSERT(LIST_EMPTY(&pp->consumers), 208184588Sdfr ("g_destroy_provider but attached")); 209184588Sdfr KASSERT (pp->acr == 0, ("g_destroy_provider with acr")); 210184588Sdfr KASSERT (pp->acw == 0, ("g_destroy_provider with acw")); 211184588Sdfr KASSERT (pp->acw == 0, ("g_destroy_provider with ace")); 212184588Sdfr g_cancel_event(pp); 213184588Sdfr g_nproviders--; 214184588Sdfr LIST_REMOVE(pp, provider); 215184588Sdfr gp = pp->geom; 216184588Sdfr devstat_remove_entry(pp->stat); 217184588Sdfr g_free(pp); 218184588Sdfr if (!(gp->flags & G_GEOM_WITHER)) 219184588Sdfr return; 220184588Sdfr if (!LIST_EMPTY(&gp->provider)) 221184588Sdfr return; 222184588Sdfr for (;;) { 223184588Sdfr cp = LIST_FIRST(&gp->consumer); 224184588Sdfr if (cp == NULL) 225184588Sdfr break; 226184588Sdfr g_detach(cp); 227184588Sdfr g_destroy_consumer(cp); 228184588Sdfr } 229184588Sdfr g_destroy_geom(gp); 230184588Sdfr} 231184588Sdfr 232184588Sdfr/* 233184588Sdfr * We keep the "geoms" list sorted by topological order (== increasing 234184588Sdfr * numerical rank) at all times. 235184588Sdfr * When an attach is done, the attaching geoms rank is invalidated 236184588Sdfr * and it is moved to the tail of the list. 237184588Sdfr * All geoms later in the sequence has their ranks reevaluated in 238184588Sdfr * sequence. If we cannot assign rank to a geom because it's 239184588Sdfr * prerequisites do not have rank, we move that element to the tail 240184588Sdfr * of the sequence with invalid rank as well. 241184588Sdfr * At some point we encounter our original geom and if we stil fail 242184588Sdfr * to assign it a rank, there must be a loop and we fail back to 243184588Sdfr * g_attach() which detach again and calls redo_rank again 244184588Sdfr * to fix up the damage. 245184588Sdfr * It would be much simpler code wise to do it recursively, but we 246184588Sdfr * can't risk that on the kernel stack. 247184588Sdfr */ 248184588Sdfr 249184588Sdfrstatic int 250184588Sdfrredo_rank(struct g_geom *gp) 251184588Sdfr{ 252184588Sdfr struct g_consumer *cp; 253184588Sdfr struct g_geom *gp1, *gp2; 254184588Sdfr int n, m; 255184588Sdfr 256184588Sdfr g_topology_assert(); 257184588Sdfr 258184588Sdfr /* Invalidate this geoms rank and move it to the tail */ 259184588Sdfr gp1 = TAILQ_NEXT(gp, geoms); 260184588Sdfr if (gp1 != NULL) { 261184588Sdfr gp->rank = 0; 262184588Sdfr TAILQ_REMOVE(&geoms, gp, geoms); 263184588Sdfr TAILQ_INSERT_TAIL(&geoms, gp, geoms); 264184588Sdfr } else { 265184588Sdfr gp1 = gp; 266184588Sdfr } 267184588Sdfr 268184588Sdfr /* re-rank the rest of the sequence */ 269184588Sdfr for (; gp1 != NULL; gp1 = gp2) { 270184588Sdfr gp1->rank = 0; 271177633Sdfr m = 1; 272177633Sdfr LIST_FOREACH(cp, &gp1->consumer, consumer) { 273177633Sdfr if (cp->provider == NULL) 274177633Sdfr continue; 275177633Sdfr n = cp->provider->geom->rank; 276177633Sdfr if (n == 0) { 277177633Sdfr m = 0; 278177633Sdfr break; 279177633Sdfr } else if (n >= m) 280177633Sdfr m = n + 1; 281177633Sdfr } 282177633Sdfr gp1->rank = m; 283177633Sdfr gp2 = TAILQ_NEXT(gp1, geoms); 284177633Sdfr 285177633Sdfr /* got a rank, moving on */ 286184588Sdfr if (m != 0) 287184588Sdfr continue; 288184588Sdfr 289177633Sdfr /* no rank to original geom means loop */ 290177633Sdfr if (gp == gp1) 291184588Sdfr return (ELOOP); 292177633Sdfr 293177633Sdfr /* no rank, put it at the end move on */ 294177633Sdfr TAILQ_REMOVE(&geoms, gp1, geoms); 295177633Sdfr TAILQ_INSERT_TAIL(&geoms, gp1, geoms); 296177633Sdfr } 297177633Sdfr return (0); 298177633Sdfr} 299177633Sdfr 300177633Sdfrint 301184588Sdfrg_attach(struct g_consumer *cp, struct g_provider *pp) 302177633Sdfr{ 303184588Sdfr int error; 304184588Sdfr 305184588Sdfr g_topology_assert(); 306184588Sdfr KASSERT(cp->provider == NULL, ("attach but attached")); 307184588Sdfr cp->provider = pp; 308184588Sdfr LIST_INSERT_HEAD(&pp->consumers, cp, consumers); 309184588Sdfr error = redo_rank(cp->geom); 310184588Sdfr if (error) { 311184588Sdfr LIST_REMOVE(cp, consumers); 312184588Sdfr cp->provider = NULL; 313177633Sdfr redo_rank(cp->geom); 314177633Sdfr } 315184588Sdfr return (error); 316184588Sdfr} 317184588Sdfr 318184588Sdfrvoid 319184588Sdfrg_detach(struct g_consumer *cp) 320184588Sdfr{ 321184588Sdfr struct g_provider *pp; 322184588Sdfr 323184588Sdfr g_trace(G_T_TOPOLOGY, "g_detach(%p)", cp); 324184588Sdfr KASSERT(cp != (void*)0xd0d0d0d0, ("ARGH!")); 325184588Sdfr g_topology_assert(); 326184588Sdfr KASSERT(cp->provider != NULL, ("detach but not attached")); 327184588Sdfr KASSERT(cp->acr == 0, ("detach but nonzero acr")); 328184588Sdfr KASSERT(cp->acw == 0, ("detach but nonzero acw")); 329184588Sdfr KASSERT(cp->ace == 0, ("detach but nonzero ace")); 330184588Sdfr KASSERT(cp->nstart == cp->nend, 331184588Sdfr ("detach with active requests")); 332184588Sdfr pp = cp->provider; 333184588Sdfr LIST_REMOVE(cp, consumers); 334184588Sdfr cp->provider = NULL; 335184588Sdfr if (LIST_EMPTY(&pp->consumers)) { 336184588Sdfr if (pp->geom->flags & G_GEOM_WITHER) 337184588Sdfr g_destroy_provider(pp); 338184588Sdfr } 339184588Sdfr redo_rank(cp->geom); 340184588Sdfr} 341184588Sdfr 342184588Sdfr 343184588Sdfr/* 344184588Sdfr * g_access_abs() 345184588Sdfr * 346184588Sdfr * Access-check with absolute new values: Just fall through 347184588Sdfr * and use the relative version. 348184588Sdfr */ 349184588Sdfrint 350184588Sdfrg_access_abs(struct g_consumer *cp, int acr, int acw, int ace) 351177633Sdfr{ 352177633Sdfr 353177633Sdfr g_topology_assert(); 354177633Sdfr return(g_access_rel(cp, 355177633Sdfr acr - cp->acr, 356184588Sdfr acw - cp->acw, 357184588Sdfr ace - cp->ace)); 358184588Sdfr} 359184588Sdfr 360184588Sdfr/* 361184588Sdfr * g_access_rel() 362184588Sdfr * 363177633Sdfr * Access-check with delta values. The question asked is "can provider 364177633Sdfr * "cp" change the access counters by the relative amounts dc[rwe] ?" 365177633Sdfr */ 366177633Sdfr 367177633Sdfrint 368184588Sdfrg_access_rel(struct g_consumer *cp, int dcr, int dcw, int dce) 369177633Sdfr{ 370177633Sdfr struct g_provider *pp; 371177633Sdfr int pr,pw,pe; 372177633Sdfr int error; 373177633Sdfr 374177633Sdfr pp = cp->provider; 375184588Sdfr 376177633Sdfr g_trace(G_T_ACCESS, "g_access_rel(%p(%s), %d, %d, %d)", 377177633Sdfr cp, pp->name, dcr, dcw, dce); 378177633Sdfr 379177633Sdfr g_topology_assert(); 380177633Sdfr KASSERT(cp->provider != NULL, ("access but not attached")); 381177633Sdfr KASSERT(cp->acr + dcr >= 0, ("access resulting in negative acr")); 382177633Sdfr KASSERT(cp->acw + dcw >= 0, ("access resulting in negative acw")); 383184588Sdfr KASSERT(cp->ace + dce >= 0, ("access resulting in negative ace")); 384177633Sdfr KASSERT(pp->geom->access != NULL, ("NULL geom->access")); 385184588Sdfr 386184588Sdfr /* 387184588Sdfr * If our class cares about being spoiled, and we have been, we 388184588Sdfr * are probably just ahead of the event telling us that. Fail 389184588Sdfr * now rather than having to unravel this later. 390184588Sdfr */ 391184588Sdfr if (cp->geom->spoiled != NULL && cp->spoiled) { 392177633Sdfr KASSERT(dcr <= 0, ("spoiled but dcr = %d", dcr)); 393177633Sdfr KASSERT(dcw <= 0, ("spoiled but dce = %d", dcw)); 394177633Sdfr KASSERT(dce <= 0, ("spoiled but dcw = %d", dce)); 395177633Sdfr } 396177633Sdfr 397177633Sdfr /* 398177633Sdfr * Figure out what counts the provider would have had, if this 399177633Sdfr * consumer had (r0w0e0) at this time. 400177633Sdfr */ 401177633Sdfr pr = pp->acr - cp->acr; 402177633Sdfr pw = pp->acw - cp->acw; 403177633Sdfr pe = pp->ace - cp->ace; 404177633Sdfr 405177633Sdfr g_trace(G_T_ACCESS, 406177633Sdfr "open delta:[r%dw%de%d] old:[r%dw%de%d] provider:[r%dw%de%d] %p(%s)", 407177633Sdfr dcr, dcw, dce, 408177633Sdfr cp->acr, cp->acw, cp->ace, 409177633Sdfr pp->acr, pp->acw, pp->ace, 410177633Sdfr pp, pp->name); 411177633Sdfr 412177633Sdfr /* If foot-shooting is enabled, any open on rank#1 is OK */ 413177633Sdfr if ((g_debugflags & 16) && pp->geom->rank == 1) 414177633Sdfr ; 415177633Sdfr /* If we try exclusive but already write: fail */ 416177633Sdfr else if (dce > 0 && pw > 0) 417177633Sdfr return (EPERM); 418177633Sdfr /* If we try write but already exclusive: fail */ 419177633Sdfr else if (dcw > 0 && pe > 0) 420177633Sdfr return (EPERM); 421177633Sdfr /* If we try to open more but provider is error'ed: fail */ 422177633Sdfr else if ((dcr > 0 || dcw > 0 || dce > 0) && pp->error != 0) 423177633Sdfr return (pp->error); 424177633Sdfr 425177633Sdfr /* Ok then... */ 426177633Sdfr 427177633Sdfr error = pp->geom->access(pp, dcr, dcw, dce); 428177633Sdfr if (!error) { 429177633Sdfr /* 430177633Sdfr * If we open first write, spoil any partner consumers. 431177633Sdfr * If we close last write, trigger re-taste. 432177633Sdfr */ 433177633Sdfr if (pp->acw == 0 && dcw != 0) 434177633Sdfr g_spoil(pp, cp); 435177633Sdfr else if (pp->acw != 0 && pp->acw == -dcw && 436177633Sdfr !(pp->geom->flags & G_GEOM_WITHER)) 437177633Sdfr g_post_event(EV_NEW_PROVIDER, pp, NULL); 438177633Sdfr 439177633Sdfr pp->acr += dcr; 440177633Sdfr pp->acw += dcw; 441177633Sdfr pp->ace += dce; 442177633Sdfr cp->acr += dcr; 443177633Sdfr cp->acw += dcw; 444177633Sdfr cp->ace += dce; 445177633Sdfr } 446177633Sdfr return (error); 447177633Sdfr} 448177633Sdfr 449177633Sdfrint 450177633Sdfrg_handleattr_int(struct bio *bp, const char *attribute, int val) 451177633Sdfr{ 452177633Sdfr 453177633Sdfr return (g_handleattr(bp, attribute, &val, sizeof val)); 454177633Sdfr} 455184588Sdfr 456177633Sdfrint 457184588Sdfrg_handleattr_off_t(struct bio *bp, const char *attribute, off_t val) 458184588Sdfr{ 459184588Sdfr 460177633Sdfr return (g_handleattr(bp, attribute, &val, sizeof val)); 461177633Sdfr} 462177633Sdfr 463177633Sdfrint 464177633Sdfrg_handleattr(struct bio *bp, const char *attribute, void *val, int len) 465177633Sdfr{ 466177633Sdfr int error; 467177633Sdfr 468177633Sdfr if (strcmp(bp->bio_attribute, attribute)) 469177633Sdfr return (0); 470177633Sdfr if (bp->bio_length != len) { 471177633Sdfr printf("bio_length %jd len %d -> EFAULT\n", 472177633Sdfr (intmax_t)bp->bio_length, len); 473177633Sdfr error = EFAULT; 474177633Sdfr } else { 475177633Sdfr error = 0; 476177633Sdfr bcopy(val, bp->bio_data, len); 477177633Sdfr bp->bio_completed = len; 478177633Sdfr } 479177633Sdfr g_io_deliver(bp, error); 480177633Sdfr return (1); 481177633Sdfr} 482177633Sdfr 483177633Sdfrint 484177633Sdfrg_std_access(struct g_provider *pp __unused, 485177633Sdfr int dr __unused, int dw __unused, int de __unused) 486177633Sdfr{ 487177633Sdfr 488177633Sdfr return (0); 489177633Sdfr} 490177633Sdfr 491177633Sdfrvoid 492177633Sdfrg_std_done(struct bio *bp) 493177633Sdfr{ 494177633Sdfr struct bio *bp2; 495177633Sdfr 496177633Sdfr bp2 = bp->bio_parent; 497177633Sdfr if (bp2->bio_error == 0) 498177633Sdfr bp2->bio_error = bp->bio_error; 499177633Sdfr bp2->bio_completed += bp->bio_completed; 500177633Sdfr g_destroy_bio(bp); 501177633Sdfr bp2->bio_inbed++; 502177633Sdfr if (bp2->bio_children == bp2->bio_inbed) 503177633Sdfr g_io_deliver(bp2, bp2->bio_error); 504177633Sdfr} 505177633Sdfr 506177633Sdfr/* XXX: maybe this is only g_slice_spoiled */ 507177633Sdfr 508177633Sdfrvoid 509184588Sdfrg_std_spoiled(struct g_consumer *cp) 510184588Sdfr{ 511184588Sdfr struct g_geom *gp; 512184588Sdfr struct g_provider *pp; 513184588Sdfr 514184588Sdfr g_trace(G_T_TOPOLOGY, "g_std_spoiled(%p)", cp); 515184588Sdfr g_topology_assert(); 516184588Sdfr g_detach(cp); 517184588Sdfr gp = cp->geom; 518184588Sdfr LIST_FOREACH(pp, &gp->provider, provider) 519184588Sdfr g_orphan_provider(pp, ENXIO); 520184588Sdfr g_destroy_consumer(cp); 521184588Sdfr if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer)) 522184588Sdfr g_destroy_geom(gp); 523184588Sdfr else 524184588Sdfr gp->flags |= G_GEOM_WITHER; 525184588Sdfr} 526184588Sdfr 527184588Sdfr/* 528184588Sdfr * Spoiling happens when a provider is opened for writing, but consumers 529184588Sdfr * which are configured by in-band data are attached (slicers for instance). 530184588Sdfr * Since the write might potentially change the in-band data, such consumers 531184588Sdfr * need to re-evaluate their existence after the writing session closes. 532184588Sdfr * We do this by (offering to) tear them down when the open for write happens 533184588Sdfr * in return for a re-taste when it closes again. 534184588Sdfr * Together with the fact that such consumers grab an 'e' bit whenever they 535184588Sdfr * are open, regardless of mode, this ends up DTRT. 536184588Sdfr */ 537177633Sdfr 538177633Sdfrvoid 539177633Sdfrg_spoil(struct g_provider *pp, struct g_consumer *cp) 540177633Sdfr{ 541184588Sdfr struct g_consumer *cp2; 542177633Sdfr 543177633Sdfr g_topology_assert(); 544184588Sdfr 545184588Sdfr if (!strcmp(pp->name, "geom.ctl")) 546184588Sdfr return; 547177633Sdfr LIST_FOREACH(cp2, &pp->consumers, consumers) { 548184588Sdfr if (cp2 == cp) 549177633Sdfr continue; 550177633Sdfr/* 551184588Sdfr KASSERT(cp2->acr == 0, ("spoiling cp->acr = %d", cp2->acr)); 552177633Sdfr KASSERT(cp2->acw == 0, ("spoiling cp->acw = %d", cp2->acw)); 553184588Sdfr*/ 554184588Sdfr KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace)); 555177633Sdfr cp2->spoiled++; 556184588Sdfr } 557184588Sdfr g_post_event(EV_SPOILED, pp, cp, NULL); 558184588Sdfr} 559184588Sdfr 560184588Sdfrint 561184588Sdfrg_getattr__(const char *attr, struct g_consumer *cp, void *var, int len) 562184588Sdfr{ 563184588Sdfr int error, i; 564184588Sdfr 565184588Sdfr i = len; 566184588Sdfr error = g_io_getattr(attr, cp, &i, var); 567184588Sdfr if (error) 568184588Sdfr return (error); 569177633Sdfr if (i != len) 570177633Sdfr return (EINVAL); 571184588Sdfr return (0); 572184588Sdfr} 573184588Sdfr 574184588Sdfr/* 575184588Sdfr * Check if the given pointer is a live object 576184588Sdfr */ 577184588Sdfr 578184588Sdfrvoid 579184588Sdfrg_sanity(void *ptr) 580184588Sdfr{ 581184588Sdfr struct g_class *mp; 582184588Sdfr struct g_geom *gp; 583184588Sdfr struct g_consumer *cp; 584184588Sdfr struct g_provider *pp; 585184588Sdfr 586184588Sdfr if (!(g_debugflags & 0x8)) 587177633Sdfr return; 588177633Sdfr LIST_FOREACH(mp, &g_classes, class) { 589177633Sdfr KASSERT(mp != ptr, ("Ptr is live class")); 590177633Sdfr KASSERT(mp->protect == 0x20016600, 591184588Sdfr ("corrupt class %p %x", mp, mp->protect)); 592177633Sdfr LIST_FOREACH(gp, &mp->geom, geom) { 593184588Sdfr KASSERT(gp != ptr, ("Ptr is live geom")); 594177633Sdfr KASSERT(gp->protect == 0x20016601, 595177633Sdfr ("corrupt geom, %p %x", gp, gp->protect)); 596184588Sdfr KASSERT(gp->name != ptr, ("Ptr is live geom's name")); 597177633Sdfr LIST_FOREACH(cp, &gp->consumer, consumer) { 598177633Sdfr KASSERT(cp != ptr, ("Ptr is live consumer")); 599184588Sdfr KASSERT(cp->protect == 0x20016602, 600177633Sdfr ("corrupt consumer %p %x", 601177633Sdfr cp, cp->protect)); 602184588Sdfr } 603184588Sdfr LIST_FOREACH(pp, &gp->provider, provider) { 604184588Sdfr KASSERT(pp != ptr, ("Ptr is live provider")); 605184588Sdfr KASSERT(pp->protect == 0x20016603, 606184588Sdfr ("corrupt provider %p %x", 607177633Sdfr pp, pp->protect)); 608177633Sdfr } 609177633Sdfr } 610177633Sdfr } 611177633Sdfr} 612177633Sdfr 613184588Sdfrstruct g_class * 614177633Sdfrg_idclass(struct geomidorname *p) 615184588Sdfr{ 616177633Sdfr struct g_class *mp; 617177633Sdfr char *n; 618184588Sdfr 619177633Sdfr if (p->len == 0) { 620177633Sdfr LIST_FOREACH(mp, &g_classes, class) 621184588Sdfr if ((uintptr_t)mp == p->u.id) 622177633Sdfr return (mp); 623177633Sdfr return (NULL); 624184588Sdfr } 625184588Sdfr n = g_malloc(p->len + 1, M_WAITOK); 626184588Sdfr if (copyin(p->u.name, n, p->len) == 0) { 627184588Sdfr n[p->len] = '\0'; 628184588Sdfr LIST_FOREACH(mp, &g_classes, class) 629177633Sdfr if (!bcmp(n, mp->name, p->len + 1)) { 630177633Sdfr g_free(n); 631177633Sdfr return (mp); 632177633Sdfr } 633177633Sdfr } 634177633Sdfr g_free(n); 635184588Sdfr return (NULL); 636177633Sdfr} 637184588Sdfr 638177633Sdfrstruct g_geom * 639177633Sdfrg_idgeom(struct geomidorname *p) 640184588Sdfr{ 641177633Sdfr struct g_class *mp; 642177633Sdfr struct g_geom *gp; 643184588Sdfr char *n; 644177633Sdfr 645177633Sdfr if (p->len == 0) { 646184588Sdfr LIST_FOREACH(mp, &g_classes, class) 647184588Sdfr LIST_FOREACH(gp, &mp->geom, geom) 648184588Sdfr if ((uintptr_t)gp == p->u.id) 649184588Sdfr return (gp); 650184588Sdfr return (NULL); 651177633Sdfr } 652177633Sdfr n = g_malloc(p->len + 1, M_WAITOK); 653177633Sdfr if (copyin(p->u.name, n, p->len) == 0) { 654177633Sdfr n[p->len] = '\0'; 655177633Sdfr LIST_FOREACH(mp, &g_classes, class) 656177633Sdfr LIST_FOREACH(gp, &mp->geom, geom) 657184588Sdfr if (!bcmp(n, gp->name, p->len + 1)) { 658177633Sdfr g_free(n); 659184588Sdfr return (gp); 660177633Sdfr } 661177633Sdfr } 662184588Sdfr g_free(n); 663177633Sdfr return (NULL); 664177633Sdfr} 665177633Sdfr 666177633Sdfrstruct g_provider * 667177633Sdfrg_idprovider(struct geomidorname *p) 668184588Sdfr{ 669184588Sdfr struct g_class *mp; 670184588Sdfr struct g_geom *gp; 671184588Sdfr struct g_provider *pp; 672184588Sdfr char *n; 673177633Sdfr 674177633Sdfr if (p->len == 0) { 675177633Sdfr LIST_FOREACH(mp, &g_classes, class) 676177633Sdfr LIST_FOREACH(gp, &mp->geom, geom) 677177633Sdfr LIST_FOREACH(pp, &gp->provider, provider) 678177633Sdfr if ((uintptr_t)pp == p->u.id) 679184588Sdfr return (pp); 680177633Sdfr return (NULL); 681177633Sdfr } 682184588Sdfr n = g_malloc(p->len + 1, M_WAITOK); 683177633Sdfr if (copyin(p->u.name, n, p->len) == 0) { 684177633Sdfr n[p->len] = '\0'; 685177633Sdfr LIST_FOREACH(mp, &g_classes, class) 686177633Sdfr LIST_FOREACH(gp, &mp->geom, geom) 687177633Sdfr LIST_FOREACH(pp, &gp->provider, provider) 688177633Sdfr if (!bcmp(n, pp->name, p->len + 1)) { 689184588Sdfr g_free(n); 690177633Sdfr return (pp); 691184588Sdfr } 692177633Sdfr } 693177633Sdfr g_free(n); 694184588Sdfr return (NULL); 695177633Sdfr} 696177633Sdfr