xref: /freebsd/sys/geom/geom_io.c (revision 6011443800897f4c694d0fb2def5b4ba41adcc4b)
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;
18082a6ae10SJim Harris 		/*
18182a6ae10SJim Harris 		 *  BIO_ORDERED flag may be used by disk drivers to enforce
18282a6ae10SJim Harris 		 *  ordering restrictions, so this flag needs to be cloned.
18382a6ae10SJim Harris 		 *  Other bio flags are not suitable for cloning.
18482a6ae10SJim Harris 		 */
18582a6ae10SJim Harris 		bp2->bio_flags = bp->bio_flags & BIO_ORDERED;
186dd84a43cSPoul-Henning Kamp 		bp2->bio_length = bp->bio_length;
187dd84a43cSPoul-Henning Kamp 		bp2->bio_offset = bp->bio_offset;
188dd84a43cSPoul-Henning Kamp 		bp2->bio_data = bp->bio_data;
189dd84a43cSPoul-Henning Kamp 		bp2->bio_attribute = bp->bio_attribute;
1906231f75bSLuigi Rizzo 		/* Inherit classification info from the parent */
1916231f75bSLuigi Rizzo 		bp2->bio_classifier1 = bp->bio_classifier1;
1926231f75bSLuigi Rizzo 		bp2->bio_classifier2 = bp->bio_classifier2;
193801bb689SPoul-Henning Kamp 		bp->bio_children++;
194a1bd3ee2SPoul-Henning Kamp 	}
1953b378147SPawel Jakub Dawidek #ifdef KTR
196b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
1973b378147SPawel Jakub Dawidek 		struct stack st;
1983b378147SPawel Jakub Dawidek 
199ad572235SRuslan Ermilov 		CTR2(KTR_GEOM, "g_clone_bio(%p): %p", bp, bp2);
2003b378147SPawel Jakub Dawidek 		stack_save(&st);
2013b378147SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
2023b378147SPawel Jakub Dawidek 	}
2033b378147SPawel Jakub Dawidek #endif
204dd84a43cSPoul-Henning Kamp 	return(bp2);
205dd84a43cSPoul-Henning Kamp }
206dd84a43cSPoul-Henning Kamp 
2074bec0ff1SPawel Jakub Dawidek struct bio *
2084bec0ff1SPawel Jakub Dawidek g_duplicate_bio(struct bio *bp)
2094bec0ff1SPawel Jakub Dawidek {
2104bec0ff1SPawel Jakub Dawidek 	struct bio *bp2;
2114bec0ff1SPawel Jakub Dawidek 
2124bec0ff1SPawel Jakub Dawidek 	bp2 = uma_zalloc(biozone, M_WAITOK | M_ZERO);
2134bec0ff1SPawel Jakub Dawidek 	bp2->bio_parent = bp;
2144bec0ff1SPawel Jakub Dawidek 	bp2->bio_cmd = bp->bio_cmd;
2154bec0ff1SPawel Jakub Dawidek 	bp2->bio_length = bp->bio_length;
2164bec0ff1SPawel Jakub Dawidek 	bp2->bio_offset = bp->bio_offset;
2174bec0ff1SPawel Jakub Dawidek 	bp2->bio_data = bp->bio_data;
2184bec0ff1SPawel Jakub Dawidek 	bp2->bio_attribute = bp->bio_attribute;
2194bec0ff1SPawel Jakub Dawidek 	bp->bio_children++;
2204bec0ff1SPawel Jakub Dawidek #ifdef KTR
221b656c1b8SPawel Jakub Dawidek 	if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) {
2224bec0ff1SPawel Jakub Dawidek 		struct stack st;
2234bec0ff1SPawel Jakub Dawidek 
2244bec0ff1SPawel Jakub Dawidek 		CTR2(KTR_GEOM, "g_duplicate_bio(%p): %p", bp, bp2);
2254bec0ff1SPawel Jakub Dawidek 		stack_save(&st);
2264bec0ff1SPawel Jakub Dawidek 		CTRSTACK(KTR_GEOM, &st, 3, 0);
2274bec0ff1SPawel Jakub Dawidek 	}
2284bec0ff1SPawel Jakub Dawidek #endif
2294bec0ff1SPawel Jakub Dawidek 	return(bp2);
2304bec0ff1SPawel Jakub Dawidek }
2314bec0ff1SPawel Jakub Dawidek 
232dd84a43cSPoul-Henning Kamp void
233dd84a43cSPoul-Henning Kamp g_io_init()
234dd84a43cSPoul-Henning Kamp {
235dd84a43cSPoul-Henning Kamp 
236dd84a43cSPoul-Henning Kamp 	g_bioq_init(&g_bio_run_down);
237dd84a43cSPoul-Henning Kamp 	g_bioq_init(&g_bio_run_up);
2385fcf4e43SPoul-Henning Kamp 	g_bioq_init(&g_bio_run_task);
2395ffb2c8bSPoul-Henning Kamp 	biozone = uma_zcreate("g_bio", sizeof (struct bio),
2405ffb2c8bSPoul-Henning Kamp 	    NULL, NULL,
2415ffb2c8bSPoul-Henning Kamp 	    NULL, NULL,
2425ffb2c8bSPoul-Henning Kamp 	    0, 0);
243dd84a43cSPoul-Henning Kamp }
244dd84a43cSPoul-Henning Kamp 
245dd84a43cSPoul-Henning Kamp int
2460d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr)
247dd84a43cSPoul-Henning Kamp {
248dd84a43cSPoul-Henning Kamp 	struct bio *bp;
249dd84a43cSPoul-Henning Kamp 	int error;
250dd84a43cSPoul-Henning Kamp 
251dd84a43cSPoul-Henning Kamp 	g_trace(G_T_BIO, "bio_getattr(%s)", attr);
252a2033c96SPoul-Henning Kamp 	bp = g_alloc_bio();
253dd84a43cSPoul-Henning Kamp 	bp->bio_cmd = BIO_GETATTR;
254dd84a43cSPoul-Henning Kamp 	bp->bio_done = NULL;
255dd84a43cSPoul-Henning Kamp 	bp->bio_attribute = attr;
256dd84a43cSPoul-Henning Kamp 	bp->bio_length = *len;
257dd84a43cSPoul-Henning Kamp 	bp->bio_data = ptr;
258dd84a43cSPoul-Henning Kamp 	g_io_request(bp, cp);
25953706245SPoul-Henning Kamp 	error = biowait(bp, "ggetattr");
260dd84a43cSPoul-Henning Kamp 	*len = bp->bio_completed;
261dd84a43cSPoul-Henning Kamp 	g_destroy_bio(bp);
262dd84a43cSPoul-Henning Kamp 	return (error);
263dd84a43cSPoul-Henning Kamp }
264dd84a43cSPoul-Henning Kamp 
265c3618c65SPawel Jakub Dawidek int
266c3618c65SPawel Jakub Dawidek g_io_flush(struct g_consumer *cp)
267c3618c65SPawel Jakub Dawidek {
268c3618c65SPawel Jakub Dawidek 	struct bio *bp;
269c3618c65SPawel Jakub Dawidek 	int error;
270c3618c65SPawel Jakub Dawidek 
271c3618c65SPawel Jakub Dawidek 	g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name);
272c3618c65SPawel Jakub Dawidek 	bp = g_alloc_bio();
273c3618c65SPawel Jakub Dawidek 	bp->bio_cmd = BIO_FLUSH;
274f03f7a0cSJustin T. Gibbs 	bp->bio_flags |= BIO_ORDERED;
275c3618c65SPawel Jakub Dawidek 	bp->bio_done = NULL;
276c3618c65SPawel Jakub Dawidek 	bp->bio_attribute = NULL;
277c3618c65SPawel Jakub Dawidek 	bp->bio_offset = cp->provider->mediasize;
278c3618c65SPawel Jakub Dawidek 	bp->bio_length = 0;
279c3618c65SPawel Jakub Dawidek 	bp->bio_data = NULL;
280c3618c65SPawel Jakub Dawidek 	g_io_request(bp, cp);
281c3618c65SPawel Jakub Dawidek 	error = biowait(bp, "gflush");
282c3618c65SPawel Jakub Dawidek 	g_destroy_bio(bp);
283c3618c65SPawel Jakub Dawidek 	return (error);
284c3618c65SPawel Jakub Dawidek }
285c3618c65SPawel Jakub Dawidek 
286e39d70d4SPoul-Henning Kamp static int
287e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp)
288e39d70d4SPoul-Henning Kamp {
289e39d70d4SPoul-Henning Kamp 	struct g_consumer *cp;
290e39d70d4SPoul-Henning Kamp 	struct g_provider *pp;
291e39d70d4SPoul-Henning Kamp 
292e39d70d4SPoul-Henning Kamp 	cp = bp->bio_from;
293e39d70d4SPoul-Henning Kamp 	pp = bp->bio_to;
294e39d70d4SPoul-Henning Kamp 
295e39d70d4SPoul-Henning Kamp 	/* Fail if access counters dont allow the operation */
296e39d70d4SPoul-Henning Kamp 	switch(bp->bio_cmd) {
297e39d70d4SPoul-Henning Kamp 	case BIO_READ:
298e39d70d4SPoul-Henning Kamp 	case BIO_GETATTR:
299e39d70d4SPoul-Henning Kamp 		if (cp->acr == 0)
300e39d70d4SPoul-Henning Kamp 			return (EPERM);
301e39d70d4SPoul-Henning Kamp 		break;
302e39d70d4SPoul-Henning Kamp 	case BIO_WRITE:
303e39d70d4SPoul-Henning Kamp 	case BIO_DELETE:
304c3618c65SPawel Jakub Dawidek 	case BIO_FLUSH:
305e39d70d4SPoul-Henning Kamp 		if (cp->acw == 0)
306e39d70d4SPoul-Henning Kamp 			return (EPERM);
307e39d70d4SPoul-Henning Kamp 		break;
308e39d70d4SPoul-Henning Kamp 	default:
309e39d70d4SPoul-Henning Kamp 		return (EPERM);
310e39d70d4SPoul-Henning Kamp 	}
311e39d70d4SPoul-Henning Kamp 	/* if provider is marked for error, don't disturb. */
312e39d70d4SPoul-Henning Kamp 	if (pp->error)
313e39d70d4SPoul-Henning Kamp 		return (pp->error);
3143631c638SAlexander Motin 	if (cp->flags & G_CF_ORPHAN)
3153631c638SAlexander Motin 		return (ENXIO);
316e39d70d4SPoul-Henning Kamp 
317e39d70d4SPoul-Henning Kamp 	switch(bp->bio_cmd) {
318e39d70d4SPoul-Henning Kamp 	case BIO_READ:
319e39d70d4SPoul-Henning Kamp 	case BIO_WRITE:
320e39d70d4SPoul-Henning Kamp 	case BIO_DELETE:
3212a842317SAndriy Gapon 		/* Zero sectorsize or mediasize is probably a lack of media. */
3222a842317SAndriy Gapon 		if (pp->sectorsize == 0 || pp->mediasize == 0)
32343bff1a7SPoul-Henning Kamp 			return (ENXIO);
324e39d70d4SPoul-Henning Kamp 		/* Reject I/O not on sector boundary */
325e39d70d4SPoul-Henning Kamp 		if (bp->bio_offset % pp->sectorsize)
326e39d70d4SPoul-Henning Kamp 			return (EINVAL);
327e39d70d4SPoul-Henning Kamp 		/* Reject I/O not integral sector long */
328e39d70d4SPoul-Henning Kamp 		if (bp->bio_length % pp->sectorsize)
329e39d70d4SPoul-Henning Kamp 			return (EINVAL);
330d1b8bf47SPoul-Henning Kamp 		/* Reject requests before or past the end of media. */
331d1b8bf47SPoul-Henning Kamp 		if (bp->bio_offset < 0)
332d1b8bf47SPoul-Henning Kamp 			return (EIO);
333e39d70d4SPoul-Henning Kamp 		if (bp->bio_offset > pp->mediasize)
334e39d70d4SPoul-Henning Kamp 			return (EIO);
335e39d70d4SPoul-Henning Kamp 		break;
336e39d70d4SPoul-Henning Kamp 	default:
337e39d70d4SPoul-Henning Kamp 		break;
338e39d70d4SPoul-Henning Kamp 	}
339e39d70d4SPoul-Henning Kamp 	return (0);
340e39d70d4SPoul-Henning Kamp }
341e39d70d4SPoul-Henning Kamp 
3426231f75bSLuigi Rizzo /*
3436231f75bSLuigi Rizzo  * bio classification support.
3446231f75bSLuigi Rizzo  *
3456231f75bSLuigi Rizzo  * g_register_classifier() and g_unregister_classifier()
3466231f75bSLuigi Rizzo  * are used to add/remove a classifier from the list.
3476231f75bSLuigi Rizzo  * The list is protected using the g_bio_run_down lock,
3486231f75bSLuigi Rizzo  * because the classifiers are called in this path.
3496231f75bSLuigi Rizzo  *
3506231f75bSLuigi Rizzo  * g_io_request() passes bio's that are not already classified
3516231f75bSLuigi Rizzo  * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers().
3526231f75bSLuigi Rizzo  * Classifiers can store their result in the two fields
3536231f75bSLuigi Rizzo  * bio_classifier1 and bio_classifier2.
3546231f75bSLuigi Rizzo  * A classifier that updates one of the fields should
3556231f75bSLuigi Rizzo  * return a non-zero value.
3566231f75bSLuigi Rizzo  * If no classifier updates the field, g_run_classifiers() sets
3576231f75bSLuigi Rizzo  * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls.
3586231f75bSLuigi Rizzo  */
3596231f75bSLuigi Rizzo 
3606231f75bSLuigi Rizzo int
3616231f75bSLuigi Rizzo g_register_classifier(struct g_classifier_hook *hook)
3626231f75bSLuigi Rizzo {
3636231f75bSLuigi Rizzo 
3646231f75bSLuigi Rizzo 	g_bioq_lock(&g_bio_run_down);
3656231f75bSLuigi Rizzo 	TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link);
3666231f75bSLuigi Rizzo 	g_bioq_unlock(&g_bio_run_down);
3676231f75bSLuigi Rizzo 
3686231f75bSLuigi Rizzo 	return (0);
3696231f75bSLuigi Rizzo }
3706231f75bSLuigi Rizzo 
3716231f75bSLuigi Rizzo void
3726231f75bSLuigi Rizzo g_unregister_classifier(struct g_classifier_hook *hook)
3736231f75bSLuigi Rizzo {
3746231f75bSLuigi Rizzo 	struct g_classifier_hook *entry;
3756231f75bSLuigi Rizzo 
3766231f75bSLuigi Rizzo 	g_bioq_lock(&g_bio_run_down);
3776231f75bSLuigi Rizzo 	TAILQ_FOREACH(entry, &g_classifier_tailq, link) {
3786231f75bSLuigi Rizzo 		if (entry == hook) {
3796231f75bSLuigi Rizzo 			TAILQ_REMOVE(&g_classifier_tailq, hook, link);
3806231f75bSLuigi Rizzo 			break;
3816231f75bSLuigi Rizzo 		}
3826231f75bSLuigi Rizzo 	}
3836231f75bSLuigi Rizzo 	g_bioq_unlock(&g_bio_run_down);
3846231f75bSLuigi Rizzo }
3856231f75bSLuigi Rizzo 
3866231f75bSLuigi Rizzo static void
3876231f75bSLuigi Rizzo g_run_classifiers(struct bio *bp)
3886231f75bSLuigi Rizzo {
3896231f75bSLuigi Rizzo 	struct g_classifier_hook *hook;
3906231f75bSLuigi Rizzo 	int classified = 0;
3916231f75bSLuigi Rizzo 
3926231f75bSLuigi Rizzo 	TAILQ_FOREACH(hook, &g_classifier_tailq, link)
3936231f75bSLuigi Rizzo 		classified |= hook->func(hook->arg, bp);
3946231f75bSLuigi Rizzo 
3956231f75bSLuigi Rizzo 	if (!classified)
3966231f75bSLuigi Rizzo 		bp->bio_classifier1 = BIO_NOTCLASSIFIED;
3976231f75bSLuigi Rizzo }
3986231f75bSLuigi Rizzo 
399dd84a43cSPoul-Henning Kamp void
400dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp)
401dd84a43cSPoul-Henning Kamp {
402801bb689SPoul-Henning Kamp 	struct g_provider *pp;
4030d883b11SAlexander Motin 	int first;
404dd84a43cSPoul-Henning Kamp 
405d0e17c1bSPoul-Henning Kamp 	KASSERT(cp != NULL, ("NULL cp in g_io_request"));
406d0e17c1bSPoul-Henning Kamp 	KASSERT(bp != NULL, ("NULL bp in g_io_request"));
407e060b6bdSPoul-Henning Kamp 	pp = cp->provider;
408801bb689SPoul-Henning Kamp 	KASSERT(pp != NULL, ("consumer not attached in g_io_request"));
40992ee312dSPawel Jakub Dawidek #ifdef DIAGNOSTIC
41092ee312dSPawel Jakub Dawidek 	KASSERT(bp->bio_driver1 == NULL,
41192ee312dSPawel Jakub Dawidek 	    ("bio_driver1 used by the consumer (geom %s)", cp->geom->name));
41292ee312dSPawel Jakub Dawidek 	KASSERT(bp->bio_driver2 == NULL,
41392ee312dSPawel Jakub Dawidek 	    ("bio_driver2 used by the consumer (geom %s)", cp->geom->name));
41492ee312dSPawel Jakub Dawidek 	KASSERT(bp->bio_pflags == 0,
41592ee312dSPawel Jakub Dawidek 	    ("bio_pflags used by the consumer (geom %s)", cp->geom->name));
41692ee312dSPawel Jakub Dawidek 	/*
41792ee312dSPawel Jakub Dawidek 	 * Remember consumer's private fields, so we can detect if they were
41892ee312dSPawel Jakub Dawidek 	 * modified by the provider.
41992ee312dSPawel Jakub Dawidek 	 */
42092ee312dSPawel Jakub Dawidek 	bp->_bio_caller1 = bp->bio_caller1;
42192ee312dSPawel Jakub Dawidek 	bp->_bio_caller2 = bp->bio_caller2;
42292ee312dSPawel Jakub Dawidek 	bp->_bio_cflags = bp->bio_cflags;
42392ee312dSPawel Jakub Dawidek #endif
424801bb689SPoul-Henning Kamp 
4251ded77b2SPawel Jakub Dawidek 	if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) {
426c3618c65SPawel Jakub Dawidek 		KASSERT(bp->bio_data != NULL,
4271ded77b2SPawel Jakub Dawidek 		    ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd));
4281ded77b2SPawel Jakub Dawidek 	}
4291ded77b2SPawel Jakub Dawidek 	if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) {
4301ded77b2SPawel Jakub Dawidek 		KASSERT(bp->bio_data == NULL,
4311ded77b2SPawel Jakub Dawidek 		    ("non-NULL bp->data in g_io_request(cmd=%hhu)",
4321ded77b2SPawel Jakub Dawidek 		    bp->bio_cmd));
433c3618c65SPawel Jakub Dawidek 	}
434dcbd0fe5SPoul-Henning Kamp 	if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) {
435dcbd0fe5SPoul-Henning Kamp 		KASSERT(bp->bio_offset % cp->provider->sectorsize == 0,
436dcbd0fe5SPoul-Henning Kamp 		    ("wrong offset %jd for sectorsize %u",
437dcbd0fe5SPoul-Henning Kamp 		    bp->bio_offset, cp->provider->sectorsize));
438dcbd0fe5SPoul-Henning Kamp 		KASSERT(bp->bio_length % cp->provider->sectorsize == 0,
439dcbd0fe5SPoul-Henning Kamp 		    ("wrong length %jd for sectorsize %u",
440dcbd0fe5SPoul-Henning Kamp 		    bp->bio_length, cp->provider->sectorsize));
441dcbd0fe5SPoul-Henning Kamp 	}
442dcbd0fe5SPoul-Henning Kamp 
443f7717523SStephan Uphoff 	g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d",
444f7717523SStephan Uphoff 	    bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd);
445f7717523SStephan Uphoff 
446dd84a43cSPoul-Henning Kamp 	bp->bio_from = cp;
447801bb689SPoul-Henning Kamp 	bp->bio_to = pp;
4482fccec19SPoul-Henning Kamp 	bp->bio_error = 0;
4492fccec19SPoul-Henning Kamp 	bp->bio_completed = 0;
450dd84a43cSPoul-Henning Kamp 
45119fa21aaSPoul-Henning Kamp 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
45219fa21aaSPoul-Henning Kamp 	    ("Bio already on queue bp=%p", bp));
45319fa21aaSPoul-Henning Kamp 	bp->bio_flags |= BIO_ONQUEUE;
45419fa21aaSPoul-Henning Kamp 
455a5be8eb5SAlexander Motin 	if (g_collectstats)
45619fa21aaSPoul-Henning Kamp 		binuptime(&bp->bio_t0);
457a5be8eb5SAlexander Motin 	else
458a5be8eb5SAlexander Motin 		getbinuptime(&bp->bio_t0);
4598827c821SPoul-Henning Kamp 
4608827c821SPoul-Henning Kamp 	/*
4618827c821SPoul-Henning Kamp 	 * The statistics collection is lockless, as such, but we
4628827c821SPoul-Henning Kamp 	 * can not update one instance of the statistics from more
4638827c821SPoul-Henning Kamp 	 * than one thread at a time, so grab the lock first.
4646231f75bSLuigi Rizzo 	 *
4656231f75bSLuigi Rizzo 	 * We also use the lock to protect the list of classifiers.
4668827c821SPoul-Henning Kamp 	 */
46719fa21aaSPoul-Henning Kamp 	g_bioq_lock(&g_bio_run_down);
4686231f75bSLuigi Rizzo 
4696231f75bSLuigi Rizzo 	if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1)
4706231f75bSLuigi Rizzo 		g_run_classifiers(bp);
4716231f75bSLuigi Rizzo 
472cf457284SPoul-Henning Kamp 	if (g_collectstats & 1)
47319fa21aaSPoul-Henning Kamp 		devstat_start_transaction(pp->stat, &bp->bio_t0);
474cf457284SPoul-Henning Kamp 	if (g_collectstats & 2)
47519fa21aaSPoul-Henning Kamp 		devstat_start_transaction(cp->stat, &bp->bio_t0);
47619fa21aaSPoul-Henning Kamp 
47719fa21aaSPoul-Henning Kamp 	pp->nstart++;
478cf457284SPoul-Henning Kamp 	cp->nstart++;
4790d883b11SAlexander Motin 	first = TAILQ_EMPTY(&g_bio_run_down.bio_queue);
48019fa21aaSPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&g_bio_run_down.bio_queue, bp, bio_queue);
48119fa21aaSPoul-Henning Kamp 	g_bio_run_down.bio_queue_length++;
48219fa21aaSPoul-Henning Kamp 	g_bioq_unlock(&g_bio_run_down);
483e39d70d4SPoul-Henning Kamp 
4842fccec19SPoul-Henning Kamp 	/* Pass it on down. */
4850d883b11SAlexander Motin 	if (first)
486dd84a43cSPoul-Henning Kamp 		wakeup(&g_wait_down);
487dd84a43cSPoul-Henning Kamp }
488dd84a43cSPoul-Henning Kamp 
489dd84a43cSPoul-Henning Kamp void
49072840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error)
491dd84a43cSPoul-Henning Kamp {
492801bb689SPoul-Henning Kamp 	struct g_consumer *cp;
493801bb689SPoul-Henning Kamp 	struct g_provider *pp;
4940d883b11SAlexander Motin 	int first;
495dd84a43cSPoul-Henning Kamp 
496e060b6bdSPoul-Henning Kamp 	KASSERT(bp != NULL, ("NULL bp in g_io_deliver"));
497801bb689SPoul-Henning Kamp 	pp = bp->bio_to;
498f7eeab17SPoul-Henning Kamp 	KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver"));
499f7eeab17SPoul-Henning Kamp 	cp = bp->bio_from;
500f7eeab17SPoul-Henning Kamp 	if (cp == NULL) {
501f7eeab17SPoul-Henning Kamp 		bp->bio_error = error;
502f7eeab17SPoul-Henning Kamp 		bp->bio_done(bp);
503f7eeab17SPoul-Henning Kamp 		return;
504f7eeab17SPoul-Henning Kamp 	}
505801bb689SPoul-Henning Kamp 	KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver"));
506801bb689SPoul-Henning Kamp 	KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver"));
507fb231f36SEdward Tomasz Napierala #ifdef DIAGNOSTIC
508fb231f36SEdward Tomasz Napierala 	/*
509fb231f36SEdward Tomasz Napierala 	 * Some classes - GJournal in particular - can modify bio's
510fb231f36SEdward Tomasz Napierala 	 * private fields while the bio is in transit; G_GEOM_VOLATILE_BIO
511fb231f36SEdward Tomasz Napierala 	 * flag means it's an expected behaviour for that particular geom.
512fb231f36SEdward Tomasz Napierala 	 */
513fb231f36SEdward Tomasz Napierala 	if ((cp->geom->flags & G_GEOM_VOLATILE_BIO) == 0) {
514fb231f36SEdward Tomasz Napierala 		KASSERT(bp->bio_caller1 == bp->_bio_caller1,
515fb231f36SEdward Tomasz Napierala 		    ("bio_caller1 used by the provider %s", pp->name));
516fb231f36SEdward Tomasz Napierala 		KASSERT(bp->bio_caller2 == bp->_bio_caller2,
517fb231f36SEdward Tomasz Napierala 		    ("bio_caller2 used by the provider %s", pp->name));
518fb231f36SEdward Tomasz Napierala 		KASSERT(bp->bio_cflags == bp->_bio_cflags,
519fb231f36SEdward Tomasz Napierala 		    ("bio_cflags used by the provider %s", pp->name));
520fb231f36SEdward Tomasz Napierala 	}
521fb231f36SEdward Tomasz Napierala #endif
52246aeebecSPawel Jakub Dawidek 	KASSERT(bp->bio_completed >= 0, ("bio_completed can't be less than 0"));
52346aeebecSPawel Jakub Dawidek 	KASSERT(bp->bio_completed <= bp->bio_length,
52446aeebecSPawel Jakub Dawidek 	    ("bio_completed can't be greater than bio_length"));
5255ab413bfSPoul-Henning Kamp 
526dd84a43cSPoul-Henning Kamp 	g_trace(G_T_BIO,
5270355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd",
528801bb689SPoul-Henning Kamp 	    bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error,
5290355b86eSPoul-Henning Kamp 	    (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length);
530801bb689SPoul-Henning Kamp 
53119fa21aaSPoul-Henning Kamp 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
53219fa21aaSPoul-Henning Kamp 	    ("Bio already on queue bp=%p", bp));
53319fa21aaSPoul-Henning Kamp 
534dcbd0fe5SPoul-Henning Kamp 	/*
535dcbd0fe5SPoul-Henning Kamp 	 * XXX: next two doesn't belong here
536dcbd0fe5SPoul-Henning Kamp 	 */
537e24cbd90SPoul-Henning Kamp 	bp->bio_bcount = bp->bio_length;
538e24cbd90SPoul-Henning Kamp 	bp->bio_resid = bp->bio_bcount - bp->bio_completed;
53919fa21aaSPoul-Henning Kamp 
5408827c821SPoul-Henning Kamp 	/*
5418827c821SPoul-Henning Kamp 	 * The statistics collection is lockless, as such, but we
5428827c821SPoul-Henning Kamp 	 * can not update one instance of the statistics from more
5438827c821SPoul-Henning Kamp 	 * than one thread at a time, so grab the lock first.
5448827c821SPoul-Henning Kamp 	 */
54519fa21aaSPoul-Henning Kamp 	g_bioq_lock(&g_bio_run_up);
546cf457284SPoul-Henning Kamp 	if (g_collectstats & 1)
547e24cbd90SPoul-Henning Kamp 		devstat_end_transaction_bio(pp->stat, bp);
548cf457284SPoul-Henning Kamp 	if (g_collectstats & 2)
549cf457284SPoul-Henning Kamp 		devstat_end_transaction_bio(cp->stat, bp);
5508827c821SPoul-Henning Kamp 
551c6ae9b5fSPoul-Henning Kamp 	cp->nend++;
552c6ae9b5fSPoul-Henning Kamp 	pp->nend++;
55319fa21aaSPoul-Henning Kamp 	if (error != ENOMEM) {
55419fa21aaSPoul-Henning Kamp 		bp->bio_error = error;
5550d883b11SAlexander Motin 		first = TAILQ_EMPTY(&g_bio_run_up.bio_queue);
55619fa21aaSPoul-Henning Kamp 		TAILQ_INSERT_TAIL(&g_bio_run_up.bio_queue, bp, bio_queue);
557276f72c5SPoul-Henning Kamp 		bp->bio_flags |= BIO_ONQUEUE;
55819fa21aaSPoul-Henning Kamp 		g_bio_run_up.bio_queue_length++;
55919fa21aaSPoul-Henning Kamp 		g_bioq_unlock(&g_bio_run_up);
5600d883b11SAlexander Motin 		if (first)
56119fa21aaSPoul-Henning Kamp 			wakeup(&g_wait_up);
56219fa21aaSPoul-Henning Kamp 		return;
56319fa21aaSPoul-Henning Kamp 	}
56419fa21aaSPoul-Henning Kamp 	g_bioq_unlock(&g_bio_run_up);
565dd84a43cSPoul-Henning Kamp 
5662cc9686eSPoul-Henning Kamp 	if (bootverbose)
567801bb689SPoul-Henning Kamp 		printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name);
5681b949c05SPawel Jakub Dawidek 	bp->bio_children = 0;
5691b949c05SPawel Jakub Dawidek 	bp->bio_inbed = 0;
570*60114438SPawel Jakub Dawidek 	bp->bio_driver1 = NULL;
571*60114438SPawel Jakub Dawidek 	bp->bio_driver2 = NULL;
572*60114438SPawel Jakub Dawidek 	bp->bio_pflags = 0;
573801bb689SPoul-Henning Kamp 	g_io_request(bp, cp);
5743432e4fdSPoul-Henning Kamp 	pace++;
5753432e4fdSPoul-Henning Kamp 	return;
5763432e4fdSPoul-Henning Kamp }
577dd84a43cSPoul-Henning Kamp 
578dd84a43cSPoul-Henning Kamp void
579dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused)
580dd84a43cSPoul-Henning Kamp {
581dd84a43cSPoul-Henning Kamp 	struct bio *bp;
582e39d70d4SPoul-Henning Kamp 	off_t excess;
583e39d70d4SPoul-Henning Kamp 	int error;
584dd84a43cSPoul-Henning Kamp 
585dd84a43cSPoul-Henning Kamp 	for(;;) {
586f0e185d7SPoul-Henning Kamp 		g_bioq_lock(&g_bio_run_down);
587dd84a43cSPoul-Henning Kamp 		bp = g_bioq_first(&g_bio_run_down);
588f0e185d7SPoul-Henning Kamp 		if (bp == NULL) {
58949dbb61dSRobert Watson 			CTR0(KTR_GEOM, "g_down going to sleep");
590f0e185d7SPoul-Henning Kamp 			msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock,
5917fc019afSAlexander Motin 			    PRIBIO | PDROP, "-", 0);
592f0e185d7SPoul-Henning Kamp 			continue;
593f0e185d7SPoul-Henning Kamp 		}
59449dbb61dSRobert Watson 		CTR0(KTR_GEOM, "g_down has work to do");
595f0e185d7SPoul-Henning Kamp 		g_bioq_unlock(&g_bio_run_down);
596376ceb79SPoul-Henning Kamp 		if (pace > 0) {
59749dbb61dSRobert Watson 			CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace);
5984d70511aSJohn Baldwin 			pause("g_down", hz/10);
599376ceb79SPoul-Henning Kamp 			pace--;
600376ceb79SPoul-Henning Kamp 		}
601e39d70d4SPoul-Henning Kamp 		error = g_io_check(bp);
602e39d70d4SPoul-Henning Kamp 		if (error) {
60349dbb61dSRobert Watson 			CTR3(KTR_GEOM, "g_down g_io_check on bp %p provider "
60449dbb61dSRobert Watson 			    "%s returned %d", bp, bp->bio_to->name, error);
605e39d70d4SPoul-Henning Kamp 			g_io_deliver(bp, error);
606e39d70d4SPoul-Henning Kamp 			continue;
607e39d70d4SPoul-Henning Kamp 		}
60849dbb61dSRobert Watson 		CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp,
60949dbb61dSRobert Watson 		    bp->bio_to->name);
610392d56b4SPoul-Henning Kamp 		switch (bp->bio_cmd) {
611392d56b4SPoul-Henning Kamp 		case BIO_READ:
612392d56b4SPoul-Henning Kamp 		case BIO_WRITE:
613392d56b4SPoul-Henning Kamp 		case BIO_DELETE:
614e39d70d4SPoul-Henning Kamp 			/* Truncate requests to the end of providers media. */
61549dbb61dSRobert Watson 			/*
61649dbb61dSRobert Watson 			 * XXX: What if we truncate because of offset being
61749dbb61dSRobert Watson 			 * bad, not length?
61849dbb61dSRobert Watson 			 */
619e39d70d4SPoul-Henning Kamp 			excess = bp->bio_offset + bp->bio_length;
620e39d70d4SPoul-Henning Kamp 			if (excess > bp->bio_to->mediasize) {
621e39d70d4SPoul-Henning Kamp 				excess -= bp->bio_to->mediasize;
622e39d70d4SPoul-Henning Kamp 				bp->bio_length -= excess;
62349dbb61dSRobert Watson 				if (excess > 0)
62449dbb61dSRobert Watson 					CTR3(KTR_GEOM, "g_down truncated bio "
62549dbb61dSRobert Watson 					    "%p provider %s by %d", bp,
62649dbb61dSRobert Watson 					    bp->bio_to->name, excess);
627e39d70d4SPoul-Henning Kamp 			}
628e39d70d4SPoul-Henning Kamp 			/* Deliver zero length transfers right here. */
629e39d70d4SPoul-Henning Kamp 			if (bp->bio_length == 0) {
630e39d70d4SPoul-Henning Kamp 				g_io_deliver(bp, 0);
63149dbb61dSRobert Watson 				CTR2(KTR_GEOM, "g_down terminated 0-length "
63249dbb61dSRobert Watson 				    "bp %p provider %s", bp, bp->bio_to->name);
633e39d70d4SPoul-Henning Kamp 				continue;
634e39d70d4SPoul-Henning Kamp 			}
635392d56b4SPoul-Henning Kamp 			break;
636392d56b4SPoul-Henning Kamp 		default:
637392d56b4SPoul-Henning Kamp 			break;
638392d56b4SPoul-Henning Kamp 		}
63951460da8SJohn Baldwin 		THREAD_NO_SLEEPING();
64049dbb61dSRobert Watson 		CTR4(KTR_GEOM, "g_down starting bp %p provider %s off %ld "
64149dbb61dSRobert Watson 		    "len %ld", bp, bp->bio_to->name, bp->bio_offset,
64249dbb61dSRobert Watson 		    bp->bio_length);
643dd84a43cSPoul-Henning Kamp 		bp->bio_to->geom->start(bp);
64451460da8SJohn Baldwin 		THREAD_SLEEPING_OK();
645dd84a43cSPoul-Henning Kamp 	}
646dd84a43cSPoul-Henning Kamp }
647dd84a43cSPoul-Henning Kamp 
648dd84a43cSPoul-Henning Kamp void
6495fcf4e43SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg)
6505fcf4e43SPoul-Henning Kamp {
6515fcf4e43SPoul-Henning Kamp 	bp->bio_task = func;
6525fcf4e43SPoul-Henning Kamp 	bp->bio_task_arg = arg;
6535fcf4e43SPoul-Henning Kamp 	/*
6545fcf4e43SPoul-Henning Kamp 	 * The taskqueue is actually just a second queue off the "up"
6555fcf4e43SPoul-Henning Kamp 	 * queue, so we use the same lock.
6565fcf4e43SPoul-Henning Kamp 	 */
6575fcf4e43SPoul-Henning Kamp 	g_bioq_lock(&g_bio_run_up);
658dcbd0fe5SPoul-Henning Kamp 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
659dcbd0fe5SPoul-Henning Kamp 	    ("Bio already on queue bp=%p target taskq", bp));
660dcbd0fe5SPoul-Henning Kamp 	bp->bio_flags |= BIO_ONQUEUE;
6615fcf4e43SPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue);
6625fcf4e43SPoul-Henning Kamp 	g_bio_run_task.bio_queue_length++;
6635fcf4e43SPoul-Henning Kamp 	wakeup(&g_wait_up);
6645fcf4e43SPoul-Henning Kamp 	g_bioq_unlock(&g_bio_run_up);
6655fcf4e43SPoul-Henning Kamp }
6665fcf4e43SPoul-Henning Kamp 
6675fcf4e43SPoul-Henning Kamp 
6685fcf4e43SPoul-Henning Kamp void
669dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused)
670dd84a43cSPoul-Henning Kamp {
671dd84a43cSPoul-Henning Kamp 	struct bio *bp;
672dd84a43cSPoul-Henning Kamp 	for(;;) {
673f0e185d7SPoul-Henning Kamp 		g_bioq_lock(&g_bio_run_up);
6745fcf4e43SPoul-Henning Kamp 		bp = g_bioq_first(&g_bio_run_task);
6755fcf4e43SPoul-Henning Kamp 		if (bp != NULL) {
6765fcf4e43SPoul-Henning Kamp 			g_bioq_unlock(&g_bio_run_up);
67751460da8SJohn Baldwin 			THREAD_NO_SLEEPING();
67849dbb61dSRobert Watson 			CTR1(KTR_GEOM, "g_up processing task bp %p", bp);
6795fcf4e43SPoul-Henning Kamp 			bp->bio_task(bp->bio_task_arg);
68051460da8SJohn Baldwin 			THREAD_SLEEPING_OK();
6815fcf4e43SPoul-Henning Kamp 			continue;
6825fcf4e43SPoul-Henning Kamp 		}
683dd84a43cSPoul-Henning Kamp 		bp = g_bioq_first(&g_bio_run_up);
684f0e185d7SPoul-Henning Kamp 		if (bp != NULL) {
685f0e185d7SPoul-Henning Kamp 			g_bioq_unlock(&g_bio_run_up);
68651460da8SJohn Baldwin 			THREAD_NO_SLEEPING();
68749dbb61dSRobert Watson 			CTR4(KTR_GEOM, "g_up biodone bp %p provider %s off "
688c4901b67SSean Bruno 			    "%jd len %ld", bp, bp->bio_to->name,
68949dbb61dSRobert Watson 			    bp->bio_offset, bp->bio_length);
69053706245SPoul-Henning Kamp 			biodone(bp);
69151460da8SJohn Baldwin 			THREAD_SLEEPING_OK();
692f0e185d7SPoul-Henning Kamp 			continue;
693f0e185d7SPoul-Henning Kamp 		}
69449dbb61dSRobert Watson 		CTR0(KTR_GEOM, "g_up going to sleep");
695f0e185d7SPoul-Henning Kamp 		msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock,
6967fc019afSAlexander Motin 		    PRIBIO | PDROP, "-", 0);
697dd84a43cSPoul-Henning Kamp 	}
698dd84a43cSPoul-Henning Kamp }
699dd84a43cSPoul-Henning Kamp 
700dd84a43cSPoul-Henning Kamp void *
701dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
702dd84a43cSPoul-Henning Kamp {
703dd84a43cSPoul-Henning Kamp 	struct bio *bp;
704dd84a43cSPoul-Henning Kamp 	void *ptr;
705dd84a43cSPoul-Henning Kamp 	int errorc;
706dd84a43cSPoul-Henning Kamp 
7078dd5480dSPawel Jakub Dawidek 	KASSERT(length > 0 && length >= cp->provider->sectorsize &&
7088dd5480dSPawel Jakub Dawidek 	    length <= MAXPHYS, ("g_read_data(): invalid length %jd",
7098dd5480dSPawel Jakub Dawidek 	    (intmax_t)length));
7103eb6ffdfSPoul-Henning Kamp 
711a2033c96SPoul-Henning Kamp 	bp = g_alloc_bio();
712dd84a43cSPoul-Henning Kamp 	bp->bio_cmd = BIO_READ;
713dd84a43cSPoul-Henning Kamp 	bp->bio_done = NULL;
714dd84a43cSPoul-Henning Kamp 	bp->bio_offset = offset;
715dd84a43cSPoul-Henning Kamp 	bp->bio_length = length;
716a163d034SWarner Losh 	ptr = g_malloc(length, M_WAITOK);
717dd84a43cSPoul-Henning Kamp 	bp->bio_data = ptr;
718dd84a43cSPoul-Henning Kamp 	g_io_request(bp, cp);
71953706245SPoul-Henning Kamp 	errorc = biowait(bp, "gread");
720dd84a43cSPoul-Henning Kamp 	if (error != NULL)
721dd84a43cSPoul-Henning Kamp 		*error = errorc;
722dd84a43cSPoul-Henning Kamp 	g_destroy_bio(bp);
723dd84a43cSPoul-Henning Kamp 	if (errorc) {
724dd84a43cSPoul-Henning Kamp 		g_free(ptr);
725dd84a43cSPoul-Henning Kamp 		ptr = NULL;
726dd84a43cSPoul-Henning Kamp 	}
727dd84a43cSPoul-Henning Kamp 	return (ptr);
728dd84a43cSPoul-Henning Kamp }
72990b1cd56SPoul-Henning Kamp 
73090b1cd56SPoul-Henning Kamp int
73190b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length)
73290b1cd56SPoul-Henning Kamp {
73390b1cd56SPoul-Henning Kamp 	struct bio *bp;
73490b1cd56SPoul-Henning Kamp 	int error;
73590b1cd56SPoul-Henning Kamp 
7368dd5480dSPawel Jakub Dawidek 	KASSERT(length > 0 && length >= cp->provider->sectorsize &&
7378dd5480dSPawel Jakub Dawidek 	    length <= MAXPHYS, ("g_write_data(): invalid length %jd",
7388dd5480dSPawel Jakub Dawidek 	    (intmax_t)length));
7393eb6ffdfSPoul-Henning Kamp 
740a2033c96SPoul-Henning Kamp 	bp = g_alloc_bio();
74190b1cd56SPoul-Henning Kamp 	bp->bio_cmd = BIO_WRITE;
74290b1cd56SPoul-Henning Kamp 	bp->bio_done = NULL;
74390b1cd56SPoul-Henning Kamp 	bp->bio_offset = offset;
74490b1cd56SPoul-Henning Kamp 	bp->bio_length = length;
74590b1cd56SPoul-Henning Kamp 	bp->bio_data = ptr;
74690b1cd56SPoul-Henning Kamp 	g_io_request(bp, cp);
74790b1cd56SPoul-Henning Kamp 	error = biowait(bp, "gwrite");
74890b1cd56SPoul-Henning Kamp 	g_destroy_bio(bp);
74990b1cd56SPoul-Henning Kamp 	return (error);
75090b1cd56SPoul-Henning Kamp }
75172e33095SPawel Jakub Dawidek 
7522b17fb95SPawel Jakub Dawidek int
7532b17fb95SPawel Jakub Dawidek g_delete_data(struct g_consumer *cp, off_t offset, off_t length)
7542b17fb95SPawel Jakub Dawidek {
7552b17fb95SPawel Jakub Dawidek 	struct bio *bp;
7562b17fb95SPawel Jakub Dawidek 	int error;
7572b17fb95SPawel Jakub Dawidek 
758eed6cda9SPoul-Henning Kamp 	KASSERT(length > 0 && length >= cp->provider->sectorsize,
759eed6cda9SPoul-Henning Kamp 	    ("g_delete_data(): invalid length %jd", (intmax_t)length));
7602b17fb95SPawel Jakub Dawidek 
7612b17fb95SPawel Jakub Dawidek 	bp = g_alloc_bio();
7622b17fb95SPawel Jakub Dawidek 	bp->bio_cmd = BIO_DELETE;
7632b17fb95SPawel Jakub Dawidek 	bp->bio_done = NULL;
7642b17fb95SPawel Jakub Dawidek 	bp->bio_offset = offset;
7652b17fb95SPawel Jakub Dawidek 	bp->bio_length = length;
7662b17fb95SPawel Jakub Dawidek 	bp->bio_data = NULL;
7672b17fb95SPawel Jakub Dawidek 	g_io_request(bp, cp);
7682b17fb95SPawel Jakub Dawidek 	error = biowait(bp, "gdelete");
7692b17fb95SPawel Jakub Dawidek 	g_destroy_bio(bp);
7702b17fb95SPawel Jakub Dawidek 	return (error);
7712b17fb95SPawel Jakub Dawidek }
7722b17fb95SPawel Jakub Dawidek 
77372e33095SPawel Jakub Dawidek void
77472e33095SPawel Jakub Dawidek g_print_bio(struct bio *bp)
77572e33095SPawel Jakub Dawidek {
77672e33095SPawel Jakub Dawidek 	const char *pname, *cmd = NULL;
77772e33095SPawel Jakub Dawidek 
77872e33095SPawel Jakub Dawidek 	if (bp->bio_to != NULL)
77972e33095SPawel Jakub Dawidek 		pname = bp->bio_to->name;
78072e33095SPawel Jakub Dawidek 	else
78172e33095SPawel Jakub Dawidek 		pname = "[unknown]";
78272e33095SPawel Jakub Dawidek 
78372e33095SPawel Jakub Dawidek 	switch (bp->bio_cmd) {
78472e33095SPawel Jakub Dawidek 	case BIO_GETATTR:
78572e33095SPawel Jakub Dawidek 		cmd = "GETATTR";
78672e33095SPawel Jakub Dawidek 		printf("%s[%s(attr=%s)]", pname, cmd, bp->bio_attribute);
78772e33095SPawel Jakub Dawidek 		return;
788c3618c65SPawel Jakub Dawidek 	case BIO_FLUSH:
789c3618c65SPawel Jakub Dawidek 		cmd = "FLUSH";
790c3618c65SPawel Jakub Dawidek 		printf("%s[%s]", pname, cmd);
791c3618c65SPawel Jakub Dawidek 		return;
79272e33095SPawel Jakub Dawidek 	case BIO_READ:
79372e33095SPawel Jakub Dawidek 		cmd = "READ";
7947ce513a5SEdward Tomasz Napierala 		break;
79572e33095SPawel Jakub Dawidek 	case BIO_WRITE:
79672e33095SPawel Jakub Dawidek 		cmd = "WRITE";
7977ce513a5SEdward Tomasz Napierala 		break;
79872e33095SPawel Jakub Dawidek 	case BIO_DELETE:
79972e33095SPawel Jakub Dawidek 		cmd = "DELETE";
8007ce513a5SEdward Tomasz Napierala 		break;
80172e33095SPawel Jakub Dawidek 	default:
80272e33095SPawel Jakub Dawidek 		cmd = "UNKNOWN";
80372e33095SPawel Jakub Dawidek 		printf("%s[%s()]", pname, cmd);
80472e33095SPawel Jakub Dawidek 		return;
80572e33095SPawel Jakub Dawidek 	}
8067ce513a5SEdward Tomasz Napierala 	printf("%s[%s(offset=%jd, length=%jd)]", pname, cmd,
8077ce513a5SEdward Tomasz Napierala 	    (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length);
80872e33095SPawel Jakub Dawidek }
809