geom_dev.c revision 92108
192108Sphk/*-
292108Sphk * Copyright (c) 2002 Poul-Henning Kamp
392108Sphk * Copyright (c) 2002 Networks Associates Technology, Inc.
492108Sphk * All rights reserved.
592108Sphk *
692108Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp
792108Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc.
892108Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
992108Sphk * DARPA CHATS research program.
1092108Sphk *
1192108Sphk * Redistribution and use in source and binary forms, with or without
1292108Sphk * modification, are permitted provided that the following conditions
1392108Sphk * are met:
1492108Sphk * 1. Redistributions of source code must retain the above copyright
1592108Sphk *    notice, this list of conditions and the following disclaimer.
1692108Sphk * 2. Redistributions in binary form must reproduce the above copyright
1792108Sphk *    notice, this list of conditions and the following disclaimer in the
1892108Sphk *    documentation and/or other materials provided with the distribution.
1992108Sphk * 3. The names of the authors may not be used to endorse or promote
2092108Sphk *    products derived from this software without specific prior written
2192108Sphk *    permission.
2292108Sphk *
2392108Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2492108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2592108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2692108Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2792108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2892108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2992108Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3092108Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3192108Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3292108Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3392108Sphk * SUCH DAMAGE.
3492108Sphk *
3592108Sphk * $FreeBSD: head/sys/geom/geom_dev.c 92108 2002-03-11 21:42:35Z phk $
3692108Sphk */
3792108Sphk
3892108Sphk
3992108Sphk#include <sys/param.h>
4092108Sphk#include <sys/systm.h>
4192108Sphk#include <sys/malloc.h>
4292108Sphk#include <sys/kernel.h>
4392108Sphk#include <sys/conf.h>
4492108Sphk#include <sys/bio.h>
4592108Sphk#include <sys/lock.h>
4692108Sphk#include <sys/mutex.h>
4792108Sphk#include <sys/errno.h>
4892108Sphk#include <sys/time.h>
4992108Sphk#include <sys/disk.h>
5092108Sphk#include <sys/fcntl.h>
5192108Sphk#include <geom/geom.h>
5292108Sphk
5392108Sphk
5492108Sphk#define CDEV_MAJOR	4
5592108Sphk
5692108Sphkstatic d_open_t		g_dev_open;
5792108Sphkstatic d_close_t	g_dev_close;
5892108Sphkstatic d_strategy_t	g_dev_strategy;
5992108Sphkstatic d_ioctl_t	g_dev_ioctl;
6092108Sphkstatic d_psize_t	g_dev_psize;
6192108Sphk
6292108Sphkstatic struct cdevsw g_dev_cdevsw = {
6392108Sphk        /* open */      g_dev_open,
6492108Sphk        /* close */     g_dev_close,
6592108Sphk        /* read */      physread,
6692108Sphk        /* write */     physwrite,
6792108Sphk        /* ioctl */     g_dev_ioctl,
6892108Sphk        /* poll */      nopoll,
6992108Sphk        /* mmap */      nommap,
7092108Sphk        /* strategy */  g_dev_strategy,
7192108Sphk        /* name */      "g_dev",
7292108Sphk        /* maj */       CDEV_MAJOR,
7392108Sphk        /* dump */      nodump,
7492108Sphk        /* psize */     g_dev_psize,
7592108Sphk        /* flags */     D_DISK | D_CANFREE | D_TRACKCLOSE,
7692108Sphk};
7792108Sphk
7892108Sphkstatic g_taste_t g_dev_taste;
7992108Sphkstatic g_orphan_t g_dev_orphan;
8092108Sphk
8192108Sphkstatic struct g_method g_dev_method	= {
8292108Sphk	"DEV-method",
8392108Sphk	g_dev_taste,
8492108Sphk	NULL,
8592108Sphk	g_dev_orphan,
8692108Sphk	NULL,
8792108Sphk	G_METHOD_INITSTUFF
8892108Sphk};
8992108Sphk
9092108Sphkstatic void
9192108Sphkg_dev_clone(void *arg, char *name, int namelen, dev_t *dev)
9292108Sphk{
9392108Sphk	struct g_geom *gp;
9492108Sphk
9592108Sphk	if (*dev != NODEV)
9692108Sphk		return;
9792108Sphk
9892108Sphk	g_trace(G_T_TOPOLOGY, "g_dev_clone(%s)", name);
9992108Sphk	g_rattle();
10092108Sphk
10192108Sphk	/* XXX: can I drop Giant here ??? */
10292108Sphk	/* g_topology_lock(); */
10392108Sphk	LIST_FOREACH(gp, &g_dev_method.geom, geom) {
10492108Sphk		if (strcmp(gp->name, name))
10592108Sphk			continue;
10692108Sphk		*dev = gp->softc;
10792108Sphk		g_trace(G_T_TOPOLOGY, "g_dev_clone(%s) = %p", name, *dev);
10892108Sphk		return;
10992108Sphk	}
11092108Sphk	/* g_topology_unlock(); */
11192108Sphk	return;
11292108Sphk}
11392108Sphk
11492108Sphkstatic void
11592108Sphkg_dev_register_cloner(void *foo __unused)
11692108Sphk{
11792108Sphk	static int once;
11892108Sphk
11992108Sphk	if (!once) {
12092108Sphk		if (!once)
12192108Sphk			EVENTHANDLER_REGISTER(dev_clone, g_dev_clone, 0, 1000);
12292108Sphk		once++;
12392108Sphk	}
12492108Sphk}
12592108Sphk
12692108SphkSYSINIT(geomdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,g_dev_register_cloner,NULL);
12792108Sphk
12892108Sphkstatic struct g_geom *
12992108Sphkg_dev_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp __unused, int insist __unused)
13092108Sphk{
13192108Sphk	struct g_geom *gp;
13292108Sphk	struct g_consumer *cp;
13392108Sphk	static int unit;
13492108Sphk#if 1
13592108Sphk	u_int secsize;
13692108Sphk	off_t mediasize;
13792108Sphk	int error, j;
13892108Sphk#endif
13992108Sphk	dev_t dev;
14092108Sphk
14192108Sphk	g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
14292108Sphk	g_topology_assert();
14392108Sphk	LIST_FOREACH(cp, &pp->consumers, consumers)
14492108Sphk		if (cp->geom->method == mp)
14592108Sphk			return (NULL);
14692108Sphk	gp = g_new_geomf(mp, pp->name);
14792108Sphk	cp = g_new_consumer(gp);
14892108Sphk	g_attach(cp, pp);
14992108Sphk#if 1
15092108Sphk	error = g_access_rel(cp, 1, 0, 0);
15192108Sphk	g_topology_unlock();
15292108Sphk	if (!error) {
15392108Sphk		j = sizeof secsize;
15492108Sphk		error = g_io_getattr("GEOM::sectorsize", cp, &j, &secsize, tp);
15592108Sphk		if (error) {
15692108Sphk			secsize = 512;
15792108Sphk			printf("g_bsd_taste: error %d Sectors are %d bytes\n",
15892108Sphk			    error, secsize);
15992108Sphk		}
16092108Sphk		j = sizeof mediasize;
16192108Sphk		error = g_io_getattr("GEOM::mediasize", cp, &j, &mediasize, tp);
16292108Sphk		if (error) {
16392108Sphk			mediasize = 0;
16492108Sphk			printf("g_error %d Mediasize is %lld bytes\n",
16592108Sphk			    error, mediasize);
16692108Sphk		}
16792108Sphk		g_topology_lock();
16892108Sphk		g_access_rel(cp, -1, 0, 0);
16992108Sphk		g_topology_unlock();
17092108Sphk	} else {
17192108Sphk		secsize = 512;
17292108Sphk		mediasize = 0;
17392108Sphk	}
17492108Sphk#else
17592108Sphk	g_topology_unlock();
17692108Sphk#endif
17792108Sphk	mtx_lock(&Giant);
17892108Sphk#if 1
17992108Sphk	if (mediasize != 0)
18092108Sphk		printf("GEOM: \"%s\" %lld bytes in %lld sectors of %u bytes\n",
18192108Sphk		    pp->name, mediasize, mediasize / secsize, secsize);
18292108Sphk	else
18392108Sphk		printf("GEOM: \"%s\" (size unavailable)\n", pp->name);
18492108Sphk#endif
18592108Sphk	dev = make_dev(&g_dev_cdevsw, unit++,
18692108Sphk	    UID_ROOT, GID_WHEEL, 0600, gp->name);
18792108Sphk	gp->softc = dev;
18892108Sphk	dev->si_drv1 = gp;
18992108Sphk	dev->si_drv2 = cp;
19092108Sphk	mtx_unlock(&Giant);
19192108Sphk	g_topology_lock();
19292108Sphk	return (gp);
19392108Sphk}
19492108Sphk
19592108Sphkstatic int
19692108Sphkg_dev_open(dev_t dev, int flags, int fmt, struct thread *td)
19792108Sphk{
19892108Sphk	struct g_geom *gp;
19992108Sphk	struct g_consumer *cp;
20092108Sphk	int error, r, w, e;
20192108Sphk
20292108Sphk	gp = dev->si_drv1;
20392108Sphk	cp = dev->si_drv2;
20492108Sphk	if (gp == NULL || cp == NULL)
20592108Sphk		return(ENXIO);
20692108Sphk	g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
20792108Sphk	    gp->name, flags, fmt, td);
20892108Sphk	mtx_unlock(&Giant);
20992108Sphk	g_topology_lock();
21092108Sphk	g_silence();
21192108Sphk	r = flags & FREAD ? 1 : 0;
21292108Sphk	w = flags & FWRITE ? 1 : 0;
21392108Sphk	e = flags & O_EXCL ? 1 : 0;
21492108Sphk	error = g_access_rel(cp, r, w, e);
21592108Sphk	g_topology_unlock();
21692108Sphk	mtx_lock(&Giant);
21792108Sphk	g_rattle();
21892108Sphk	return(error);
21992108Sphk}
22092108Sphk
22192108Sphkstatic int
22292108Sphkg_dev_close(dev_t dev, int flags, int fmt, struct thread *td)
22392108Sphk{
22492108Sphk	struct g_geom *gp;
22592108Sphk	struct g_consumer *cp;
22692108Sphk	int error, r, w, e;
22792108Sphk
22892108Sphk	gp = dev->si_drv1;
22992108Sphk	cp = dev->si_drv2;
23092108Sphk	if (gp == NULL || cp == NULL)
23192108Sphk		return(ENXIO);
23292108Sphk	g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
23392108Sphk	    gp->name, flags, fmt, td);
23492108Sphk	mtx_unlock(&Giant);
23592108Sphk	g_topology_lock();
23692108Sphk	g_silence();
23792108Sphk	r = flags & FREAD ? -1 : 0;
23892108Sphk	w = flags & FWRITE ? -1 : 0;
23992108Sphk	e = flags & O_EXCL ? -1 : 0;
24092108Sphk	error = g_access_rel(cp, r, w, e);
24192108Sphk	g_topology_unlock();
24292108Sphk	mtx_lock(&Giant);
24392108Sphk	g_rattle();
24492108Sphk	return (error);
24592108Sphk}
24692108Sphk
24792108Sphkstatic int
24892108Sphkg_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
24992108Sphk{
25092108Sphk	struct g_geom *gp;
25192108Sphk	struct g_consumer *cp;
25292108Sphk	char *nm;
25392108Sphk	int i, error;
25492108Sphk
25592108Sphk	gp = dev->si_drv1;
25692108Sphk	cp = dev->si_drv2;
25792108Sphk
25892108Sphk	error = 0;
25992108Sphk	mtx_unlock(&Giant);
26092108Sphk	switch (cmd) {
26192108Sphk	case DIOCGDINFO:	nm = "IOCTL::DIOCGDINFO";	break;
26292108Sphk	case DIOCGDVIRGIN:	nm = "IOCTL::DIOCGDVIRGIN";	break;
26392108Sphk	case DIOCGPART:		nm = "IOCTL::DIOCGPART";	break;
26492108Sphk	default:		nm = "?";			break;
26592108Sphk	}
26692108Sphk	i = IOCGROUP(cmd);
26792108Sphk	if (*nm == '?') {
26892108Sphk		printf("IOCTL(0x%lx) \"%s\"", cmd, gp->name);
26992108Sphk		if (i > ' ' && i <= '~')
27092108Sphk			printf(" '%c'", (int)IOCGROUP(cmd));
27192108Sphk		else
27292108Sphk			printf(" 0x%lx", IOCGROUP(cmd));
27392108Sphk		printf("/%ld ", cmd & 0xff);
27492108Sphk		if (cmd & IOC_IN)
27592108Sphk			printf("I");
27692108Sphk		if (cmd & IOC_OUT)
27792108Sphk			printf("O");
27892108Sphk		printf("(%ld)", IOCPARM_LEN(cmd));
27992108Sphk		printf(" \"%s\"\n", nm);
28092108Sphk		error = ENOIOCTL;
28192108Sphk	}
28292108Sphk	if (error == 0) {
28392108Sphk		i = IOCPARM_LEN(cmd);
28492108Sphk		error = g_io_getattr(nm, cp, &i, data, td);
28592108Sphk		if (error != 0 && cmd == DIOCGDVIRGIN) {
28692108Sphk			g_topology_lock();
28792108Sphk			gp = g_create_geomf("BSD-method", cp->provider, NULL);
28892108Sphk			g_topology_unlock();
28992108Sphk		}
29092108Sphk	}
29192108Sphk	mtx_lock(&Giant);
29292108Sphk	g_rattle();
29392108Sphk	if (error == ENOIOCTL)
29492108Sphk		error = ENOTTY;
29592108Sphk	return (error);
29692108Sphk}
29792108Sphk
29892108Sphkstatic int
29992108Sphkg_dev_psize(dev_t dev)
30092108Sphk{
30192108Sphk	struct g_consumer *cp;
30292108Sphk	int i, error;
30392108Sphk	off_t mediasize;
30492108Sphk
30592108Sphk	cp = dev->si_drv2;
30692108Sphk
30792108Sphk	i = sizeof mediasize;
30892108Sphk	error = g_io_getattr("GEOM::mediasize", cp, &i, &mediasize, NULL);
30992108Sphk	if (error)
31092108Sphk		return (-1);
31192108Sphk	return (mediasize >> DEV_BSHIFT);
31292108Sphk}
31392108Sphk
31492108Sphkstatic void
31592108Sphkg_dev_done(struct bio *bp2)
31692108Sphk{
31792108Sphk	struct bio *bp;
31892108Sphk
31992108Sphk	bp = bp2->bio_linkage;
32092108Sphk	bp->bio_error = bp2->bio_error;
32192108Sphk	if (bp->bio_error != 0) {
32292108Sphk		g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
32392108Sphk		    bp2, bp->bio_error);
32492108Sphk		bp->bio_flags |= BIO_ERROR;
32592108Sphk	} else {
32692108Sphk		g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %lld",
32792108Sphk		    bp2, bp, bp->bio_resid, bp2->bio_completed);
32892108Sphk	}
32992108Sphk	bp->bio_resid = bp->bio_bcount - bp2->bio_completed;
33092108Sphk	g_destroy_bio(bp2);
33192108Sphk	mtx_lock(&Giant);
33292108Sphk	biodone(bp);
33392108Sphk	mtx_unlock(&Giant);
33492108Sphk}
33592108Sphk
33692108Sphkstatic void
33792108Sphkg_dev_strategy(struct bio *bp)
33892108Sphk{
33992108Sphk	struct g_geom *gp;
34092108Sphk	struct g_consumer *cp;
34192108Sphk	struct bio *bp2;
34292108Sphk	dev_t dev;
34392108Sphk
34492108Sphk	mtx_unlock(&Giant);
34592108Sphk	dev = bp->bio_dev;
34692108Sphk	gp = dev->si_drv1;
34792108Sphk	cp = dev->si_drv2;
34892108Sphk	bp2 = g_clone_bio(bp);
34992108Sphk	bp2->bio_offset = (off_t)bp->bio_blkno << DEV_BSHIFT;
35092108Sphk	bp2->bio_length = (off_t)bp->bio_bcount;
35192108Sphk	bp2->bio_done = g_dev_done;
35292108Sphk	g_trace(G_T_BIO,
35392108Sphk	    "g_dev_strategy(%p/%p) offset %lld length %lld data %p cmd %d",
35492108Sphk	    bp, bp2, bp->bio_offset, bp2->bio_length, bp2->bio_data,
35592108Sphk	    bp2->bio_cmd);
35692108Sphk	g_io_request(bp2, cp);
35792108Sphk	mtx_lock(&Giant);
35892108Sphk}
35992108Sphk
36092108Sphk
36192108Sphkstatic void
36292108Sphkg_dev_orphan(struct g_consumer *cp, struct thread *tp)
36392108Sphk{
36492108Sphk	struct g_geom *gp;
36592108Sphk	dev_t dev;
36692108Sphk
36792108Sphk	gp = cp->geom;
36892108Sphk	g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, gp->name);
36992108Sphk	g_topology_assert();
37092108Sphk	if (cp->biocount > 0)
37192108Sphk		return;
37292108Sphk	dev = gp->softc;
37392108Sphk	destroy_dev(dev);
37492108Sphk	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
37592108Sphk		g_access_rel(cp, -cp->acr, -cp->acw, -cp->ace);
37692108Sphk	g_dettach(cp);
37792108Sphk	g_destroy_consumer(cp);
37892108Sphk	g_destroy_geom(gp);
37992108Sphk}
38092108Sphk
38192108SphkDECLARE_GEOM_METHOD(g_dev_method, g_dev)
38292108Sphk
383