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