geom_io.c revision 104701
1238901Sandrew/*-
2238901Sandrew * Copyright (c) 2002 Poul-Henning Kamp
3238901Sandrew * Copyright (c) 2002 Networks Associates Technology, Inc.
4238901Sandrew * All rights reserved.
5238901Sandrew *
6238901Sandrew * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7238901Sandrew * and NAI Labs, the Security Research Division of Network Associates, Inc.
8238901Sandrew * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9238901Sandrew * DARPA CHATS research program.
10238901Sandrew *
11238901Sandrew * Redistribution and use in source and binary forms, with or without
12238901Sandrew * modification, are permitted provided that the following conditions
13238901Sandrew * are met:
14238901Sandrew * 1. Redistributions of source code must retain the above copyright
15238901Sandrew *    notice, this list of conditions and the following disclaimer.
16238901Sandrew * 2. Redistributions in binary form must reproduce the above copyright
17238901Sandrew *    notice, this list of conditions and the following disclaimer in the
18238901Sandrew *    documentation and/or other materials provided with the distribution.
19238901Sandrew * 3. The names of the authors may not be used to endorse or promote
20245614Sandrew *    products derived from this software without specific prior written
21238901Sandrew *    permission.
22238901Sandrew *
23245614Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24238901Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25245614Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26238901Sandrew * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27238901Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28238901Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29245614Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30245614Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31238901Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32238901Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33238901Sandrew * SUCH DAMAGE.
34238901Sandrew *
35238901Sandrew * $FreeBSD: head/sys/geom/geom_io.c 104701 2002-10-09 07:11:59Z phk $
36238901Sandrew */
37238901Sandrew
38238901Sandrew
39238901Sandrew#include <sys/param.h>
40238901Sandrew#ifndef _KERNEL
41238901Sandrew#include <stdio.h>
42238901Sandrew#include <string.h>
43238901Sandrew#include <stdlib.h>
44238901Sandrew#include <signal.h>
45238901Sandrew#include <err.h>
46238901Sandrew#include <sched.h>
47238901Sandrew#else
48238901Sandrew#include <sys/systm.h>
49238901Sandrew#include <sys/kernel.h>
50238901Sandrew#include <sys/malloc.h>
51245614Sandrew#include <sys/bio.h>
52245614Sandrew#endif
53245614Sandrew
54245614Sandrew#include <sys/errno.h>
55245614Sandrew#include <geom/geom.h>
56245614Sandrew#include <geom/geom_int.h>
57245614Sandrew
58245614Sandrewstatic struct g_bioq g_bio_run_down;
59245614Sandrewstatic struct g_bioq g_bio_run_up;
60245614Sandrewstatic struct g_bioq g_bio_idle;
61245614Sandrew
62245614Sandrew#include <machine/atomic.h>
63245614Sandrew
64245614Sandrewstatic void
65245614Sandrewg_bioq_lock(struct g_bioq *bq)
66245614Sandrew{
67245614Sandrew
68245614Sandrew	mtx_lock(&bq->bio_queue_lock);
69245614Sandrew}
70245614Sandrew
71238901Sandrewstatic void
72245614Sandrewg_bioq_unlock(struct g_bioq *bq)
73245614Sandrew{
74245614Sandrew
75245614Sandrew	mtx_unlock(&bq->bio_queue_lock);
76245614Sandrew}
77245614Sandrew
78245614Sandrew#if 0
79245614Sandrewstatic void
80245614Sandrewg_bioq_destroy(struct g_bioq *bq)
81245614Sandrew{
82245614Sandrew
83245614Sandrew	mtx_destroy(&bq->bio_queue_lock);
84245614Sandrew}
85245614Sandrew#endif
86245614Sandrew
87245614Sandrewstatic void
88245614Sandrewg_bioq_init(struct g_bioq *bq)
89245614Sandrew{
90245614Sandrew
91245614Sandrew	TAILQ_INIT(&bq->bio_queue);
92245614Sandrew	mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF);
93245614Sandrew}
94245614Sandrew
95245614Sandrewstatic struct bio *
96245614Sandrewg_bioq_first(struct g_bioq *bq)
97245614Sandrew{
98245614Sandrew	struct bio *bp;
99245614Sandrew
100245614Sandrew	g_bioq_lock(bq);
101245614Sandrew	bp = TAILQ_FIRST(&bq->bio_queue);
102245614Sandrew	if (bp != NULL) {
103245614Sandrew		TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue);
104245614Sandrew		bq->bio_queue_length--;
105245614Sandrew	}
106238901Sandrew	g_bioq_unlock(bq);
107238901Sandrew	return (bp);
108238901Sandrew}
109238901Sandrew
110238901Sandrewstatic void
111238901Sandrewg_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq)
112238901Sandrew{
113238901Sandrew
114238901Sandrew	g_bioq_lock(rq);
115238901Sandrew	TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue);
116238901Sandrew	rq->bio_queue_length++;
117238901Sandrew	g_bioq_unlock(rq);
118238901Sandrew}
119245614Sandrew
120245614Sandrewstruct bio *
121238901Sandrewg_new_bio(void)
122238901Sandrew{
123238901Sandrew	struct bio *bp;
124238901Sandrew
125238901Sandrew	bp = g_bioq_first(&g_bio_idle);
126238901Sandrew	if (bp == NULL)
127238901Sandrew		bp = g_malloc(sizeof *bp, M_NOWAIT | M_ZERO);
128238901Sandrew	g_trace(G_T_BIO, "g_new_bio() = %p", bp);
129245614Sandrew	return (bp);
130238901Sandrew}
131238901Sandrew
132238901Sandrewvoid
133238901Sandrewg_destroy_bio(struct bio *bp)
134238901Sandrew{
135238901Sandrew
136238901Sandrew	g_trace(G_T_BIO, "g_destroy_bio(%p)", bp);
137238901Sandrew	bzero(bp, sizeof *bp);
138238901Sandrew	g_bioq_enqueue_tail(bp, &g_bio_idle);
139238901Sandrew}
140238901Sandrew
141238901Sandrewstruct bio *
142245614Sandrewg_clone_bio(struct bio *bp)
143245614Sandrew{
144245614Sandrew	struct bio *bp2;
145245614Sandrew
146245614Sandrew	bp2 = g_new_bio();
147245614Sandrew	if (bp2 != NULL) {
148245614Sandrew		bp2->bio_linkage = bp;
149245614Sandrew		bp2->bio_cmd = bp->bio_cmd;
150245614Sandrew		bp2->bio_length = bp->bio_length;
151245614Sandrew		bp2->bio_offset = bp->bio_offset;
152245614Sandrew		bp2->bio_data = bp->bio_data;
153245614Sandrew		bp2->bio_attribute = bp->bio_attribute;
154245614Sandrew		bp->bio_children++;	/* XXX: atomic ? */
155245614Sandrew	}
156245614Sandrew	g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2);
157245614Sandrew	return(bp2);
158245614Sandrew}
159245614Sandrew
160245614Sandrewvoid
161245614Sandrewg_io_init()
162245614Sandrew{
163245614Sandrew
164245614Sandrew	g_bioq_init(&g_bio_run_down);
165245614Sandrew	g_bioq_init(&g_bio_run_up);
166245614Sandrew	g_bioq_init(&g_bio_idle);
167245614Sandrew}
168245614Sandrew
169245614Sandrewint
170245614Sandrewg_io_setattr(const char *attr, struct g_consumer *cp, int len, void *ptr)
171245614Sandrew{
172245614Sandrew	struct bio *bp;
173245614Sandrew	int error;
174245614Sandrew
175238901Sandrew	g_trace(G_T_BIO, "bio_setattr(%s)", attr);
176238901Sandrew	bp = g_new_bio();
177238901Sandrew	bp->bio_cmd = BIO_SETATTR;
178238901Sandrew	bp->bio_done = NULL;
179238901Sandrew	bp->bio_attribute = attr;
180238901Sandrew	bp->bio_length = len;
181238901Sandrew	bp->bio_data = ptr;
182238901Sandrew	g_io_request(bp, cp);
183245614Sandrew	error = biowait(bp, "gsetattr");
184245614Sandrew	g_destroy_bio(bp);
185238901Sandrew	return (error);
186238901Sandrew}
187238901Sandrew
188238901Sandrew
189238901Sandrewint
190238901Sandrewg_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr)
191238901Sandrew{
192238901Sandrew	struct bio *bp;
193238901Sandrew	int error;
194238901Sandrew
195238901Sandrew	g_trace(G_T_BIO, "bio_getattr(%s)", attr);
196238901Sandrew	bp = g_new_bio();
197238901Sandrew	bp->bio_cmd = BIO_GETATTR;
198238901Sandrew	bp->bio_done = NULL;
199238901Sandrew	bp->bio_attribute = attr;
200238901Sandrew	bp->bio_length = *len;
201238901Sandrew	bp->bio_data = ptr;
202238901Sandrew	g_io_request(bp, cp);
203238901Sandrew	error = biowait(bp, "ggetattr");
204238901Sandrew	*len = bp->bio_completed;
205238901Sandrew	g_destroy_bio(bp);
206238901Sandrew	return (error);
207238901Sandrew}
208238901Sandrew
209238901Sandrewvoid
210238901Sandrewg_io_request(struct bio *bp, struct g_consumer *cp)
211238901Sandrew{
212238901Sandrew	int error;
213238901Sandrew	off_t excess;
214238901Sandrew
215238901Sandrew	KASSERT(cp != NULL, ("bio_request on thin air"));
216238901Sandrew	error = 0;
217238901Sandrew	bp->bio_from = cp;
218238901Sandrew	bp->bio_to = cp->provider;
219238901Sandrew	bp->bio_error = 0;
220238901Sandrew	bp->bio_completed = 0;
221238901Sandrew
222238901Sandrew	/* begin_stats(&bp->stats); */
223238901Sandrew
224238901Sandrew	atomic_add_int(&cp->biocount, 1);
225238901Sandrew	/* Fail on unattached consumers */
226238901Sandrew	if (bp->bio_to == NULL) {
227238901Sandrew		g_io_deliver(bp, ENXIO);
228238901Sandrew		return;
229238901Sandrew	}
230238901Sandrew	/* Fail if access doesn't allow operation */
231238901Sandrew	switch(bp->bio_cmd) {
232238901Sandrew	case BIO_READ:
233238901Sandrew	case BIO_GETATTR:
234238901Sandrew		if (cp->acr == 0) {
235238901Sandrew			g_io_deliver(bp, EPERM);
236238901Sandrew			return;
237238901Sandrew		}
238238901Sandrew		break;
239238901Sandrew	case BIO_WRITE:
240238901Sandrew	case BIO_DELETE:
241238901Sandrew		if (cp->acw == 0) {
242238901Sandrew			g_io_deliver(bp, EPERM);
243238901Sandrew			return;
244238901Sandrew		}
245238901Sandrew		break;
246238901Sandrew	case BIO_SETATTR:
247238901Sandrew		/* XXX: Should ideally check for (cp->ace == 0) */
248238901Sandrew		if ((cp->acw == 0)) {
249238901Sandrew#ifdef DIAGNOSTIC
250238901Sandrew			printf("setattr on %s mode (%d,%d,%d)\n",
251238901Sandrew				cp->provider->name,
252238901Sandrew				cp->acr, cp->acw, cp->ace);
253238901Sandrew#endif
254238901Sandrew			g_io_deliver(bp, EPERM);
255238901Sandrew			return;
256238901Sandrew		}
257238901Sandrew		break;
258238901Sandrew	default:
259238901Sandrew		g_io_deliver(bp, EPERM);
260238901Sandrew		return;
261238901Sandrew	}
262238901Sandrew	/* if provider is marked for error, don't disturb. */
263238901Sandrew	if (bp->bio_to->error) {
264238901Sandrew		g_io_deliver(bp, bp->bio_to->error);
265238901Sandrew		return;
266238901Sandrew	}
267238901Sandrew	switch(bp->bio_cmd) {
268238901Sandrew	case BIO_READ:
269238901Sandrew	case BIO_WRITE:
270245614Sandrew	case BIO_DELETE:
271238901Sandrew		/* Reject requests past the end of media. */
272238901Sandrew		if (bp->bio_offset > bp->bio_to->mediasize) {
273245614Sandrew			g_io_deliver(bp, EIO);
274245614Sandrew			return;
275245614Sandrew		}
276245614Sandrew		/* Truncate requests to the end of providers media. */
277238901Sandrew		excess = bp->bio_offset + bp->bio_length;
278238901Sandrew		if (excess > bp->bio_to->mediasize) {
279238901Sandrew			excess -= bp->bio_to->mediasize;
280238901Sandrew			bp->bio_length -= excess;
281238901Sandrew		}
282245614Sandrew		/* Deliver zero length transfers right here. */
283238901Sandrew		if (bp->bio_length == 0) {
284238901Sandrew			g_io_deliver(bp, 0);
285238901Sandrew			return;
286238901Sandrew		}
287238901Sandrew		break;
288238901Sandrew	default:
289238901Sandrew		break;
290238901Sandrew	}
291238901Sandrew	/* Pass it on down. */
292238901Sandrew	g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d",
293238901Sandrew	    bp, bp->bio_from, bp->bio_from->geom->name,
294238901Sandrew	    bp->bio_to, bp->bio_to->name, bp->bio_cmd);
295238901Sandrew	g_bioq_enqueue_tail(bp, &g_bio_run_down);
296238901Sandrew	wakeup(&g_wait_down);
297238901Sandrew}
298238901Sandrew
299238901Sandrewvoid
300238901Sandrewg_io_deliver(struct bio *bp, int error)
301238901Sandrew{
302238901Sandrew
303238901Sandrew	g_trace(G_T_BIO,
304238901Sandrew	    "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d",
305238901Sandrew	    bp, bp->bio_from, bp->bio_from->geom->name,
306238901Sandrew	    bp->bio_to, bp->bio_to->name, bp->bio_cmd, error);
307238901Sandrew	/* finish_stats(&bp->stats); */
308238901Sandrew
309238901Sandrew	bp->bio_error = error;
310238901Sandrew
311238901Sandrew	g_bioq_enqueue_tail(bp, &g_bio_run_up);
312
313	wakeup(&g_wait_up);
314}
315
316void
317g_io_schedule_down(struct thread *tp __unused)
318{
319	struct bio *bp;
320
321	for(;;) {
322		bp = g_bioq_first(&g_bio_run_down);
323		if (bp == NULL)
324			break;
325		bp->bio_to->geom->start(bp);
326	}
327}
328
329void
330g_io_schedule_up(struct thread *tp __unused)
331{
332	struct bio *bp;
333	struct g_consumer *cp;
334
335	for(;;) {
336		bp = g_bioq_first(&g_bio_run_up);
337		if (bp == NULL)
338			break;
339
340		cp = bp->bio_from;
341
342		atomic_add_int(&cp->biocount, -1);
343		biodone(bp);
344	}
345}
346
347void *
348g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
349{
350	struct bio *bp;
351	void *ptr;
352	int errorc;
353
354	bp = g_new_bio();
355	bp->bio_cmd = BIO_READ;
356	bp->bio_done = NULL;
357	bp->bio_offset = offset;
358	bp->bio_length = length;
359	ptr = g_malloc(length, M_WAITOK);
360	bp->bio_data = ptr;
361	g_io_request(bp, cp);
362	errorc = biowait(bp, "gread");
363	if (error != NULL)
364		*error = errorc;
365	g_destroy_bio(bp);
366	if (errorc) {
367		g_free(ptr);
368		ptr = NULL;
369	}
370	return (ptr);
371}
372
373int
374g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length)
375{
376	struct bio *bp;
377	int error;
378
379	bp = g_new_bio();
380	bp->bio_cmd = BIO_WRITE;
381	bp->bio_done = NULL;
382	bp->bio_offset = offset;
383	bp->bio_length = length;
384	bp->bio_data = ptr;
385	g_io_request(bp, cp);
386	error = biowait(bp, "gwrite");
387	g_destroy_bio(bp);
388	return (error);
389}
390