geom_io.c revision 110517
115885Sjulian/*-
215885Sjulian * Copyright (c) 2002 Poul-Henning Kamp
315885Sjulian * Copyright (c) 2002 Networks Associates Technology, Inc.
415885Sjulian * All rights reserved.
515885Sjulian *
615885Sjulian * This software was developed for the FreeBSD Project by Poul-Henning Kamp
715885Sjulian * and NAI Labs, the Security Research Division of Network Associates, Inc.
815885Sjulian * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
915885Sjulian * DARPA CHATS research program.
1015885Sjulian *
1115885Sjulian * Redistribution and use in source and binary forms, with or without
1215885Sjulian * modification, are permitted provided that the following conditions
1315885Sjulian * are met:
1415885Sjulian * 1. Redistributions of source code must retain the above copyright
1515885Sjulian *    notice, this list of conditions and the following disclaimer.
1615885Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1715885Sjulian *    notice, this list of conditions and the following disclaimer in the
1815885Sjulian *    documentation and/or other materials provided with the distribution.
1915885Sjulian * 3. The names of the authors may not be used to endorse or promote
2015885Sjulian *    products derived from this software without specific prior written
2115885Sjulian *    permission.
2218207Sbde *
2318207Sbde * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2418207Sbde * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2518207Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2615885Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2715885Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2817967Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2917967Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3017254Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3117254Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3217254Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3317254Sjulian * SUCH DAMAGE.
3417254Sjulian *
3517254Sjulian * $FreeBSD: head/sys/geom/geom_io.c 110517 2003-02-07 21:09:51Z phk $
3615885Sjulian */
3715885Sjulian
3815885Sjulian
3915885Sjulian#include <sys/param.h>
4015885Sjulian#include <sys/stdint.h>
4115885Sjulian#ifndef _KERNEL
4215885Sjulian#include <stdio.h>
4315885Sjulian#include <string.h>
4415885Sjulian#include <stdlib.h>
4515885Sjulian#include <signal.h>
4615885Sjulian#include <err.h>
4715885Sjulian#include <sched.h>
4815885Sjulian#else
4915885Sjulian#include <sys/systm.h>
5015885Sjulian#include <sys/kernel.h>
5115885Sjulian#include <sys/malloc.h>
5215885Sjulian#include <sys/bio.h>
5315885Sjulian#endif
5418240Sjulian
5515885Sjulian#include <sys/errno.h>
5617921Sjulian#include <geom/geom.h>
5717921Sjulian#include <geom/geom_int.h>
5817921Sjulian
5915885Sjulianstatic struct g_bioq g_bio_run_down;
6015885Sjulianstatic struct g_bioq g_bio_run_up;
6115885Sjulianstatic struct g_bioq g_bio_idle;
6215885Sjulian
6315885Sjulianstatic u_int pace;
6415885Sjulian
6517921Sjulian#include <machine/atomic.h>
6617921Sjulian
6717921Sjulianstatic void
6817921Sjuliang_bioq_lock(struct g_bioq *bq)
6917921Sjulian{
7017921Sjulian
7115885Sjulian	mtx_lock(&bq->bio_queue_lock);
7215885Sjulian}
7315885Sjulian
7417921Sjulianstatic void
7517921Sjuliang_bioq_unlock(struct g_bioq *bq)
7617921Sjulian{
7717921Sjulian
7817921Sjulian	mtx_unlock(&bq->bio_queue_lock);
7917921Sjulian}
8017921Sjulian
8115885Sjulian#if 0
8215885Sjulianstatic void
8315885Sjuliang_bioq_destroy(struct g_bioq *bq)
8415885Sjulian{
8515885Sjulian
8615885Sjulian	mtx_destroy(&bq->bio_queue_lock);
8715885Sjulian}
8815885Sjulian#endif
8917921Sjulian
9017921Sjulianstatic void
9117921Sjuliang_bioq_init(struct g_bioq *bq)
9217921Sjulian{
9315885Sjulian
9415885Sjulian	TAILQ_INIT(&bq->bio_queue);
9515885Sjulian	mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF);
9615885Sjulian}
9715885Sjulian
9815885Sjulianstatic struct bio *
9917921Sjuliang_bioq_first(struct g_bioq *bq)
10017921Sjulian{
10117921Sjulian	struct bio *bp;
10215885Sjulian
10315885Sjulian	g_bioq_lock(bq);
10415885Sjulian	bp = TAILQ_FIRST(&bq->bio_queue);
10515885Sjulian	if (bp != NULL) {
10615885Sjulian		TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue);
10715885Sjulian		bq->bio_queue_length--;
10815885Sjulian	}
10917921Sjulian	g_bioq_unlock(bq);
11017921Sjulian	return (bp);
11117921Sjulian}
11217921Sjulian
11317921Sjulianstatic void
11415885Sjuliang_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq)
11515885Sjulian{
11615885Sjulian
11715885Sjulian	g_bioq_lock(rq);
11815885Sjulian	TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue);
11915885Sjulian	rq->bio_queue_length++;
12015885Sjulian	g_bioq_unlock(rq);
12117921Sjulian}
12217921Sjulian
12317921Sjulianstruct bio *
12417921Sjuliang_new_bio(void)
12517921Sjulian{
12615885Sjulian	struct bio *bp;
12715885Sjulian
12815885Sjulian	bp = g_bioq_first(&g_bio_idle);
12915885Sjulian	if (bp == NULL)
13015885Sjulian		bp = g_malloc(sizeof *bp, M_NOWAIT | M_ZERO);
13115885Sjulian	/* g_trace(G_T_BIO, "g_new_bio() = %p", bp); */
13215885Sjulian	return (bp);
13315885Sjulian}
13415885Sjulian
13515885Sjulianvoid
13617921Sjuliang_destroy_bio(struct bio *bp)
13717921Sjulian{
13817921Sjulian
13917921Sjulian	/* g_trace(G_T_BIO, "g_destroy_bio(%p)", bp); */
14017921Sjulian	bzero(bp, sizeof *bp);
14115885Sjulian	g_bioq_enqueue_tail(bp, &g_bio_idle);
14218240Sjulian}
14318244Sjulian
14415885Sjulianstruct bio *
14515885Sjuliang_clone_bio(struct bio *bp)
14615885Sjulian{
14715885Sjulian	struct bio *bp2;
14815885Sjulian
14917921Sjulian	bp2 = g_new_bio();
15017921Sjulian	if (bp2 != NULL) {
15115885Sjulian		bp2->bio_parent = bp;
15215885Sjulian		bp2->bio_cmd = bp->bio_cmd;
15318240Sjulian		bp2->bio_length = bp->bio_length;
15415885Sjulian		bp2->bio_offset = bp->bio_offset;
15515885Sjulian		bp2->bio_data = bp->bio_data;
15615885Sjulian		bp2->bio_attribute = bp->bio_attribute;
15715885Sjulian		bp->bio_children++;	/* XXX: atomic ? */
15815885Sjulian	}
15918240Sjulian	/* g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2); */
16015885Sjulian	return(bp2);
16115885Sjulian}
16218240Sjulian
16315885Sjulianvoid
16418240Sjuliang_io_init()
16518240Sjulian{
16618240Sjulian
16718240Sjulian	g_bioq_init(&g_bio_run_down);
16818240Sjulian	g_bioq_init(&g_bio_run_up);
16918240Sjulian	g_bioq_init(&g_bio_idle);
17018240Sjulian}
17115885Sjulian
17217921Sjulianint
17317921Sjuliang_io_setattr(const char *attr, struct g_consumer *cp, int len, void *ptr)
17417921Sjulian{
17517921Sjulian	struct bio *bp;
17620407Swollman	int error;
17720407Swollman
17820407Swollman	g_trace(G_T_BIO, "bio_setattr(%s)", attr);
17918240Sjulian	bp = g_new_bio();
18018240Sjulian	bp->bio_cmd = BIO_SETATTR;
18118240Sjulian	bp->bio_done = NULL;
18220407Swollman	bp->bio_attribute = attr;
18315885Sjulian	bp->bio_length = len;
18417921Sjulian	bp->bio_data = ptr;
18517921Sjulian	g_io_request(bp, cp);
18617921Sjulian	error = biowait(bp, "gsetattr");
18717921Sjulian	g_destroy_bio(bp);
18820407Swollman	return (error);
18920407Swollman}
19020407Swollman
19115885Sjulian
19215885Sjulianint
19315885Sjuliang_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr)
19415885Sjulian{
19515885Sjulian	struct bio *bp;
19615885Sjulian	int error;
19715885Sjulian
19815885Sjulian	g_trace(G_T_BIO, "bio_getattr(%s)", attr);
19915885Sjulian	bp = g_new_bio();
20017921Sjulian	bp->bio_cmd = BIO_GETATTR;
20117921Sjulian	bp->bio_done = NULL;
20217921Sjulian	bp->bio_attribute = attr;
20317921Sjulian	bp->bio_length = *len;
20415885Sjulian	bp->bio_data = ptr;
20515885Sjulian	g_io_request(bp, cp);
20617921Sjulian	error = biowait(bp, "ggetattr");
20717921Sjulian	*len = bp->bio_completed;
20817921Sjulian	g_destroy_bio(bp);
20915885Sjulian	return (error);
21015885Sjulian}
21115885Sjulian
21215885Sjulianstatic int
21315885Sjuliang_io_check(struct bio *bp)
21415885Sjulian{
21515885Sjulian	struct g_consumer *cp;
21615885Sjulian	struct g_provider *pp;
21717921Sjulian
21817921Sjulian	cp = bp->bio_from;
21917921Sjulian	pp = bp->bio_to;
22017921Sjulian
22115885Sjulian	/* Fail if access counters dont allow the operation */
22215885Sjulian	switch(bp->bio_cmd) {
22315885Sjulian	case BIO_READ:
22415885Sjulian	case BIO_GETATTR:
22515885Sjulian		if (cp->acr == 0)
22615885Sjulian			return (EPERM);
22717921Sjulian		break;
22817921Sjulian	case BIO_WRITE:
22917921Sjulian	case BIO_DELETE:
23017921Sjulian	case BIO_SETATTR:
23115885Sjulian		if (cp->acw == 0)
23215885Sjulian			return (EPERM);
23315885Sjulian		break;
23415885Sjulian	default:
23515885Sjulian		return (EPERM);
23615885Sjulian	}
23715885Sjulian	/* if provider is marked for error, don't disturb. */
23815885Sjulian	if (pp->error)
23915885Sjulian		return (pp->error);
24015885Sjulian
24115885Sjulian	switch(bp->bio_cmd) {
24215885Sjulian	case BIO_READ:
24317921Sjulian	case BIO_WRITE:
24417921Sjulian	case BIO_DELETE:
24517921Sjulian		/* Reject I/O not on sector boundary */
24617921Sjulian		if (bp->bio_offset % pp->sectorsize)
24715885Sjulian			return (EINVAL);
24815885Sjulian		/* Reject I/O not integral sector long */
24917921Sjulian		if (bp->bio_length % pp->sectorsize)
25017921Sjulian			return (EINVAL);
25117921Sjulian		/* Reject requests past the end of media. */
25217921Sjulian		if (bp->bio_offset > pp->mediasize)
25317254Sjulian			return (EIO);
25417254Sjulian		break;
25517921Sjulian	default:
25617921Sjulian		break;
25717921Sjulian	}
25817921Sjulian	return (0);
25917254Sjulian}
26017254Sjulian
26117254Sjulianvoid
26217254Sjuliang_io_request(struct bio *bp, struct g_consumer *cp)
26315885Sjulian{
26415885Sjulian
26515885Sjulian	KASSERT(cp != NULL, ("NULL cp in g_io_request"));
26615885Sjulian	KASSERT(bp != NULL, ("NULL bp in g_io_request"));
26715885Sjulian	KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request"));
26815885Sjulian	KASSERT(bp->bio_to == NULL, ("consumer not attached in g_io_request"));
26915885Sjulian	bp->bio_from = cp;
27015885Sjulian	bp->bio_to = cp->provider;
27115885Sjulian	bp->bio_error = 0;
27215885Sjulian	bp->bio_completed = 0;
27315885Sjulian
27415885Sjulian	/* begin_stats(&bp->stats); */
27517921Sjulian
27617921Sjulian	atomic_add_int(&cp->biocount, 1);
27717921Sjulian
27815885Sjulian	/* Pass it on down. */
27917921Sjulian	g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d",
28017921Sjulian	    bp, bp->bio_from, bp->bio_from->geom->name,
28117921Sjulian	    bp->bio_to, bp->bio_to->name, bp->bio_cmd);
28217921Sjulian	g_bioq_enqueue_tail(bp, &g_bio_run_down);
28318240Sjulian	wakeup(&g_wait_down);
28420407Swollman}
28517921Sjulian
28618240Sjulianvoid
28718240Sjuliang_io_deliver(struct bio *bp, int error)
28818240Sjulian{
28918240Sjulian
29018240Sjulian	KASSERT(bp != NULL, ("NULL bp in g_io_deliver"));
29115885Sjulian	KASSERT(bp->bio_from != NULL, ("NULL bio_from in g_io_deliver"));
29217921Sjulian	KASSERT(bp->bio_from->geom != NULL,
29317921Sjulian	    ("NULL bio_from->geom in g_io_deliver"));
29417921Sjulian	KASSERT(bp->bio_to != NULL, ("NULL bio_to in g_io_deliver"));
29517921Sjulian
29615885Sjulian	g_trace(G_T_BIO,
29715885Sjulian"g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd",
29815885Sjulian	    bp, bp->bio_from, bp->bio_from->geom->name,
29915885Sjulian	    bp->bio_to, bp->bio_to->name, bp->bio_cmd, error,
30015885Sjulian	    (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length);
30115885Sjulian	/* finish_stats(&bp->stats); */
30215885Sjulian
30317921Sjulian	if (error == ENOMEM) {
30417921Sjulian		printf("ENOMEM %p on %p(%s)\n",
30517921Sjulian			bp, bp->bio_to, bp->bio_to->name);
30617921Sjulian		g_io_request(bp, bp->bio_from);
30715885Sjulian		pace++;
30815885Sjulian		return;
30915885Sjulian	}
31015885Sjulian
31115885Sjulian	bp->bio_error = error;
31215885Sjulian
31317921Sjulian	g_bioq_enqueue_tail(bp, &g_bio_run_up);
31417921Sjulian
31518240Sjulian	wakeup(&g_wait_up);
31618240Sjulian}
31718240Sjulian
31818240Sjulianvoid
31918240Sjuliang_io_schedule_down(struct thread *tp __unused)
32017921Sjulian{
32118240Sjulian	struct bio *bp;
32215885Sjulian	off_t excess;
32315885Sjulian	int error;
32415885Sjulian
32515885Sjulian	for(;;) {
32615885Sjulian		bp = g_bioq_first(&g_bio_run_down);
32715885Sjulian		if (bp == NULL)
32815885Sjulian			break;
32915885Sjulian		error = g_io_check(bp);
33015885Sjulian		if (error) {
33117254Sjulian			g_io_deliver(bp, error);
33217921Sjulian			continue;
33317921Sjulian		}
33417921Sjulian		/* Truncate requests to the end of providers media. */
33517921Sjulian		excess = bp->bio_offset + bp->bio_length;
33617921Sjulian		if (excess > bp->bio_to->mediasize) {
33717921Sjulian			excess -= bp->bio_to->mediasize;
33815885Sjulian			bp->bio_length -= excess;
33915885Sjulian		}
34015885Sjulian		/* Deliver zero length transfers right here. */
34115885Sjulian		if (bp->bio_length == 0) {
34215885Sjulian			g_io_deliver(bp, 0);
34315885Sjulian			continue;
34415885Sjulian		}
34515885Sjulian		bp->bio_to->geom->start(bp);
34617967Sjulian		if (pace) {
34718005Sjulian			pace--;
34818005Sjulian			break;
34918005Sjulian		}
35018005Sjulian	}
35118005Sjulian}
35217967Sjulian
35317967Sjulianvoid
35417967Sjuliang_io_schedule_up(struct thread *tp __unused)
35517967Sjulian{
35617967Sjulian	struct bio *bp;
35717967Sjulian	struct g_consumer *cp;
35817967Sjulian
35917967Sjulian	for(;;) {
36015885Sjulian		bp = g_bioq_first(&g_bio_run_up);
36115885Sjulian		if (bp == NULL)
36215885Sjulian			break;
36315885Sjulian
36415885Sjulian		cp = bp->bio_from;
36515885Sjulian
36615885Sjulian		atomic_add_int(&cp->biocount, -1);
36717921Sjulian		biodone(bp);
36817921Sjulian	}
36917921Sjulian}
37017921Sjulian
37115885Sjulianvoid *
37215885Sjuliang_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
37315885Sjulian{
37415885Sjulian	struct bio *bp;
37515885Sjulian	void *ptr;
37615885Sjulian	int errorc;
37715885Sjulian
37815885Sjulian	bp = g_new_bio();
37917254Sjulian	bp->bio_cmd = BIO_READ;
38017967Sjulian	bp->bio_done = NULL;
38115885Sjulian	bp->bio_offset = offset;
38215885Sjulian	bp->bio_length = length;
38317921Sjulian	ptr = g_malloc(length, 0);
38417921Sjulian	bp->bio_data = ptr;
38517921Sjulian	g_io_request(bp, cp);
38615885Sjulian	errorc = biowait(bp, "gread");
38717921Sjulian	if (error != NULL)
38817921Sjulian		*error = errorc;
38917921Sjulian	g_destroy_bio(bp);
39017921Sjulian	if (errorc) {
39117921Sjulian		g_free(ptr);
39217921Sjulian		ptr = NULL;
39317921Sjulian	}
39417921Sjulian	return (ptr);
39515885Sjulian}
39615885Sjulian
39717254Sjulianint
39815885Sjuliang_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length)
39915885Sjulian{
40015885Sjulian	struct bio *bp;
40115885Sjulian	int error;
40217254Sjulian
40317964Sjulian	bp = g_new_bio();
40417254Sjulian	bp->bio_cmd = BIO_WRITE;
40517254Sjulian	bp->bio_done = NULL;
40617254Sjulian	bp->bio_offset = offset;
40717254Sjulian	bp->bio_length = length;
40817254Sjulian	bp->bio_data = ptr;
40917964Sjulian	g_io_request(bp, cp);
41017254Sjulian	error = biowait(bp, "gwrite");
41115885Sjulian	g_destroy_bio(bp);
41215885Sjulian	return (error);
41315885Sjulian}
41415885Sjulian