geom_slice.c revision 260385
117680Spst/*-
217680Spst * Copyright (c) 2002 Poul-Henning Kamp
317680Spst * Copyright (c) 2002 Networks Associates Technology, Inc.
417680Spst * All rights reserved.
517680Spst *
617680Spst * This software was developed for the FreeBSD Project by Poul-Henning Kamp
717680Spst * and NAI Labs, the Security Research Division of Network Associates, Inc.
817680Spst * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
917680Spst * DARPA CHATS research program.
1017680Spst *
1117680Spst * Redistribution and use in source and binary forms, with or without
1217680Spst * modification, are permitted provided that the following conditions
1317680Spst * are met:
1417680Spst * 1. Redistributions of source code must retain the above copyright
1517680Spst *    notice, this list of conditions and the following disclaimer.
1617680Spst * 2. Redistributions in binary form must reproduce the above copyright
1717680Spst *    notice, this list of conditions and the following disclaimer in the
1817680Spst *    documentation and/or other materials provided with the distribution.
1917680Spst * 3. The names of the authors may not be used to endorse or promote
2017680Spst *    products derived from this software without specific prior written
2117680Spst *    permission.
2217680Spst *
2317680Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2417680Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2517680Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2617680Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2717680Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2817680Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2917680Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3017680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3117680Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3217680Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3317680Spst * SUCH DAMAGE.
3417680Spst */
3517680Spst
3617680Spst#include <sys/cdefs.h>
3717680Spst__FBSDID("$FreeBSD: stable/10/sys/geom/geom_slice.c 260385 2014-01-07 01:32:23Z scottl $");
3817680Spst
3917680Spst#include <sys/param.h>
4017680Spst#include <sys/systm.h>
4117680Spst#include <sys/kernel.h>
4226180Sfenner#include <sys/malloc.h>
4317680Spst#include <sys/bio.h>
4426180Sfenner#include <sys/sysctl.h>
4526180Sfenner#include <sys/proc.h>
4617680Spst#include <sys/kthread.h>
4717680Spst#include <sys/lock.h>
4817680Spst#include <sys/mutex.h>
4917680Spst#include <sys/errno.h>
5017680Spst#include <sys/sbuf.h>
5117680Spst#include <geom/geom.h>
5217680Spst#include <geom/geom_slice.h>
5317680Spst#include <machine/stdarg.h>
5417680Spst
5517680Spststatic g_access_t g_slice_access;
5617680Spststatic g_start_t g_slice_start;
5717680Spst
5817680Spststatic struct g_slicer *
5917680Spstg_slice_alloc(unsigned nslice, unsigned scsize)
6017680Spst{
6117680Spst	struct g_slicer *gsp;
6217680Spst
6317680Spst	gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO);
6417680Spst	if (scsize > 0)
6517680Spst		gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO);
6617680Spst	else
6717680Spst		gsp->softc = NULL;
6817680Spst	gsp->slices = g_malloc(nslice * sizeof(struct g_slice),
6917680Spst	    M_WAITOK | M_ZERO);
7017680Spst	gsp->nslice = nslice;
7117680Spst	return (gsp);
7217680Spst}
7317680Spst
7417680Spststatic void
7517680Spstg_slice_free(struct g_slicer *gsp)
7617680Spst{
7717680Spst
7817680Spst	if (gsp == NULL)	/* XXX: phk thinks about this */
7917680Spst		return;
8017680Spst	g_free(gsp->slices);
8117680Spst	if (gsp->hotspot != NULL)
8217680Spst		g_free(gsp->hotspot);
8317680Spst	if (gsp->softc != NULL)
8417680Spst		g_free(gsp->softc);
8517680Spst	g_free(gsp);
8617680Spst}
8717680Spst
8817680Spststatic int
8917680Spstg_slice_access(struct g_provider *pp, int dr, int dw, int de)
9017680Spst{
9117680Spst	int error;
9217680Spst	u_int u;
9317680Spst	struct g_geom *gp;
9417680Spst	struct g_consumer *cp;
9517680Spst	struct g_provider *pp2;
9617680Spst	struct g_slicer *gsp;
9717680Spst	struct g_slice *gsl, *gsl2;
9817680Spst
9917680Spst	gp = pp->geom;
10017680Spst	cp = LIST_FIRST(&gp->consumer);
10117680Spst	KASSERT (cp != NULL, ("g_slice_access but no consumer"));
10217680Spst	gsp = gp->softc;
10317680Spst	if (dr > 0 || dw > 0 || de > 0) {
10417680Spst		gsl = &gsp->slices[pp->index];
10517680Spst		for (u = 0; u < gsp->nslice; u++) {
10617680Spst			gsl2 = &gsp->slices[u];
10717680Spst			if (gsl2->length == 0)
10817680Spst				continue;
10917680Spst			if (u == pp->index)
11017680Spst				continue;
11117680Spst			if (gsl->offset + gsl->length <= gsl2->offset)
11217680Spst				continue;
11317680Spst			if (gsl2->offset + gsl2->length <= gsl->offset)
11417680Spst				continue;
11517680Spst			/* overlap */
11617680Spst			pp2 = gsl2->provider;
11717680Spst			if ((pp->acw + dw) > 0 && pp2->ace > 0)
11817680Spst				return (EPERM);
11917680Spst			if ((pp->ace + de) > 0 && pp2->acw > 0)
12017680Spst				return (EPERM);
12117680Spst		}
12217680Spst	}
12317680Spst	/* On first open, grab an extra "exclusive" bit */
12417680Spst	if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
12517680Spst		de++;
12617680Spst	/* ... and let go of it on last close */
12717680Spst	if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
12817680Spst		de--;
12917680Spst	error = g_access(cp, dr, dw, de);
13017680Spst	return (error);
13117680Spst}
13217680Spst
13317680Spst/*
13417680Spst * XXX: It should be possible to specify here if we should finish all of the
13517680Spst * XXX: bio, or only the non-hot bits.  This would get messy if there were
13617680Spst * XXX: two hot spots in the same bio, so for now we simply finish off the
13717680Spst * XXX: entire bio.  Modifying hot data on the way to disk is frowned on
13817680Spst * XXX: so making that considerably harder is not a bad idea anyway.
13917680Spst */
14017680Spstvoid
14117680Spstg_slice_finish_hot(struct bio *bp)
14217680Spst{
14317680Spst	struct bio *bp2;
14417680Spst	struct g_geom *gp;
14517680Spst	struct g_consumer *cp;
14617680Spst	struct g_slicer *gsp;
14717680Spst	struct g_slice *gsl;
14817680Spst	int idx;
14917680Spst
15017680Spst	KASSERT(bp->bio_to != NULL,
15117680Spst	    ("NULL bio_to in g_slice_finish_hot(%p)", bp));
15217680Spst	KASSERT(bp->bio_from != NULL,
15317680Spst	    ("NULL bio_from in g_slice_finish_hot(%p)", bp));
15417680Spst	gp = bp->bio_to->geom;
15517680Spst	gsp = gp->softc;
15617680Spst	cp = LIST_FIRST(&gp->consumer);
15717680Spst	KASSERT(cp != NULL, ("NULL consumer in g_slice_finish_hot(%p)", bp));
15817680Spst	idx = bp->bio_to->index;
15917680Spst	gsl = &gsp->slices[idx];
16017680Spst
16117680Spst	bp2 = g_clone_bio(bp);
16217680Spst	if (bp2 == NULL) {
16317680Spst		g_io_deliver(bp, ENOMEM);
16417680Spst		return;
16517680Spst	}
16617680Spst	if (bp2->bio_offset + bp2->bio_length > gsl->length)
16717680Spst		bp2->bio_length = gsl->length - bp2->bio_offset;
16817680Spst	bp2->bio_done = g_std_done;
16917680Spst	bp2->bio_offset += gsl->offset;
17017680Spst	g_io_request(bp2, cp);
17117680Spst	return;
17217680Spst}
17317680Spst
17417680Spststatic void
17517680Spstg_slice_done(struct bio *bp)
17617680Spst{
17717680Spst
17817680Spst	KASSERT(bp->bio_cmd == BIO_GETATTR &&
17917680Spst	    strcmp(bp->bio_attribute, "GEOM::ident") == 0,
18017680Spst	    ("bio_cmd=0x%x bio_attribute=%s", bp->bio_cmd, bp->bio_attribute));
18117680Spst
18217680Spst	if (bp->bio_error == 0 && bp->bio_data[0] != '\0') {
18317680Spst		char idx[8];
18417680Spst
18517680Spst		/* Add index to the ident received. */
18617680Spst		snprintf(idx, sizeof(idx), "s%d",
18717680Spst		    bp->bio_parent->bio_to->index);
18817680Spst		if (strlcat(bp->bio_data, idx, bp->bio_length) >=
18917680Spst		    bp->bio_length) {
19017680Spst			bp->bio_error = EFAULT;
19117680Spst		}
19217680Spst	}
19317680Spst	g_std_done(bp);
19417680Spst}
19517680Spst
19617680Spststatic void
19717680Spstg_slice_start(struct bio *bp)
19817680Spst{
19917680Spst	struct bio *bp2;
20017680Spst	struct g_provider *pp;
20117680Spst	struct g_geom *gp;
20217680Spst	struct g_consumer *cp;
20317680Spst	struct g_slicer *gsp;
20417680Spst	struct g_slice *gsl;
20517680Spst	struct g_slice_hot *ghp;
20617680Spst	int idx, error;
20717680Spst	u_int m_index;
20817680Spst	off_t t;
20917680Spst
21017680Spst	pp = bp->bio_to;
21117680Spst	gp = pp->geom;
21217680Spst	gsp = gp->softc;
21317680Spst	cp = LIST_FIRST(&gp->consumer);
21417680Spst	idx = pp->index;
21517680Spst	gsl = &gsp->slices[idx];
21617680Spst	switch(bp->bio_cmd) {
21717680Spst	case BIO_READ:
21817680Spst	case BIO_WRITE:
21917680Spst	case BIO_DELETE:
22017680Spst		if (bp->bio_offset > gsl->length) {
22117680Spst			g_io_deliver(bp, EINVAL); /* XXX: EWHAT ? */
22217680Spst			return;
22317680Spst		}
22417680Spst		/*
22517680Spst		 * Check if we collide with any hot spaces, and call the
22617680Spst		 * method once if so.
22717680Spst		 */
22817680Spst		t = bp->bio_offset + gsl->offset;
22917680Spst		for (m_index = 0; m_index < gsp->nhotspot; m_index++) {
23017680Spst			ghp = &gsp->hotspot[m_index];
23117680Spst			if (t >= ghp->offset + ghp->length)
23217680Spst				continue;
23317680Spst			if (t + bp->bio_length <= ghp->offset)
23417680Spst				continue;
23517680Spst			switch(bp->bio_cmd) {
23617680Spst			case BIO_READ:		idx = ghp->ract; break;
23717680Spst			case BIO_WRITE:		idx = ghp->wact; break;
23817680Spst			case BIO_DELETE:	idx = ghp->dact; break;
23917680Spst			}
24017680Spst			switch(idx) {
24117680Spst			case G_SLICE_HOT_ALLOW:
24217680Spst				/* Fall out and continue normal processing */
24317680Spst				continue;
24417680Spst			case G_SLICE_HOT_DENY:
24517680Spst				g_io_deliver(bp, EROFS);
24617680Spst				return;
24717680Spst			case G_SLICE_HOT_START:
24817680Spst				error = gsp->start(bp);
24917680Spst				if (error && error != EJUSTRETURN)
25017680Spst					g_io_deliver(bp, error);
25117680Spst				return;
25217680Spst			case G_SLICE_HOT_CALL:
25317680Spst				error = g_post_event(gsp->hot, bp, M_NOWAIT,
25417680Spst				    gp, NULL);
25517680Spst				if (error)
25617680Spst					g_io_deliver(bp, error);
25717680Spst				return;
25817680Spst			}
25917680Spst			break;
26017680Spst		}
26117680Spst		bp2 = g_clone_bio(bp);
26217680Spst		if (bp2 == NULL) {
26317680Spst			g_io_deliver(bp, ENOMEM);
26417680Spst			return;
26517680Spst		}
26617680Spst		if (bp2->bio_offset + bp2->bio_length > gsl->length)
26717680Spst			bp2->bio_length = gsl->length - bp2->bio_offset;
26817680Spst		bp2->bio_done = g_std_done;
26917680Spst		bp2->bio_offset += gsl->offset;
27017680Spst		g_io_request(bp2, cp);
27117680Spst		return;
27217680Spst	case BIO_GETATTR:
27317680Spst		/* Give the real method a chance to override */
27417680Spst		if (gsp->start != NULL && gsp->start(bp))
27517680Spst			return;
27617680Spst		if (!strcmp("GEOM::ident", bp->bio_attribute)) {
27717680Spst			bp2 = g_clone_bio(bp);
27817680Spst			if (bp2 == NULL) {
27917680Spst				g_io_deliver(bp, ENOMEM);
28017680Spst				return;
28117680Spst			}
28217680Spst			bp2->bio_done = g_slice_done;
28317680Spst			g_io_request(bp2, cp);
28417680Spst			return;
28517680Spst		}
28617680Spst		if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
28717680Spst			struct g_kerneldump *gkd;
28817680Spst
28917680Spst			gkd = (struct g_kerneldump *)bp->bio_data;
29017680Spst			gkd->offset += gsp->slices[idx].offset;
29117680Spst			if (gkd->length > gsp->slices[idx].length)
29217680Spst				gkd->length = gsp->slices[idx].length;
29317680Spst			/* now, pass it on downwards... */
29417680Spst		}
29517680Spst		/* FALLTHROUGH */
29617680Spst	case BIO_FLUSH:
29717680Spst		bp2 = g_clone_bio(bp);
29817680Spst		if (bp2 == NULL) {
29917680Spst			g_io_deliver(bp, ENOMEM);
30017680Spst			return;
30117680Spst		}
30217680Spst		bp2->bio_done = g_std_done;
30317680Spst		g_io_request(bp2, cp);
30417680Spst		break;
30517680Spst	default:
30617680Spst		g_io_deliver(bp, EOPNOTSUPP);
30717680Spst		return;
30817680Spst	}
30917680Spst}
31017680Spst
31117680Spstvoid
31217680Spstg_slice_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
31317680Spst{
31417680Spst	struct g_slicer *gsp;
31517680Spst
31617680Spst	gsp = gp->softc;
31717680Spst	if (indent == NULL) {
31817680Spst		sbuf_printf(sb, " i %u", pp->index);
31917680Spst		sbuf_printf(sb, " o %ju",
32017680Spst		    (uintmax_t)gsp->slices[pp->index].offset);
32117680Spst		return;
32217680Spst	}
32317680Spst	if (pp != NULL) {
32417680Spst		sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
32517680Spst		sbuf_printf(sb, "%s<length>%ju</length>\n",
32617680Spst		    indent, (uintmax_t)gsp->slices[pp->index].length);
32717680Spst		sbuf_printf(sb, "%s<seclength>%ju</seclength>\n", indent,
32817680Spst		    (uintmax_t)gsp->slices[pp->index].length / 512);
32917680Spst		sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
33017680Spst		    (uintmax_t)gsp->slices[pp->index].offset);
33117680Spst		sbuf_printf(sb, "%s<secoffset>%ju</secoffset>\n", indent,
33217680Spst		    (uintmax_t)gsp->slices[pp->index].offset / 512);
33317680Spst	}
33417680Spst}
33517680Spst
33617680Spstint
33717680Spstg_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
33817680Spst{
33917680Spst	struct g_provider *pp, *pp2;
34017680Spst	struct g_slicer *gsp;
34117680Spst	struct g_slice *gsl;
34226180Sfenner	va_list ap;
34326180Sfenner	struct sbuf *sb;
34417680Spst	int acc;
34517680Spst
34617680Spst	g_trace(G_T_TOPOLOGY, "g_slice_config(%s, %d, %d)",
34717680Spst	     gp->name, idx, how);
34817680Spst	g_topology_assert();
34917680Spst	gsp = gp->softc;
35017680Spst	if (idx >= gsp->nslice)
35117680Spst		return(EINVAL);
35217680Spst	gsl = &gsp->slices[idx];
35317680Spst	pp = gsl->provider;
35417680Spst	if (pp != NULL)
35517680Spst		acc = pp->acr + pp->acw + pp->ace;
35617680Spst	else
35717680Spst		acc = 0;
35817680Spst	if (acc != 0 && how != G_SLICE_CONFIG_FORCE) {
35917680Spst		if (length < gsl->length)
36017680Spst			return(EBUSY);
36117680Spst		if (offset != gsl->offset)
36217680Spst			return(EBUSY);
36317680Spst	}
36417680Spst	/* XXX: check offset + length <= MEDIASIZE */
36517680Spst	if (how == G_SLICE_CONFIG_CHECK)
36617680Spst		return (0);
36717680Spst	gsl->length = length;
36817680Spst	gsl->offset = offset;
36917680Spst	gsl->sectorsize = sectorsize;
37017680Spst	if (length == 0) {
37117680Spst		if (pp == NULL)
37217680Spst			return (0);
37317680Spst		if (bootverbose)
37417680Spst			printf("GEOM: Deconfigure %s\n", pp->name);
37517680Spst		g_wither_provider(pp, ENXIO);
37617680Spst		gsl->provider = NULL;
37717680Spst		gsp->nprovider--;
37817680Spst		return (0);
37917680Spst	}
38017680Spst	if (pp != NULL) {
38117680Spst		if (bootverbose)
38217680Spst			printf("GEOM: Reconfigure %s, start %jd length %jd end %jd\n",
38317680Spst			    pp->name, (intmax_t)offset, (intmax_t)length,
38417680Spst			    (intmax_t)(offset + length - 1));
38517680Spst		g_resize_provider(pp, gsl->length);
38617680Spst		return (0);
38717680Spst	}
38817680Spst	sb = sbuf_new_auto();
38917680Spst	va_start(ap, fmt);
39017680Spst	sbuf_vprintf(sb, fmt, ap);
39117680Spst	va_end(ap);
39217680Spst	sbuf_finish(sb);
39317680Spst	pp = g_new_providerf(gp, "%s", sbuf_data(sb));
39417680Spst	pp2 = LIST_FIRST(&gp->consumer)->provider;
39517680Spst	pp->stripesize = pp2->stripesize;
39617680Spst	pp->stripeoffset = pp2->stripeoffset + offset;
39717680Spst	if (pp->stripesize > 0)
39817680Spst		pp->stripeoffset %= pp->stripesize;
39917680Spst	if (gsp->nhotspot == 0) {
40017680Spst		pp->flags |= pp2->flags & G_PF_ACCEPT_UNMAPPED;
40117680Spst		pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
40217680Spst	}
40317680Spst	if (0 && bootverbose)
40426180Sfenner		printf("GEOM: Configure %s, start %jd length %jd end %jd\n",
40517680Spst		    pp->name, (intmax_t)offset, (intmax_t)length,
40617680Spst		    (intmax_t)(offset + length - 1));
40717680Spst	pp->index = idx;
40817680Spst	pp->mediasize = gsl->length;
40917680Spst	pp->sectorsize = gsl->sectorsize;
41017680Spst	gsl->provider = pp;
41117680Spst	gsp->nprovider++;
41217680Spst	g_error_provider(pp, 0);
41317680Spst	sbuf_delete(sb);
41417680Spst	return(0);
41517680Spst}
41617680Spst
41717680Spst/*
41817680Spst * Configure "hotspots".  A hotspot is a piece of the parent device which
41917680Spst * this particular slicer cares about for some reason.  Typically because
42017680Spst * it contains meta-data used to configure the slicer.
42117680Spst * A hotspot is identified by its index number. The offset and length are
42217680Spst * relative to the parent device, and the three "?act" fields specify
42317680Spst * what action to take on BIO_READ, BIO_DELETE and BIO_WRITE.
42417680Spst *
42517680Spst * XXX: There may be a race relative to g_slice_start() here, if an existing
42617680Spst * XXX: hotspot is changed wile I/O is happening.  Should this become a problem
42717680Spst * XXX: we can protect the hotspot stuff with a mutex.
42817680Spst */
42917680Spst
43017680Spstint
43117680Spstg_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact)
43217680Spst{
43317680Spst	struct g_slicer *gsp;
43417680Spst	struct g_slice_hot *gsl, *gsl2;
43517680Spst	struct g_consumer *cp;
43617680Spst	struct g_provider *pp;
43717680Spst
43817680Spst	g_trace(G_T_TOPOLOGY, "g_slice_conf_hot(%s, idx: %d, off: %jd, len: %jd)",
43917680Spst	    gp->name, idx, (intmax_t)offset, (intmax_t)length);
44017680Spst	g_topology_assert();
44117680Spst	gsp = gp->softc;
44217680Spst	/* Deny unmapped I/O and direct dispatch if hotspots are used. */
44317680Spst	if (gsp->nhotspot == 0) {
44417680Spst		LIST_FOREACH(pp, &gp->provider, provider)
44517680Spst			pp->flags &= ~(G_PF_ACCEPT_UNMAPPED |
44617680Spst			    G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE);
44717680Spst		LIST_FOREACH(cp, &gp->consumer, consumer)
44817680Spst			cp->flags &= ~(G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE);
44917680Spst	}
45017680Spst	gsl = gsp->hotspot;
45117680Spst	if(idx >= gsp->nhotspot) {
45217680Spst		gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO);
45317680Spst		if (gsp->hotspot != NULL)
45417680Spst			bcopy(gsp->hotspot, gsl2, gsp->nhotspot * sizeof *gsl2);
45517680Spst		gsp->hotspot = gsl2;
45617680Spst		if (gsp->hotspot != NULL)
45717680Spst			g_free(gsl);
45817680Spst		gsl = gsl2;
45917680Spst		gsp->nhotspot = idx + 1;
46017680Spst	}
46117680Spst	gsl[idx].offset = offset;
46217680Spst	gsl[idx].length = length;
46317680Spst	KASSERT(!((ract | dact | wact) & G_SLICE_HOT_START)
46417680Spst	    || gsp->start != NULL, ("G_SLICE_HOT_START but no slice->start"));
46517680Spst	/* XXX: check that we _have_ a start function if HOT_START specified */
46617680Spst	gsl[idx].ract = ract;
46717680Spst	gsl[idx].dact = dact;
46817680Spst	gsl[idx].wact = wact;
46917680Spst	return (0);
47017680Spst}
47117680Spst
47217680Spstvoid
47317680Spstg_slice_spoiled(struct g_consumer *cp)
47417680Spst{
47517680Spst	struct g_geom *gp;
47617680Spst	struct g_slicer *gsp;
47717680Spst
47817680Spst	g_topology_assert();
47917680Spst	gp = cp->geom;
48017680Spst	g_trace(G_T_TOPOLOGY, "g_slice_spoiled(%p/%s)", cp, gp->name);
48117680Spst	cp->flags |= G_CF_ORPHAN;
48217680Spst	gsp = gp->softc;
48317680Spst	gp->softc = NULL;
48417680Spst	g_slice_free(gsp);
48517680Spst	g_wither_geom(gp, ENXIO);
48617680Spst}
48717680Spst
48817680Spstint
48917680Spstg_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
49017680Spst{
49117680Spst
49217680Spst	g_slice_spoiled(LIST_FIRST(&gp->consumer));
49317680Spst	return (0);
49417680Spst}
49517680Spst
49617680Spststruct g_geom *
49717680Spstg_slice_new(struct g_class *mp, u_int slices, struct g_provider *pp, struct g_consumer **cpp, void *extrap, int extra, g_slice_start_t *start)
49817680Spst{
49917680Spst	struct g_geom *gp;
50017680Spst	struct g_slicer *gsp;
50117680Spst	struct g_consumer *cp;
50217680Spst	void **vp;
50317680Spst	int error;
50417680Spst
50517680Spst	g_topology_assert();
50617680Spst	vp = (void **)extrap;
50717680Spst	gp = g_new_geomf(mp, "%s", pp->name);
50817680Spst	gsp = g_slice_alloc(slices, extra);
50917680Spst	gsp->start = start;
51017680Spst	gp->access = g_slice_access;
51117680Spst	gp->orphan = g_slice_orphan;
51217680Spst	gp->softc = gsp;
51317680Spst	gp->start = g_slice_start;
51417680Spst	gp->spoiled = g_slice_spoiled;
51517680Spst	if (gp->dumpconf == NULL)
51617680Spst		gp->dumpconf = g_slice_dumpconf;
51717680Spst	if (gp->class->destroy_geom == NULL)
51817680Spst		gp->class->destroy_geom = g_slice_destroy_geom;
51917680Spst	cp = g_new_consumer(gp);
52017680Spst	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
52117680Spst	error = g_attach(cp, pp);
52217680Spst	if (error == 0)
52317680Spst		error = g_access(cp, 1, 0, 0);
52417680Spst	if (error) {
52517680Spst		g_wither_geom(gp, ENXIO);
52617680Spst		return (NULL);
52717680Spst	}
52817680Spst	if (extrap != NULL)
52917680Spst		*vp = gsp->softc;
53017680Spst	*cpp = cp;
53117680Spst	return (gp);
53217680Spst}
53317680Spst
53417680Spstvoid
53517680Spstg_slice_orphan(struct g_consumer *cp)
53617680Spst{
53717680Spst
53817680Spst	g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name);
53917680Spst	g_topology_assert();
54017680Spst
54117680Spst	/* XXX: Not good enough we leak the softc and its suballocations */
54217680Spst	g_slice_free(cp->geom->softc);
54317680Spst	g_wither_geom(cp->geom, ENXIO);
54417680Spst}
54517680Spst