xref: /freebsd/sys/geom/geom_io.c (revision 2a842317eb386798cb7a8e14aad7068d5546e259)
1dd84a43cSPoul-Henning Kamp /*-
2dd84a43cSPoul-Henning Kamp  * Copyright (c) 2002 Poul-Henning Kamp
3dd84a43cSPoul-Henning Kamp  * Copyright (c) 2002 Networks Associates Technology, Inc.
4dd84a43cSPoul-Henning Kamp  * All rights reserved.
5dd84a43cSPoul-Henning Kamp  *
6dd84a43cSPoul-Henning Kamp  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7dd84a43cSPoul-Henning Kamp  * and NAI Labs, the Security Research Division of Network Associates, Inc.
8dd84a43cSPoul-Henning Kamp  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9dd84a43cSPoul-Henning Kamp  * DARPA CHATS research program.
10dd84a43cSPoul-Henning Kamp  *
11dd84a43cSPoul-Henning Kamp  * Redistribution and use in source and binary forms, with or without
12dd84a43cSPoul-Henning Kamp  * modification, are permitted provided that the following conditions
13dd84a43cSPoul-Henning Kamp  * are met:
14dd84a43cSPoul-Henning Kamp  * 1. Redistributions of source code must retain the above copyright
15dd84a43cSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer.
16dd84a43cSPoul-Henning Kamp  * 2. Redistributions in binary form must reproduce the above copyright
17dd84a43cSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer in the
18dd84a43cSPoul-Henning Kamp  *    documentation and/or other materials provided with the distribution.
19dd84a43cSPoul-Henning Kamp  * 3. The names of the authors may not be used to endorse or promote
20dd84a43cSPoul-Henning Kamp  *    products derived from this software without specific prior written
21dd84a43cSPoul-Henning Kamp  *    permission.
22dd84a43cSPoul-Henning Kamp  *
23dd84a43cSPoul-Henning Kamp  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24dd84a43cSPoul-Henning Kamp  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25dd84a43cSPoul-Henning Kamp  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26dd84a43cSPoul-Henning Kamp  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27dd84a43cSPoul-Henning Kamp  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28dd84a43cSPoul-Henning Kamp  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29dd84a43cSPoul-Henning Kamp  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30dd84a43cSPoul-Henning Kamp  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31dd84a43cSPoul-Henning Kamp  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32dd84a43cSPoul-Henning Kamp  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33dd84a43cSPoul-Henning Kamp  * SUCH DAMAGE.
34dd84a43cSPoul-Henning Kamp  */
35dd84a43cSPoul-Henning Kamp 
3650b1faefSDavid E. O'Brien #include <sys/cdefs.h>
3750b1faefSDavid E. O'Brien __FBSDID("$FreeBSD$");
38dd84a43cSPoul-Henning Kamp 
39dd84a43cSPoul-Henning Kamp #include <sys/param.h>
40dd84a43cSPoul-Henning Kamp #include <sys/systm.h>
41dd84a43cSPoul-Henning Kamp #include <sys/kernel.h>
42dd84a43cSPoul-Henning Kamp #include <sys/malloc.h>
43dd84a43cSPoul-Henning Kamp #include <sys/bio.h>
4449dbb61dSRobert Watson #include <sys/ktr.h>
4551460da8SJohn Baldwin #include <sys/proc.h>
463b378147SPawel Jakub Dawidek #include <sys/stack.h>
47dd84a43cSPoul-Henning Kamp 
48dd84a43cSPoul-Henning Kamp #include <sys/errno.h>
49dd84a43cSPoul-Henning Kamp #include <geom/geom.h>
50b1876192SPoul-Henning Kamp #include <geom/geom_int.h>
51e24cbd90SPoul-Henning Kamp #include <sys/devicestat.h>
52dd84a43cSPoul-Henning Kamp 
535ffb2c8bSPoul-Henning Kamp #include <vm/uma.h>
545ffb2c8bSPoul-Henning Kamp 
55dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_down;
56dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_up;
575fcf4e43SPoul-Henning Kamp static struct g_bioq g_bio_run_task;
58dd84a43cSPoul-Henning Kamp 
593432e4fdSPoul-Henning Kamp static u_int pace;
605ffb2c8bSPoul-Henning Kamp static uma_zone_t	biozone;
613432e4fdSPoul-Henning Kamp 
626231f75bSLuigi Rizzo /*
636231f75bSLuigi Rizzo  * The head of the list of classifiers used in g_io_request.
646231f75bSLuigi Rizzo  * Use g_register_classifier() and g_unregister_classifier()
656231f75bSLuigi Rizzo  * to add/remove entries to the list.
666231f75bSLuigi Rizzo  * Classifiers are invoked in registration order.
676231f75bSLuigi Rizzo  */
686231f75bSLuigi Rizzo static TAILQ_HEAD(g_classifier_tailq, g_classifier_hook)
696231f75bSLuigi Rizzo     g_classifier_tailq = TAILQ_HEAD_INITIALIZER(g_classifier_tailq);
706231f75bSLuigi Rizzo 
71dd84a43cSPoul-Henning Kamp #include <machine/atomic.h>
72dd84a43cSPoul-Henning Kamp 
73dd84a43cSPoul-Henning Kamp static void
74dd84a43cSPoul-Henning Kamp g_bioq_lock(struct g_bioq *bq)
75dd84a43cSPoul-Henning Kamp {
76dd84a43cSPoul-Henning Kamp 
77dd84a43cSPoul-Henning Kamp 	mtx_lock(&bq->bio_queue_lock);
78dd84a43cSPoul-Henning Kamp }
79dd84a43cSPoul-Henning Kamp 
80dd84a43cSPoul-Henning Kamp static void
81dd84a43cSPoul-Henning Kamp g_bioq_unlock(struct g_bioq *bq)
82dd84a43cSPoul-Henning Kamp {
83dd84a43cSPoul-Henning Kamp 
84dd84a43cSPoul-Henning Kamp 	mtx_unlock(&bq->bio_queue_lock);
85dd84a43cSPoul-Henning Kamp }
86dd84a43cSPoul-Henning Kamp 
87dd84a43cSPoul-Henning Kamp #if 0
88dd84a43cSPoul-Henning Kamp static void
89dd84a43cSPoul-Henning Kamp g_bioq_destroy(struct g_bioq *bq)
90dd84a43cSPoul-Henning Kamp {
91dd84a43cSPoul-Henning Kamp 
92dd84a43cSPoul-Henning Kamp 	mtx_destroy(&bq->bio_queue_lock);
93dd84a43cSPoul-Henning Kamp }
94dd84a43cSPoul-Henning Kamp #endif
95dd84a43cSPoul-Henning Kamp 
96dd84a43cSPoul-Henning Kamp static void
97dd84a43cSPoul-Henning Kamp g_bioq_init(struct g_bioq *bq)
98dd84a43cSPoul-Henning Kamp {
99dd84a43cSPoul-Henning Kamp 
100dd84a43cSPoul-Henning Kamp 	TAILQ_INIT(&bq->bio_queue);
1016008862bSJohn Baldwin 	mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF);
102dd84a43cSPoul-Henning Kamp }
103dd84a43cSPoul-Henning Kamp 
104dd84a43cSPoul-Henning Kamp static struct bio *
105dd84a43cSPoul-Henning Kamp g_bioq_first(struct g_bioq *bq)
106dd84a43cSPoul-Henning Kamp {
107dd84a43cSPoul-Henning Kamp 	struct bio *bp;
108dd84a43cSPoul-Henning Kamp 
109dd84a43cSPoul-Henning Kamp 	bp = TAILQ_FIRST(&bq->bio_queue);
110dd84a43cSPoul-Henning Kamp 	if (bp != NULL) {
111dcbd0fe5SPoul-Henning Kamp 		KASSERT((bp->bio_flags & BIO_ONQUEUE),
112dcbd0fe5SPoul-Henning Kamp 		    ("Bio not on queue bp=%p target %p", bp, bq));
113dcbd0fe5SPoul-Henning Kamp 		bp->bio_flags &= ~BIO_ONQUEUE;
114dd84a43cSPoul-Henning Kamp 		TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue);
115dd84a43cSPoul-Henning Kamp 		bq->bio_queue_length--;
116dd84a43cSPoul-Henning Kamp 	}
117dd84a43cSPoul-Henning Kamp 	return (bp);
118dd84a43cSPoul-Henning Kamp }
119dd84a43cSPoul-Henning Kamp 
120dd84a43cSPoul-Henning Kamp struct bio *
121dd84a43cSPoul-Henning Kamp g_new_bio(void)
122dd84a43cSPoul-Henning Kamp {
123dd84a43cSPoul-Henning Kamp 	struct bio *bp;
124dd84a43cSPoul-Henning Kamp 
1255ffb2c8bSPoul-Henning Kamp 	bp = uma_zalloc(biozone, M_NOWAIT | M_ZERO);
1263b378147SPawel Jakub Dawidek #ifdef KTR
127b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
1283b378147SPawel Jakub Dawidek 		struct stack st;
1293b378147SPawel Jakub Dawidek 
1303b378147SPawel Jakub Dawidek 		CTR1(KTR_GEOM, "g_new_bio(): %p", bp);
1313b378147SPawel Jakub Dawidek 		stack_save(&st);
1323b378147SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
1333b378147SPawel Jakub Dawidek 	}
1343b378147SPawel Jakub Dawidek #endif
135dd84a43cSPoul-Henning Kamp 	return (bp);
136dd84a43cSPoul-Henning Kamp }
137dd84a43cSPoul-Henning Kamp 
138a2033c96SPoul-Henning Kamp struct bio *
139a2033c96SPoul-Henning Kamp g_alloc_bio(void)
140a2033c96SPoul-Henning Kamp {
141a2033c96SPoul-Henning Kamp 	struct bio *bp;
142a2033c96SPoul-Henning Kamp 
143a2033c96SPoul-Henning Kamp 	bp = uma_zalloc(biozone, M_WAITOK | M_ZERO);
1443b378147SPawel Jakub Dawidek #ifdef KTR
145b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
1463b378147SPawel Jakub Dawidek 		struct stack st;
1473b378147SPawel Jakub Dawidek 
1483b378147SPawel Jakub Dawidek 		CTR1(KTR_GEOM, "g_alloc_bio(): %p", bp);
1493b378147SPawel Jakub Dawidek 		stack_save(&st);
1503b378147SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
1513b378147SPawel Jakub Dawidek 	}
1523b378147SPawel Jakub Dawidek #endif
153a2033c96SPoul-Henning Kamp 	return (bp);
154a2033c96SPoul-Henning Kamp }
155a2033c96SPoul-Henning Kamp 
156dd84a43cSPoul-Henning Kamp void
157dd84a43cSPoul-Henning Kamp g_destroy_bio(struct bio *bp)
158dd84a43cSPoul-Henning Kamp {
1593b378147SPawel Jakub Dawidek #ifdef KTR
160b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
1613b378147SPawel Jakub Dawidek 		struct stack st;
162dd84a43cSPoul-Henning Kamp 
1633b378147SPawel Jakub Dawidek 		CTR1(KTR_GEOM, "g_destroy_bio(): %p", bp);
1643b378147SPawel Jakub Dawidek 		stack_save(&st);
1653b378147SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
1663b378147SPawel Jakub Dawidek 	}
1673b378147SPawel Jakub Dawidek #endif
1685ffb2c8bSPoul-Henning Kamp 	uma_zfree(biozone, bp);
169dd84a43cSPoul-Henning Kamp }
170dd84a43cSPoul-Henning Kamp 
171dd84a43cSPoul-Henning Kamp struct bio *
172dd84a43cSPoul-Henning Kamp g_clone_bio(struct bio *bp)
173dd84a43cSPoul-Henning Kamp {
174dd84a43cSPoul-Henning Kamp 	struct bio *bp2;
175dd84a43cSPoul-Henning Kamp 
1765ffb2c8bSPoul-Henning Kamp 	bp2 = uma_zalloc(biozone, M_NOWAIT | M_ZERO);
177a1bd3ee2SPoul-Henning Kamp 	if (bp2 != NULL) {
178936cc461SPoul-Henning Kamp 		bp2->bio_parent = bp;
179dd84a43cSPoul-Henning Kamp 		bp2->bio_cmd = bp->bio_cmd;
180dd84a43cSPoul-Henning Kamp 		bp2->bio_length = bp->bio_length;
181dd84a43cSPoul-Henning Kamp 		bp2->bio_offset = bp->bio_offset;
182dd84a43cSPoul-Henning Kamp 		bp2->bio_data = bp->bio_data;
183dd84a43cSPoul-Henning Kamp 		bp2->bio_attribute = bp->bio_attribute;
1846231f75bSLuigi Rizzo 		/* Inherit classification info from the parent */
1856231f75bSLuigi Rizzo 		bp2->bio_classifier1 = bp->bio_classifier1;
1866231f75bSLuigi Rizzo 		bp2->bio_classifier2 = bp->bio_classifier2;
187801bb689SPoul-Henning Kamp 		bp->bio_children++;
188a1bd3ee2SPoul-Henning Kamp 	}
1893b378147SPawel Jakub Dawidek #ifdef KTR
190b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
1913b378147SPawel Jakub Dawidek 		struct stack st;
1923b378147SPawel Jakub Dawidek 
193ad572235SRuslan Ermilov 		CTR2(KTR_GEOM, "g_clone_bio(%p): %p", bp, bp2);
1943b378147SPawel Jakub Dawidek 		stack_save(&st);
1953b378147SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
1963b378147SPawel Jakub Dawidek 	}
1973b378147SPawel Jakub Dawidek #endif
198dd84a43cSPoul-Henning Kamp 	return(bp2);
199dd84a43cSPoul-Henning Kamp }
200dd84a43cSPoul-Henning Kamp 
2014bec0ff1SPawel Jakub Dawidek struct bio *
2024bec0ff1SPawel Jakub Dawidek g_duplicate_bio(struct bio *bp)
2034bec0ff1SPawel Jakub Dawidek {
2044bec0ff1SPawel Jakub Dawidek 	struct bio *bp2;
2054bec0ff1SPawel Jakub Dawidek 
2064bec0ff1SPawel Jakub Dawidek 	bp2 = uma_zalloc(biozone, M_WAITOK | M_ZERO);
2074bec0ff1SPawel Jakub Dawidek 	bp2->bio_parent = bp;
2084bec0ff1SPawel Jakub Dawidek 	bp2->bio_cmd = bp->bio_cmd;
2094bec0ff1SPawel Jakub Dawidek 	bp2->bio_length = bp->bio_length;
2104bec0ff1SPawel Jakub Dawidek 	bp2->bio_offset = bp->bio_offset;
2114bec0ff1SPawel Jakub Dawidek 	bp2->bio_data = bp->bio_data;
2124bec0ff1SPawel Jakub Dawidek 	bp2->bio_attribute = bp->bio_attribute;
2134bec0ff1SPawel Jakub Dawidek 	bp->bio_children++;
2144bec0ff1SPawel Jakub Dawidek #ifdef KTR
215b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
2164bec0ff1SPawel Jakub Dawidek 		struct stack st;
2174bec0ff1SPawel Jakub Dawidek 
2184bec0ff1SPawel Jakub Dawidek 		CTR2(KTR_GEOM, "g_duplicate_bio(%p): %p", bp, bp2);
2194bec0ff1SPawel Jakub Dawidek 		stack_save(&st);
2204bec0ff1SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
2214bec0ff1SPawel Jakub Dawidek 	}
2224bec0ff1SPawel Jakub Dawidek #endif
2234bec0ff1SPawel Jakub Dawidek 	return(bp2);
2244bec0ff1SPawel Jakub Dawidek }
2254bec0ff1SPawel Jakub Dawidek 
226dd84a43cSPoul-Henning Kamp void
227dd84a43cSPoul-Henning Kamp g_io_init()
228dd84a43cSPoul-Henning Kamp {
229dd84a43cSPoul-Henning Kamp 
230dd84a43cSPoul-Henning Kamp 	g_bioq_init(&g_bio_run_down);
231dd84a43cSPoul-Henning Kamp 	g_bioq_init(&g_bio_run_up);
2325fcf4e43SPoul-Henning Kamp 	g_bioq_init(&g_bio_run_task);
2335ffb2c8bSPoul-Henning Kamp 	biozone = uma_zcreate("g_bio", sizeof (struct bio),
2345ffb2c8bSPoul-Henning Kamp 	    NULL, NULL,
2355ffb2c8bSPoul-Henning Kamp 	    NULL, NULL,
2365ffb2c8bSPoul-Henning Kamp 	    0, 0);
237dd84a43cSPoul-Henning Kamp }
238dd84a43cSPoul-Henning Kamp 
239dd84a43cSPoul-Henning Kamp int
2400d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr)
241dd84a43cSPoul-Henning Kamp {
242dd84a43cSPoul-Henning Kamp 	struct bio *bp;
243dd84a43cSPoul-Henning Kamp 	int error;
244dd84a43cSPoul-Henning Kamp 
245dd84a43cSPoul-Henning Kamp 	g_trace(G_T_BIO, "bio_getattr(%s)", attr);
246a2033c96SPoul-Henning Kamp 	bp = g_alloc_bio();
247dd84a43cSPoul-Henning Kamp 	bp->bio_cmd = BIO_GETATTR;
248dd84a43cSPoul-Henning Kamp 	bp->bio_done = NULL;
249dd84a43cSPoul-Henning Kamp 	bp->bio_attribute = attr;
250dd84a43cSPoul-Henning Kamp 	bp->bio_length = *len;
251dd84a43cSPoul-Henning Kamp 	bp->bio_data = ptr;
252dd84a43cSPoul-Henning Kamp 	g_io_request(bp, cp);
25353706245SPoul-Henning Kamp 	error = biowait(bp, "ggetattr");
254dd84a43cSPoul-Henning Kamp 	*len = bp->bio_completed;
255dd84a43cSPoul-Henning Kamp 	g_destroy_bio(bp);
256dd84a43cSPoul-Henning Kamp 	return (error);
257dd84a43cSPoul-Henning Kamp }
258dd84a43cSPoul-Henning Kamp 
259c3618c65SPawel Jakub Dawidek int
260c3618c65SPawel Jakub Dawidek g_io_flush(struct g_consumer *cp)
261c3618c65SPawel Jakub Dawidek {
262c3618c65SPawel Jakub Dawidek 	struct bio *bp;
263c3618c65SPawel Jakub Dawidek 	int error;
264c3618c65SPawel Jakub Dawidek 
265c3618c65SPawel Jakub Dawidek 	g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name);
266c3618c65SPawel Jakub Dawidek 	bp = g_alloc_bio();
267c3618c65SPawel Jakub Dawidek 	bp->bio_cmd = BIO_FLUSH;
268c3618c65SPawel Jakub Dawidek 	bp->bio_done = NULL;
269c3618c65SPawel Jakub Dawidek 	bp->bio_attribute = NULL;
270c3618c65SPawel Jakub Dawidek 	bp->bio_offset = cp->provider->mediasize;
271c3618c65SPawel Jakub Dawidek 	bp->bio_length = 0;
272c3618c65SPawel Jakub Dawidek 	bp->bio_data = NULL;
273c3618c65SPawel Jakub Dawidek 	g_io_request(bp, cp);
274c3618c65SPawel Jakub Dawidek 	error = biowait(bp, "gflush");
275c3618c65SPawel Jakub Dawidek 	g_destroy_bio(bp);
276c3618c65SPawel Jakub Dawidek 	return (error);
277c3618c65SPawel Jakub Dawidek }
278c3618c65SPawel Jakub Dawidek 
279e39d70d4SPoul-Henning Kamp static int
280e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp)
281e39d70d4SPoul-Henning Kamp {
282e39d70d4SPoul-Henning Kamp 	struct g_consumer *cp;
283e39d70d4SPoul-Henning Kamp 	struct g_provider *pp;
284e39d70d4SPoul-Henning Kamp 
285e39d70d4SPoul-Henning Kamp 	cp = bp->bio_from;
286e39d70d4SPoul-Henning Kamp 	pp = bp->bio_to;
287e39d70d4SPoul-Henning Kamp 
288e39d70d4SPoul-Henning Kamp 	/* Fail if access counters dont allow the operation */
289e39d70d4SPoul-Henning Kamp 	switch(bp->bio_cmd) {
290e39d70d4SPoul-Henning Kamp 	case BIO_READ:
291e39d70d4SPoul-Henning Kamp 	case BIO_GETATTR:
292e39d70d4SPoul-Henning Kamp 		if (cp->acr == 0)
293e39d70d4SPoul-Henning Kamp 			return (EPERM);
294e39d70d4SPoul-Henning Kamp 		break;
295e39d70d4SPoul-Henning Kamp 	case BIO_WRITE:
296e39d70d4SPoul-Henning Kamp 	case BIO_DELETE:
297c3618c65SPawel Jakub Dawidek 	case BIO_FLUSH:
298e39d70d4SPoul-Henning Kamp 		if (cp->acw == 0)
299e39d70d4SPoul-Henning Kamp 			return (EPERM);
300e39d70d4SPoul-Henning Kamp 		break;
301e39d70d4SPoul-Henning Kamp 	default:
302e39d70d4SPoul-Henning Kamp 		return (EPERM);
303e39d70d4SPoul-Henning Kamp 	}
304e39d70d4SPoul-Henning Kamp 	/* if provider is marked for error, don't disturb. */
305e39d70d4SPoul-Henning Kamp 	if (pp->error)
306e39d70d4SPoul-Henning Kamp 		return (pp->error);
307e39d70d4SPoul-Henning Kamp 
308e39d70d4SPoul-Henning Kamp 	switch(bp->bio_cmd) {
309e39d70d4SPoul-Henning Kamp 	case BIO_READ:
310e39d70d4SPoul-Henning Kamp 	case BIO_WRITE:
311e39d70d4SPoul-Henning Kamp 	case BIO_DELETE:
312*2a842317SAndriy Gapon 		/* Zero sectorsize or mediasize is probably a lack of media. */
313*2a842317SAndriy Gapon 		if (pp->sectorsize == 0 || pp->mediasize == 0)
31443bff1a7SPoul-Henning Kamp 			return (ENXIO);
315e39d70d4SPoul-Henning Kamp 		/* Reject I/O not on sector boundary */
316e39d70d4SPoul-Henning Kamp 		if (bp->bio_offset % pp->sectorsize)
317e39d70d4SPoul-Henning Kamp 			return (EINVAL);
318e39d70d4SPoul-Henning Kamp 		/* Reject I/O not integral sector long */
319e39d70d4SPoul-Henning Kamp 		if (bp->bio_length % pp->sectorsize)
320e39d70d4SPoul-Henning Kamp 			return (EINVAL);
321d1b8bf47SPoul-Henning Kamp 		/* Reject requests before or past the end of media. */
322d1b8bf47SPoul-Henning Kamp 		if (bp->bio_offset < 0)
323d1b8bf47SPoul-Henning Kamp 			return (EIO);
324e39d70d4SPoul-Henning Kamp 		if (bp->bio_offset > pp->mediasize)
325e39d70d4SPoul-Henning Kamp 			return (EIO);
326e39d70d4SPoul-Henning Kamp 		break;
327e39d70d4SPoul-Henning Kamp 	default:
328e39d70d4SPoul-Henning Kamp 		break;
329e39d70d4SPoul-Henning Kamp 	}
330e39d70d4SPoul-Henning Kamp 	return (0);
331e39d70d4SPoul-Henning Kamp }
332e39d70d4SPoul-Henning Kamp 
3336231f75bSLuigi Rizzo /*
3346231f75bSLuigi Rizzo  * bio classification support.
3356231f75bSLuigi Rizzo  *
3366231f75bSLuigi Rizzo  * g_register_classifier() and g_unregister_classifier()
3376231f75bSLuigi Rizzo  * are used to add/remove a classifier from the list.
3386231f75bSLuigi Rizzo  * The list is protected using the g_bio_run_down lock,
3396231f75bSLuigi Rizzo  * because the classifiers are called in this path.
3406231f75bSLuigi Rizzo  *
3416231f75bSLuigi Rizzo  * g_io_request() passes bio's that are not already classified
3426231f75bSLuigi Rizzo  * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers().
3436231f75bSLuigi Rizzo  * Classifiers can store their result in the two fields
3446231f75bSLuigi Rizzo  * bio_classifier1 and bio_classifier2.
3456231f75bSLuigi Rizzo  * A classifier that updates one of the fields should
3466231f75bSLuigi Rizzo  * return a non-zero value.
3476231f75bSLuigi Rizzo  * If no classifier updates the field, g_run_classifiers() sets
3486231f75bSLuigi Rizzo  * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls.
3496231f75bSLuigi Rizzo  */
3506231f75bSLuigi Rizzo 
3516231f75bSLuigi Rizzo int
3526231f75bSLuigi Rizzo g_register_classifier(struct g_classifier_hook *hook)
3536231f75bSLuigi Rizzo {
3546231f75bSLuigi Rizzo 
3556231f75bSLuigi Rizzo 	g_bioq_lock(&g_bio_run_down);
3566231f75bSLuigi Rizzo 	TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link);
3576231f75bSLuigi Rizzo 	g_bioq_unlock(&g_bio_run_down);
3586231f75bSLuigi Rizzo 
3596231f75bSLuigi Rizzo 	return (0);
3606231f75bSLuigi Rizzo }
3616231f75bSLuigi Rizzo 
3626231f75bSLuigi Rizzo void
3636231f75bSLuigi Rizzo g_unregister_classifier(struct g_classifier_hook *hook)
3646231f75bSLuigi Rizzo {
3656231f75bSLuigi Rizzo 	struct g_classifier_hook *entry;
3666231f75bSLuigi Rizzo 
3676231f75bSLuigi Rizzo 	g_bioq_lock(&g_bio_run_down);
3686231f75bSLuigi Rizzo 	TAILQ_FOREACH(entry, &g_classifier_tailq, link) {
3696231f75bSLuigi Rizzo 		if (entry == hook) {
3706231f75bSLuigi Rizzo 			TAILQ_REMOVE(&g_classifier_tailq, hook, link);
3716231f75bSLuigi Rizzo 			break;
3726231f75bSLuigi Rizzo 		}
3736231f75bSLuigi Rizzo 	}
3746231f75bSLuigi Rizzo 	g_bioq_unlock(&g_bio_run_down);
3756231f75bSLuigi Rizzo }
3766231f75bSLuigi Rizzo 
3776231f75bSLuigi Rizzo static void
3786231f75bSLuigi Rizzo g_run_classifiers(struct bio *bp)
3796231f75bSLuigi Rizzo {
3806231f75bSLuigi Rizzo 	struct g_classifier_hook *hook;
3816231f75bSLuigi Rizzo 	int classified = 0;
3826231f75bSLuigi Rizzo 
3836231f75bSLuigi Rizzo 	TAILQ_FOREACH(hook, &g_classifier_tailq, link)
3846231f75bSLuigi Rizzo 		classified |= hook->func(hook->arg, bp);
3856231f75bSLuigi Rizzo 
3866231f75bSLuigi Rizzo 	if (!classified)
3876231f75bSLuigi Rizzo 		bp->bio_classifier1 = BIO_NOTCLASSIFIED;
3886231f75bSLuigi Rizzo }
3896231f75bSLuigi Rizzo 
390dd84a43cSPoul-Henning Kamp void
391dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp)
392dd84a43cSPoul-Henning Kamp {
393801bb689SPoul-Henning Kamp 	struct g_provider *pp;
3940d883b11SAlexander Motin 	int first;
395dd84a43cSPoul-Henning Kamp 
396d0e17c1bSPoul-Henning Kamp 	KASSERT(cp != NULL, ("NULL cp in g_io_request"));
397d0e17c1bSPoul-Henning Kamp 	KASSERT(bp != NULL, ("NULL bp in g_io_request"));
398e060b6bdSPoul-Henning Kamp 	pp = cp->provider;
399801bb689SPoul-Henning Kamp 	KASSERT(pp != NULL, ("consumer not attached in g_io_request"));
40092ee312dSPawel Jakub Dawidek #ifdef DIAGNOSTIC
40192ee312dSPawel Jakub Dawidek 	KASSERT(bp->bio_driver1 == NULL,
40292ee312dSPawel Jakub Dawidek 	    ("bio_driver1 used by the consumer (geom %s)", cp->geom->name));
40392ee312dSPawel Jakub Dawidek 	KASSERT(bp->bio_driver2 == NULL,
40492ee312dSPawel Jakub Dawidek 	    ("bio_driver2 used by the consumer (geom %s)", cp->geom->name));
40592ee312dSPawel Jakub Dawidek 	KASSERT(bp->bio_pflags == 0,
40692ee312dSPawel Jakub Dawidek 	    ("bio_pflags used by the consumer (geom %s)", cp->geom->name));
40792ee312dSPawel Jakub Dawidek 	/*
40892ee312dSPawel Jakub Dawidek 	 * Remember consumer's private fields, so we can detect if they were
40992ee312dSPawel Jakub Dawidek 	 * modified by the provider.
41092ee312dSPawel Jakub Dawidek 	 */
41192ee312dSPawel Jakub Dawidek 	bp->_bio_caller1 = bp->bio_caller1;
41292ee312dSPawel Jakub Dawidek 	bp->_bio_caller2 = bp->bio_caller2;
41392ee312dSPawel Jakub Dawidek 	bp->_bio_cflags = bp->bio_cflags;
41492ee312dSPawel Jakub Dawidek #endif
415801bb689SPoul-Henning Kamp 
4161ded77b2SPawel Jakub Dawidek 	if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) {
417c3618c65SPawel Jakub Dawidek 		KASSERT(bp->bio_data != NULL,
4181ded77b2SPawel Jakub Dawidek 		    ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd));
4191ded77b2SPawel Jakub Dawidek 	}
4201ded77b2SPawel Jakub Dawidek 	if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) {
4211ded77b2SPawel Jakub Dawidek 		KASSERT(bp->bio_data == NULL,
4221ded77b2SPawel Jakub Dawidek 		    ("non-NULL bp->data in g_io_request(cmd=%hhu)",
4231ded77b2SPawel Jakub Dawidek 		    bp->bio_cmd));
424c3618c65SPawel Jakub Dawidek 	}
425dcbd0fe5SPoul-Henning Kamp 	if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) {
426dcbd0fe5SPoul-Henning Kamp 		KASSERT(bp->bio_offset % cp->provider->sectorsize == 0,
427dcbd0fe5SPoul-Henning Kamp 		    ("wrong offset %jd for sectorsize %u",
428dcbd0fe5SPoul-Henning Kamp 		    bp->bio_offset, cp->provider->sectorsize));
429dcbd0fe5SPoul-Henning Kamp 		KASSERT(bp->bio_length % cp->provider->sectorsize == 0,
430dcbd0fe5SPoul-Henning Kamp 		    ("wrong length %jd for sectorsize %u",
431dcbd0fe5SPoul-Henning Kamp 		    bp->bio_length, cp->provider->sectorsize));
432dcbd0fe5SPoul-Henning Kamp 	}
433dcbd0fe5SPoul-Henning Kamp 
434f7717523SStephan Uphoff 	g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d",
435f7717523SStephan Uphoff 	    bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd);
436f7717523SStephan Uphoff 
437dd84a43cSPoul-Henning Kamp 	bp->bio_from = cp;
438801bb689SPoul-Henning Kamp 	bp->bio_to = pp;
4392fccec19SPoul-Henning Kamp 	bp->bio_error = 0;
4402fccec19SPoul-Henning Kamp 	bp->bio_completed = 0;
441dd84a43cSPoul-Henning Kamp 
44219fa21aaSPoul-Henning Kamp 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
44319fa21aaSPoul-Henning Kamp 	    ("Bio already on queue bp=%p", bp));
44419fa21aaSPoul-Henning Kamp 	bp->bio_flags |= BIO_ONQUEUE;
44519fa21aaSPoul-Henning Kamp 
446a5be8eb5SAlexander Motin 	if (g_collectstats)
44719fa21aaSPoul-Henning Kamp 		binuptime(&bp->bio_t0);
448a5be8eb5SAlexander Motin 	else
449a5be8eb5SAlexander Motin 		getbinuptime(&bp->bio_t0);
4508827c821SPoul-Henning Kamp 
4518827c821SPoul-Henning Kamp 	/*
4528827c821SPoul-Henning Kamp 	 * The statistics collection is lockless, as such, but we
4538827c821SPoul-Henning Kamp 	 * can not update one instance of the statistics from more
4548827c821SPoul-Henning Kamp 	 * than one thread at a time, so grab the lock first.
4556231f75bSLuigi Rizzo 	 *
4566231f75bSLuigi Rizzo 	 * We also use the lock to protect the list of classifiers.
4578827c821SPoul-Henning Kamp 	 */
45819fa21aaSPoul-Henning Kamp 	g_bioq_lock(&g_bio_run_down);
4596231f75bSLuigi Rizzo 
4606231f75bSLuigi Rizzo 	if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1)
4616231f75bSLuigi Rizzo 		g_run_classifiers(bp);
4626231f75bSLuigi Rizzo 
463cf457284SPoul-Henning Kamp 	if (g_collectstats & 1)
46419fa21aaSPoul-Henning Kamp 		devstat_start_transaction(pp->stat, &bp->bio_t0);
465cf457284SPoul-Henning Kamp 	if (g_collectstats & 2)
46619fa21aaSPoul-Henning Kamp 		devstat_start_transaction(cp->stat, &bp->bio_t0);
46719fa21aaSPoul-Henning Kamp 
46819fa21aaSPoul-Henning Kamp 	pp->nstart++;
469cf457284SPoul-Henning Kamp 	cp->nstart++;
4700d883b11SAlexander Motin 	first = TAILQ_EMPTY(&g_bio_run_down.bio_queue);
47119fa21aaSPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&g_bio_run_down.bio_queue, bp, bio_queue);
47219fa21aaSPoul-Henning Kamp 	g_bio_run_down.bio_queue_length++;
47319fa21aaSPoul-Henning Kamp 	g_bioq_unlock(&g_bio_run_down);
474e39d70d4SPoul-Henning Kamp 
4752fccec19SPoul-Henning Kamp 	/* Pass it on down. */
4760d883b11SAlexander Motin 	if (first)
477dd84a43cSPoul-Henning Kamp 		wakeup(&g_wait_down);
478dd84a43cSPoul-Henning Kamp }
479dd84a43cSPoul-Henning Kamp 
480dd84a43cSPoul-Henning Kamp void
48172840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error)
482dd84a43cSPoul-Henning Kamp {
483801bb689SPoul-Henning Kamp 	struct g_consumer *cp;
484801bb689SPoul-Henning Kamp 	struct g_provider *pp;
4850d883b11SAlexander Motin 	int first;
486dd84a43cSPoul-Henning Kamp 
487e060b6bdSPoul-Henning Kamp 	KASSERT(bp != NULL, ("NULL bp in g_io_deliver"));
488801bb689SPoul-Henning Kamp 	pp = bp->bio_to;
489f7eeab17SPoul-Henning Kamp 	KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver"));
490f7eeab17SPoul-Henning Kamp 	cp = bp->bio_from;
491f7eeab17SPoul-Henning Kamp 	if (cp == NULL) {
492f7eeab17SPoul-Henning Kamp 		bp->bio_error = error;
493f7eeab17SPoul-Henning Kamp 		bp->bio_done(bp);
494f7eeab17SPoul-Henning Kamp 		return;
495f7eeab17SPoul-Henning Kamp 	}
496801bb689SPoul-Henning Kamp 	KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver"));
497801bb689SPoul-Henning Kamp 	KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver"));
498fb231f36SEdward Tomasz Napierala #ifdef DIAGNOSTIC
499fb231f36SEdward Tomasz Napierala 	/*
500fb231f36SEdward Tomasz Napierala 	 * Some classes - GJournal in particular - can modify bio's
501fb231f36SEdward Tomasz Napierala 	 * private fields while the bio is in transit; G_GEOM_VOLATILE_BIO
502fb231f36SEdward Tomasz Napierala 	 * flag means it's an expected behaviour for that particular geom.
503fb231f36SEdward Tomasz Napierala 	 */
504fb231f36SEdward Tomasz Napierala 	if ((cp->geom->flags & G_GEOM_VOLATILE_BIO) == 0) {
505fb231f36SEdward Tomasz Napierala 		KASSERT(bp->bio_caller1 == bp->_bio_caller1,
506fb231f36SEdward Tomasz Napierala 		    ("bio_caller1 used by the provider %s", pp->name));
507fb231f36SEdward Tomasz Napierala 		KASSERT(bp->bio_caller2 == bp->_bio_caller2,
508fb231f36SEdward Tomasz Napierala 		    ("bio_caller2 used by the provider %s", pp->name));
509fb231f36SEdward Tomasz Napierala 		KASSERT(bp->bio_cflags == bp->_bio_cflags,
510fb231f36SEdward Tomasz Napierala 		    ("bio_cflags used by the provider %s", pp->name));
511fb231f36SEdward Tomasz Napierala 	}
512fb231f36SEdward Tomasz Napierala #endif
51346aeebecSPawel Jakub Dawidek 	KASSERT(bp->bio_completed >= 0, ("bio_completed can't be less than 0"));
51446aeebecSPawel Jakub Dawidek 	KASSERT(bp->bio_completed <= bp->bio_length,
51546aeebecSPawel Jakub Dawidek 	    ("bio_completed can't be greater than bio_length"));
5165ab413bfSPoul-Henning Kamp 
517dd84a43cSPoul-Henning Kamp 	g_trace(G_T_BIO,
5180355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd",
519801bb689SPoul-Henning Kamp 	    bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error,
5200355b86eSPoul-Henning Kamp 	    (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length);
521801bb689SPoul-Henning Kamp 
52219fa21aaSPoul-Henning Kamp 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
52319fa21aaSPoul-Henning Kamp 	    ("Bio already on queue bp=%p", bp));
52419fa21aaSPoul-Henning Kamp 
525dcbd0fe5SPoul-Henning Kamp 	/*
526dcbd0fe5SPoul-Henning Kamp 	 * XXX: next two doesn't belong here
527dcbd0fe5SPoul-Henning Kamp 	 */
528e24cbd90SPoul-Henning Kamp 	bp->bio_bcount = bp->bio_length;
529e24cbd90SPoul-Henning Kamp 	bp->bio_resid = bp->bio_bcount - bp->bio_completed;
53019fa21aaSPoul-Henning Kamp 
5318827c821SPoul-Henning Kamp 	/*
5328827c821SPoul-Henning Kamp 	 * The statistics collection is lockless, as such, but we
5338827c821SPoul-Henning Kamp 	 * can not update one instance of the statistics from more
5348827c821SPoul-Henning Kamp 	 * than one thread at a time, so grab the lock first.
5358827c821SPoul-Henning Kamp 	 */
53619fa21aaSPoul-Henning Kamp 	g_bioq_lock(&g_bio_run_up);
537cf457284SPoul-Henning Kamp 	if (g_collectstats & 1)
538e24cbd90SPoul-Henning Kamp 		devstat_end_transaction_bio(pp->stat, bp);
539cf457284SPoul-Henning Kamp 	if (g_collectstats & 2)
540cf457284SPoul-Henning Kamp 		devstat_end_transaction_bio(cp->stat, bp);
5418827c821SPoul-Henning Kamp 
542c6ae9b5fSPoul-Henning Kamp 	cp->nend++;
543c6ae9b5fSPoul-Henning Kamp 	pp->nend++;
54419fa21aaSPoul-Henning Kamp 	if (error != ENOMEM) {
54519fa21aaSPoul-Henning Kamp 		bp->bio_error = error;
5460d883b11SAlexander Motin 		first = TAILQ_EMPTY(&g_bio_run_up.bio_queue);
54719fa21aaSPoul-Henning Kamp 		TAILQ_INSERT_TAIL(&g_bio_run_up.bio_queue, bp, bio_queue);
548276f72c5SPoul-Henning Kamp 		bp->bio_flags |= BIO_ONQUEUE;
54919fa21aaSPoul-Henning Kamp 		g_bio_run_up.bio_queue_length++;
55019fa21aaSPoul-Henning Kamp 		g_bioq_unlock(&g_bio_run_up);
5510d883b11SAlexander Motin 		if (first)
55219fa21aaSPoul-Henning Kamp 			wakeup(&g_wait_up);
55319fa21aaSPoul-Henning Kamp 		return;
55419fa21aaSPoul-Henning Kamp 	}
55519fa21aaSPoul-Henning Kamp 	g_bioq_unlock(&g_bio_run_up);
556dd84a43cSPoul-Henning Kamp 
5572cc9686eSPoul-Henning Kamp 	if (bootverbose)
558801bb689SPoul-Henning Kamp 		printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name);
5591b949c05SPawel Jakub Dawidek 	bp->bio_children = 0;
5601b949c05SPawel Jakub Dawidek 	bp->bio_inbed = 0;
561801bb689SPoul-Henning Kamp 	g_io_request(bp, cp);
5623432e4fdSPoul-Henning Kamp 	pace++;
5633432e4fdSPoul-Henning Kamp 	return;
5643432e4fdSPoul-Henning Kamp }
565dd84a43cSPoul-Henning Kamp 
566dd84a43cSPoul-Henning Kamp void
567dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused)
568dd84a43cSPoul-Henning Kamp {
569dd84a43cSPoul-Henning Kamp 	struct bio *bp;
570e39d70d4SPoul-Henning Kamp 	off_t excess;
571e39d70d4SPoul-Henning Kamp 	int error;
572dd84a43cSPoul-Henning Kamp 
573dd84a43cSPoul-Henning Kamp 	for(;;) {
574f0e185d7SPoul-Henning Kamp 		g_bioq_lock(&g_bio_run_down);
575dd84a43cSPoul-Henning Kamp 		bp = g_bioq_first(&g_bio_run_down);
576f0e185d7SPoul-Henning Kamp 		if (bp == NULL) {
57749dbb61dSRobert Watson 			CTR0(KTR_GEOM, "g_down going to sleep");
578f0e185d7SPoul-Henning Kamp 			msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock,
5797fc019afSAlexander Motin 			    PRIBIO | PDROP, "-", 0);
580f0e185d7SPoul-Henning Kamp 			continue;
581f0e185d7SPoul-Henning Kamp 		}
58249dbb61dSRobert Watson 		CTR0(KTR_GEOM, "g_down has work to do");
583f0e185d7SPoul-Henning Kamp 		g_bioq_unlock(&g_bio_run_down);
584376ceb79SPoul-Henning Kamp 		if (pace > 0) {
58549dbb61dSRobert Watson 			CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace);
5864d70511aSJohn Baldwin 			pause("g_down", hz/10);
587376ceb79SPoul-Henning Kamp 			pace--;
588376ceb79SPoul-Henning Kamp 		}
589e39d70d4SPoul-Henning Kamp 		error = g_io_check(bp);
590e39d70d4SPoul-Henning Kamp 		if (error) {
59149dbb61dSRobert Watson 			CTR3(KTR_GEOM, "g_down g_io_check on bp %p provider "
59249dbb61dSRobert Watson 			    "%s returned %d", bp, bp->bio_to->name, error);
593e39d70d4SPoul-Henning Kamp 			g_io_deliver(bp, error);
594e39d70d4SPoul-Henning Kamp 			continue;
595e39d70d4SPoul-Henning Kamp 		}
59649dbb61dSRobert Watson 		CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp,
59749dbb61dSRobert Watson 		    bp->bio_to->name);
598392d56b4SPoul-Henning Kamp 		switch (bp->bio_cmd) {
599392d56b4SPoul-Henning Kamp 		case BIO_READ:
600392d56b4SPoul-Henning Kamp 		case BIO_WRITE:
601392d56b4SPoul-Henning Kamp 		case BIO_DELETE:
602e39d70d4SPoul-Henning Kamp 			/* Truncate requests to the end of providers media. */
60349dbb61dSRobert Watson 			/*
60449dbb61dSRobert Watson 			 * XXX: What if we truncate because of offset being
60549dbb61dSRobert Watson 			 * bad, not length?
60649dbb61dSRobert Watson 			 */
607e39d70d4SPoul-Henning Kamp 			excess = bp->bio_offset + bp->bio_length;
608e39d70d4SPoul-Henning Kamp 			if (excess > bp->bio_to->mediasize) {
609e39d70d4SPoul-Henning Kamp 				excess -= bp->bio_to->mediasize;
610e39d70d4SPoul-Henning Kamp 				bp->bio_length -= excess;
61149dbb61dSRobert Watson 				if (excess > 0)
61249dbb61dSRobert Watson 					CTR3(KTR_GEOM, "g_down truncated bio "
61349dbb61dSRobert Watson 					    "%p provider %s by %d", bp,
61449dbb61dSRobert Watson 					    bp->bio_to->name, excess);
615e39d70d4SPoul-Henning Kamp 			}
616e39d70d4SPoul-Henning Kamp 			/* Deliver zero length transfers right here. */
617e39d70d4SPoul-Henning Kamp 			if (bp->bio_length == 0) {
618e39d70d4SPoul-Henning Kamp 				g_io_deliver(bp, 0);
61949dbb61dSRobert Watson 				CTR2(KTR_GEOM, "g_down terminated 0-length "
62049dbb61dSRobert Watson 				    "bp %p provider %s", bp, bp->bio_to->name);
621e39d70d4SPoul-Henning Kamp 				continue;
622e39d70d4SPoul-Henning Kamp 			}
623392d56b4SPoul-Henning Kamp 			break;
624392d56b4SPoul-Henning Kamp 		default:
625392d56b4SPoul-Henning Kamp 			break;
626392d56b4SPoul-Henning Kamp 		}
62751460da8SJohn Baldwin 		THREAD_NO_SLEEPING();
62849dbb61dSRobert Watson 		CTR4(KTR_GEOM, "g_down starting bp %p provider %s off %ld "
62949dbb61dSRobert Watson 		    "len %ld", bp, bp->bio_to->name, bp->bio_offset,
63049dbb61dSRobert Watson 		    bp->bio_length);
631dd84a43cSPoul-Henning Kamp 		bp->bio_to->geom->start(bp);
63251460da8SJohn Baldwin 		THREAD_SLEEPING_OK();
633dd84a43cSPoul-Henning Kamp 	}
634dd84a43cSPoul-Henning Kamp }
635dd84a43cSPoul-Henning Kamp 
636dd84a43cSPoul-Henning Kamp void
6375fcf4e43SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg)
6385fcf4e43SPoul-Henning Kamp {
6395fcf4e43SPoul-Henning Kamp 	bp->bio_task = func;
6405fcf4e43SPoul-Henning Kamp 	bp->bio_task_arg = arg;
6415fcf4e43SPoul-Henning Kamp 	/*
6425fcf4e43SPoul-Henning Kamp 	 * The taskqueue is actually just a second queue off the "up"
6435fcf4e43SPoul-Henning Kamp 	 * queue, so we use the same lock.
6445fcf4e43SPoul-Henning Kamp 	 */
6455fcf4e43SPoul-Henning Kamp 	g_bioq_lock(&g_bio_run_up);
646dcbd0fe5SPoul-Henning Kamp 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
647dcbd0fe5SPoul-Henning Kamp 	    ("Bio already on queue bp=%p target taskq", bp));
648dcbd0fe5SPoul-Henning Kamp 	bp->bio_flags |= BIO_ONQUEUE;
6495fcf4e43SPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue);
6505fcf4e43SPoul-Henning Kamp 	g_bio_run_task.bio_queue_length++;
6515fcf4e43SPoul-Henning Kamp 	wakeup(&g_wait_up);
6525fcf4e43SPoul-Henning Kamp 	g_bioq_unlock(&g_bio_run_up);
6535fcf4e43SPoul-Henning Kamp }
6545fcf4e43SPoul-Henning Kamp 
6555fcf4e43SPoul-Henning Kamp 
6565fcf4e43SPoul-Henning Kamp void
657dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused)
658dd84a43cSPoul-Henning Kamp {
659dd84a43cSPoul-Henning Kamp 	struct bio *bp;
660dd84a43cSPoul-Henning Kamp 	for(;;) {
661f0e185d7SPoul-Henning Kamp 		g_bioq_lock(&g_bio_run_up);
6625fcf4e43SPoul-Henning Kamp 		bp = g_bioq_first(&g_bio_run_task);
6635fcf4e43SPoul-Henning Kamp 		if (bp != NULL) {
6645fcf4e43SPoul-Henning Kamp 			g_bioq_unlock(&g_bio_run_up);
66551460da8SJohn Baldwin 			THREAD_NO_SLEEPING();
66649dbb61dSRobert Watson 			CTR1(KTR_GEOM, "g_up processing task bp %p", bp);
6675fcf4e43SPoul-Henning Kamp 			bp->bio_task(bp->bio_task_arg);
66851460da8SJohn Baldwin 			THREAD_SLEEPING_OK();
6695fcf4e43SPoul-Henning Kamp 			continue;
6705fcf4e43SPoul-Henning Kamp 		}
671dd84a43cSPoul-Henning Kamp 		bp = g_bioq_first(&g_bio_run_up);
672f0e185d7SPoul-Henning Kamp 		if (bp != NULL) {
673f0e185d7SPoul-Henning Kamp 			g_bioq_unlock(&g_bio_run_up);
67451460da8SJohn Baldwin 			THREAD_NO_SLEEPING();
67549dbb61dSRobert Watson 			CTR4(KTR_GEOM, "g_up biodone bp %p provider %s off "
676c4901b67SSean Bruno 			    "%jd len %ld", bp, bp->bio_to->name,
67749dbb61dSRobert Watson 			    bp->bio_offset, bp->bio_length);
67853706245SPoul-Henning Kamp 			biodone(bp);
67951460da8SJohn Baldwin 			THREAD_SLEEPING_OK();
680f0e185d7SPoul-Henning Kamp 			continue;
681f0e185d7SPoul-Henning Kamp 		}
68249dbb61dSRobert Watson 		CTR0(KTR_GEOM, "g_up going to sleep");
683f0e185d7SPoul-Henning Kamp 		msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock,
6847fc019afSAlexander Motin 		    PRIBIO | PDROP, "-", 0);
685dd84a43cSPoul-Henning Kamp 	}
686dd84a43cSPoul-Henning Kamp }
687dd84a43cSPoul-Henning Kamp 
688dd84a43cSPoul-Henning Kamp void *
689dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
690dd84a43cSPoul-Henning Kamp {
691dd84a43cSPoul-Henning Kamp 	struct bio *bp;
692dd84a43cSPoul-Henning Kamp 	void *ptr;
693dd84a43cSPoul-Henning Kamp 	int errorc;
694dd84a43cSPoul-Henning Kamp 
6958dd5480dSPawel Jakub Dawidek 	KASSERT(length > 0 && length >= cp->provider->sectorsize &&
6968dd5480dSPawel Jakub Dawidek 	    length <= MAXPHYS, ("g_read_data(): invalid length %jd",
6978dd5480dSPawel Jakub Dawidek 	    (intmax_t)length));
6983eb6ffdfSPoul-Henning Kamp 
699a2033c96SPoul-Henning Kamp 	bp = g_alloc_bio();
700dd84a43cSPoul-Henning Kamp 	bp->bio_cmd = BIO_READ;
701dd84a43cSPoul-Henning Kamp 	bp->bio_done = NULL;
702dd84a43cSPoul-Henning Kamp 	bp->bio_offset = offset;
703dd84a43cSPoul-Henning Kamp 	bp->bio_length = length;
704a163d034SWarner Losh 	ptr = g_malloc(length, M_WAITOK);
705dd84a43cSPoul-Henning Kamp 	bp->bio_data = ptr;
706dd84a43cSPoul-Henning Kamp 	g_io_request(bp, cp);
70753706245SPoul-Henning Kamp 	errorc = biowait(bp, "gread");
708dd84a43cSPoul-Henning Kamp 	if (error != NULL)
709dd84a43cSPoul-Henning Kamp 		*error = errorc;
710dd84a43cSPoul-Henning Kamp 	g_destroy_bio(bp);
711dd84a43cSPoul-Henning Kamp 	if (errorc) {
712dd84a43cSPoul-Henning Kamp 		g_free(ptr);
713dd84a43cSPoul-Henning Kamp 		ptr = NULL;
714dd84a43cSPoul-Henning Kamp 	}
715dd84a43cSPoul-Henning Kamp 	return (ptr);
716dd84a43cSPoul-Henning Kamp }
71790b1cd56SPoul-Henning Kamp 
71890b1cd56SPoul-Henning Kamp int
71990b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length)
72090b1cd56SPoul-Henning Kamp {
72190b1cd56SPoul-Henning Kamp 	struct bio *bp;
72290b1cd56SPoul-Henning Kamp 	int error;
72390b1cd56SPoul-Henning Kamp 
7248dd5480dSPawel Jakub Dawidek 	KASSERT(length > 0 && length >= cp->provider->sectorsize &&
7258dd5480dSPawel Jakub Dawidek 	    length <= MAXPHYS, ("g_write_data(): invalid length %jd",
7268dd5480dSPawel Jakub Dawidek 	    (intmax_t)length));
7273eb6ffdfSPoul-Henning Kamp 
728a2033c96SPoul-Henning Kamp 	bp = g_alloc_bio();
72990b1cd56SPoul-Henning Kamp 	bp->bio_cmd = BIO_WRITE;
73090b1cd56SPoul-Henning Kamp 	bp->bio_done = NULL;
73190b1cd56SPoul-Henning Kamp 	bp->bio_offset = offset;
73290b1cd56SPoul-Henning Kamp 	bp->bio_length = length;
73390b1cd56SPoul-Henning Kamp 	bp->bio_data = ptr;
73490b1cd56SPoul-Henning Kamp 	g_io_request(bp, cp);
73590b1cd56SPoul-Henning Kamp 	error = biowait(bp, "gwrite");
73690b1cd56SPoul-Henning Kamp 	g_destroy_bio(bp);
73790b1cd56SPoul-Henning Kamp 	return (error);
73890b1cd56SPoul-Henning Kamp }
73972e33095SPawel Jakub Dawidek 
7402b17fb95SPawel Jakub Dawidek int
7412b17fb95SPawel Jakub Dawidek g_delete_data(struct g_consumer *cp, off_t offset, off_t length)
7422b17fb95SPawel Jakub Dawidek {
7432b17fb95SPawel Jakub Dawidek 	struct bio *bp;
7442b17fb95SPawel Jakub Dawidek 	int error;
7452b17fb95SPawel Jakub Dawidek 
746eed6cda9SPoul-Henning Kamp 	KASSERT(length > 0 && length >= cp->provider->sectorsize,
747eed6cda9SPoul-Henning Kamp 	    ("g_delete_data(): invalid length %jd", (intmax_t)length));
7482b17fb95SPawel Jakub Dawidek 
7492b17fb95SPawel Jakub Dawidek 	bp = g_alloc_bio();
7502b17fb95SPawel Jakub Dawidek 	bp->bio_cmd = BIO_DELETE;
7512b17fb95SPawel Jakub Dawidek 	bp->bio_done = NULL;
7522b17fb95SPawel Jakub Dawidek 	bp->bio_offset = offset;
7532b17fb95SPawel Jakub Dawidek 	bp->bio_length = length;
7542b17fb95SPawel Jakub Dawidek 	bp->bio_data = NULL;
7552b17fb95SPawel Jakub Dawidek 	g_io_request(bp, cp);
7562b17fb95SPawel Jakub Dawidek 	error = biowait(bp, "gdelete");
7572b17fb95SPawel Jakub Dawidek 	g_destroy_bio(bp);
7582b17fb95SPawel Jakub Dawidek 	return (error);
7592b17fb95SPawel Jakub Dawidek }
7602b17fb95SPawel Jakub Dawidek 
76172e33095SPawel Jakub Dawidek void
76272e33095SPawel Jakub Dawidek g_print_bio(struct bio *bp)
76372e33095SPawel Jakub Dawidek {
76472e33095SPawel Jakub Dawidek 	const char *pname, *cmd = NULL;
76572e33095SPawel Jakub Dawidek 
76672e33095SPawel Jakub Dawidek 	if (bp->bio_to != NULL)
76772e33095SPawel Jakub Dawidek 		pname = bp->bio_to->name;
76872e33095SPawel Jakub Dawidek 	else
76972e33095SPawel Jakub Dawidek 		pname = "[unknown]";
77072e33095SPawel Jakub Dawidek 
77172e33095SPawel Jakub Dawidek 	switch (bp->bio_cmd) {
77272e33095SPawel Jakub Dawidek 	case BIO_GETATTR:
77372e33095SPawel Jakub Dawidek 		cmd = "GETATTR";
77472e33095SPawel Jakub Dawidek 		printf("%s[%s(attr=%s)]", pname, cmd, bp->bio_attribute);
77572e33095SPawel Jakub Dawidek 		return;
776c3618c65SPawel Jakub Dawidek 	case BIO_FLUSH:
777c3618c65SPawel Jakub Dawidek 		cmd = "FLUSH";
778c3618c65SPawel Jakub Dawidek 		printf("%s[%s]", pname, cmd);
779c3618c65SPawel Jakub Dawidek 		return;
78072e33095SPawel Jakub Dawidek 	case BIO_READ:
78172e33095SPawel Jakub Dawidek 		cmd = "READ";
78272e33095SPawel Jakub Dawidek 	case BIO_WRITE:
78372e33095SPawel Jakub Dawidek 		if (cmd == NULL)
78472e33095SPawel Jakub Dawidek 			cmd = "WRITE";
78572e33095SPawel Jakub Dawidek 	case BIO_DELETE:
78672e33095SPawel Jakub Dawidek 		if (cmd == NULL)
78772e33095SPawel Jakub Dawidek 			cmd = "DELETE";
78872e33095SPawel Jakub Dawidek 		printf("%s[%s(offset=%jd, length=%jd)]", pname, cmd,
78972e33095SPawel Jakub Dawidek 		    (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length);
79072e33095SPawel Jakub Dawidek 		return;
79172e33095SPawel Jakub Dawidek 	default:
79272e33095SPawel Jakub Dawidek 		cmd = "UNKNOWN";
79372e33095SPawel Jakub Dawidek 		printf("%s[%s()]", pname, cmd);
79472e33095SPawel Jakub Dawidek 		return;
79572e33095SPawel Jakub Dawidek 	}
79672e33095SPawel Jakub Dawidek 	/* NOTREACHED */
79772e33095SPawel Jakub Dawidek }
798