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