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 36116196Sobrien#include <sys/cdefs.h> 37116196Sobrien__FBSDID("$FreeBSD$"); 3892108Sphk 3992108Sphk#include <sys/param.h> 4092108Sphk#include <sys/systm.h> 4192108Sphk#include <sys/kernel.h> 4292108Sphk#include <sys/malloc.h> 4392108Sphk#include <sys/bio.h> 4492108Sphk#include <sys/sysctl.h> 4592108Sphk#include <sys/proc.h> 4692108Sphk#include <sys/kthread.h> 4792108Sphk#include <sys/lock.h> 4892108Sphk#include <sys/mutex.h> 4992108Sphk#include <sys/errno.h> 5092108Sphk#include <sys/sbuf.h> 5192108Sphk#include <geom/geom.h> 5292108Sphk#include <geom/geom_slice.h> 5392108Sphk#include <machine/stdarg.h> 5492108Sphk 5593776Sphkstatic g_access_t g_slice_access; 5693776Sphkstatic g_start_t g_slice_start; 5793776Sphk 5895321Sphkstatic struct g_slicer * 59114493Sphkg_slice_alloc(unsigned nslice, unsigned scsize) 6092108Sphk{ 6192108Sphk struct g_slicer *gsp; 6292108Sphk 63111119Simp gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO); 64131046Spjd if (scsize > 0) 65131046Spjd gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO); 66131046Spjd else 67131046Spjd gsp->softc = NULL; 68104057Sphk gsp->slices = g_malloc(nslice * sizeof(struct g_slice), 69111119Simp M_WAITOK | M_ZERO); 7092108Sphk gsp->nslice = nslice; 7192108Sphk return (gsp); 7292108Sphk} 7392108Sphk 74114493Sphkstatic void 75114493Sphkg_slice_free(struct g_slicer *gsp) 76114493Sphk{ 77114493Sphk 78132631Sle if (gsp == NULL) /* XXX: phk thinks about this */ 79132631Sle return; 80114493Sphk g_free(gsp->slices); 81114493Sphk if (gsp->hotspot != NULL) 82114493Sphk g_free(gsp->hotspot); 83131408Spjd if (gsp->softc != NULL) 84131408Spjd g_free(gsp->softc); 85114493Sphk g_free(gsp); 86114493Sphk} 87114493Sphk 8893776Sphkstatic int 8992108Sphkg_slice_access(struct g_provider *pp, int dr, int dw, int de) 9092108Sphk{ 91107953Sphk int error; 92107953Sphk u_int u; 9392108Sphk struct g_geom *gp; 9492108Sphk struct g_consumer *cp; 9592108Sphk struct g_provider *pp2; 9692108Sphk struct g_slicer *gsp; 9792108Sphk struct g_slice *gsl, *gsl2; 9892108Sphk 9992108Sphk gp = pp->geom; 10092108Sphk cp = LIST_FIRST(&gp->consumer); 10192108Sphk KASSERT (cp != NULL, ("g_slice_access but no consumer")); 10292108Sphk gsp = gp->softc; 103131568Sphk if (dr > 0 || dw > 0 || de > 0) { 104131568Sphk gsl = &gsp->slices[pp->index]; 105131568Sphk for (u = 0; u < gsp->nslice; u++) { 106131568Sphk gsl2 = &gsp->slices[u]; 107131568Sphk if (gsl2->length == 0) 108131568Sphk continue; 109131568Sphk if (u == pp->index) 110131568Sphk continue; 111131568Sphk if (gsl->offset + gsl->length <= gsl2->offset) 112131568Sphk continue; 113131568Sphk if (gsl2->offset + gsl2->length <= gsl->offset) 114131568Sphk continue; 115131568Sphk /* overlap */ 116131568Sphk pp2 = gsl2->provider; 117131568Sphk if ((pp->acw + dw) > 0 && pp2->ace > 0) 118131568Sphk return (EPERM); 119131568Sphk if ((pp->ace + de) > 0 && pp2->acw > 0) 120131568Sphk return (EPERM); 121131568Sphk } 12292108Sphk } 12392108Sphk /* On first open, grab an extra "exclusive" bit */ 12492108Sphk if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) 12592108Sphk de++; 12692108Sphk /* ... and let go of it on last close */ 12792108Sphk if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) 12892108Sphk de--; 129125755Sphk error = g_access(cp, dr, dw, de); 13092108Sphk return (error); 13192108Sphk} 13292108Sphk 133113713Sphk/* 134113713Sphk * XXX: It should be possible to specify here if we should finish all of the 135113713Sphk * XXX: bio, or only the non-hot bits. This would get messy if there were 136113713Sphk * XXX: two hot spots in the same bio, so for now we simply finish off the 137113713Sphk * XXX: entire bio. Modifying hot data on the way to disk is frowned on 138113713Sphk * XXX: so making that considerably harder is not a bad idea anyway. 139113713Sphk */ 140107522Sphkvoid 141107522Sphkg_slice_finish_hot(struct bio *bp) 142107522Sphk{ 143107522Sphk struct bio *bp2; 144107522Sphk struct g_geom *gp; 145107522Sphk struct g_consumer *cp; 146107522Sphk struct g_slicer *gsp; 147107522Sphk struct g_slice *gsl; 148107953Sphk int idx; 149107522Sphk 150113713Sphk KASSERT(bp->bio_to != NULL, 151113713Sphk ("NULL bio_to in g_slice_finish_hot(%p)", bp)); 152113713Sphk KASSERT(bp->bio_from != NULL, 153113713Sphk ("NULL bio_from in g_slice_finish_hot(%p)", bp)); 154107522Sphk gp = bp->bio_to->geom; 155107522Sphk gsp = gp->softc; 156107522Sphk cp = LIST_FIRST(&gp->consumer); 157107522Sphk KASSERT(cp != NULL, ("NULL consumer in g_slice_finish_hot(%p)", bp)); 158107953Sphk idx = bp->bio_to->index; 159107953Sphk gsl = &gsp->slices[idx]; 160107522Sphk 161107522Sphk bp2 = g_clone_bio(bp); 162107522Sphk if (bp2 == NULL) { 163107522Sphk g_io_deliver(bp, ENOMEM); 164107522Sphk return; 165107522Sphk } 166107522Sphk if (bp2->bio_offset + bp2->bio_length > gsl->length) 167107522Sphk bp2->bio_length = gsl->length - bp2->bio_offset; 168107522Sphk bp2->bio_done = g_std_done; 169107522Sphk bp2->bio_offset += gsl->offset; 170107522Sphk g_io_request(bp2, cp); 171107522Sphk return; 172107522Sphk} 173107522Sphk 17493776Sphkstatic void 175169288Spjdg_slice_done(struct bio *bp) 176169288Spjd{ 177169288Spjd 178169288Spjd KASSERT(bp->bio_cmd == BIO_GETATTR && 179169288Spjd strcmp(bp->bio_attribute, "GEOM::ident") == 0, 180169288Spjd ("bio_cmd=0x%x bio_attribute=%s", bp->bio_cmd, bp->bio_attribute)); 181169288Spjd 182169288Spjd if (bp->bio_error == 0 && bp->bio_data[0] != '\0') { 183169288Spjd char idx[8]; 184169288Spjd 185169288Spjd /* Add index to the ident received. */ 186169288Spjd snprintf(idx, sizeof(idx), "s%d", 187169288Spjd bp->bio_parent->bio_to->index); 188169288Spjd if (strlcat(bp->bio_data, idx, bp->bio_length) >= 189169288Spjd bp->bio_length) { 190169288Spjd bp->bio_error = EFAULT; 191169288Spjd } 192169288Spjd } 193169288Spjd g_std_done(bp); 194169288Spjd} 195169288Spjd 196169288Spjdstatic void 19792108Sphkg_slice_start(struct bio *bp) 19892108Sphk{ 19992108Sphk struct bio *bp2; 20092108Sphk struct g_provider *pp; 20192108Sphk struct g_geom *gp; 20292108Sphk struct g_consumer *cp; 20392108Sphk struct g_slicer *gsp; 204113712Sphk struct g_slice *gsl; 205113713Sphk struct g_slice_hot *ghp; 206107953Sphk int idx, error; 207107522Sphk u_int m_index; 20894287Sphk off_t t; 20992108Sphk 21092108Sphk pp = bp->bio_to; 21192108Sphk gp = pp->geom; 21292108Sphk gsp = gp->softc; 21392108Sphk cp = LIST_FIRST(&gp->consumer); 214107953Sphk idx = pp->index; 215107953Sphk gsl = &gsp->slices[idx]; 21692108Sphk switch(bp->bio_cmd) { 21792108Sphk case BIO_READ: 21892108Sphk case BIO_WRITE: 21992108Sphk case BIO_DELETE: 22092108Sphk if (bp->bio_offset > gsl->length) { 221104195Sphk g_io_deliver(bp, EINVAL); /* XXX: EWHAT ? */ 22292108Sphk return; 22392108Sphk } 224107522Sphk /* 225107522Sphk * Check if we collide with any hot spaces, and call the 226107522Sphk * method once if so. 227107522Sphk */ 228107832Sphk t = bp->bio_offset + gsl->offset; 229113712Sphk for (m_index = 0; m_index < gsp->nhotspot; m_index++) { 230113713Sphk ghp = &gsp->hotspot[m_index]; 231113713Sphk if (t >= ghp->offset + ghp->length) 232107522Sphk continue; 233113713Sphk if (t + bp->bio_length <= ghp->offset) 234107522Sphk continue; 235113713Sphk switch(bp->bio_cmd) { 236113713Sphk case BIO_READ: idx = ghp->ract; break; 237113713Sphk case BIO_WRITE: idx = ghp->wact; break; 238113713Sphk case BIO_DELETE: idx = ghp->dact; break; 239113713Sphk } 240113713Sphk switch(idx) { 241113713Sphk case G_SLICE_HOT_ALLOW: 242113713Sphk /* Fall out and continue normal processing */ 243113713Sphk continue; 244113713Sphk case G_SLICE_HOT_DENY: 245113713Sphk g_io_deliver(bp, EROFS); 246107522Sphk return; 247113713Sphk case G_SLICE_HOT_START: 248113713Sphk error = gsp->start(bp); 249113713Sphk if (error && error != EJUSTRETURN) 250113713Sphk g_io_deliver(bp, error); 251107522Sphk return; 252113713Sphk case G_SLICE_HOT_CALL: 253113937Sphk error = g_post_event(gsp->hot, bp, M_NOWAIT, 254113937Sphk gp, NULL); 255113713Sphk if (error) 256113713Sphk g_io_deliver(bp, error); 257113713Sphk return; 258107522Sphk } 259107522Sphk break; 260107522Sphk } 26192108Sphk bp2 = g_clone_bio(bp); 262104057Sphk if (bp2 == NULL) { 263104195Sphk g_io_deliver(bp, ENOMEM); 264104057Sphk return; 265104057Sphk } 26692108Sphk if (bp2->bio_offset + bp2->bio_length > gsl->length) 26792108Sphk bp2->bio_length = gsl->length - bp2->bio_offset; 26892108Sphk bp2->bio_done = g_std_done; 26992108Sphk bp2->bio_offset += gsl->offset; 27092108Sphk g_io_request(bp2, cp); 27192108Sphk return; 27292108Sphk case BIO_GETATTR: 27394287Sphk /* Give the real method a chance to override */ 274113878Sphk if (gsp->start != NULL && gsp->start(bp)) 27594287Sphk return; 276169288Spjd if (!strcmp("GEOM::ident", bp->bio_attribute)) { 277169288Spjd bp2 = g_clone_bio(bp); 278169288Spjd if (bp2 == NULL) { 279169288Spjd g_io_deliver(bp, ENOMEM); 280169288Spjd return; 281169288Spjd } 282169288Spjd bp2->bio_done = g_slice_done; 283169288Spjd g_io_request(bp2, cp); 284169288Spjd return; 285169288Spjd } 28695038Sphk if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) { 28795038Sphk struct g_kerneldump *gkd; 28895038Sphk 28995038Sphk gkd = (struct g_kerneldump *)bp->bio_data; 290107953Sphk gkd->offset += gsp->slices[idx].offset; 291107953Sphk if (gkd->length > gsp->slices[idx].length) 292107953Sphk gkd->length = gsp->slices[idx].length; 29395038Sphk /* now, pass it on downwards... */ 29495038Sphk } 295163836Spjd /* FALLTHROUGH */ 296163836Spjd case BIO_FLUSH: 29792108Sphk bp2 = g_clone_bio(bp); 298104081Sphk if (bp2 == NULL) { 299104195Sphk g_io_deliver(bp, ENOMEM); 300104081Sphk return; 301104081Sphk } 30292108Sphk bp2->bio_done = g_std_done; 30392108Sphk g_io_request(bp2, cp); 30492108Sphk break; 30592108Sphk default: 306104195Sphk g_io_deliver(bp, EOPNOTSUPP); 30792108Sphk return; 30892108Sphk } 30992108Sphk} 31092108Sphk 31192108Sphkvoid 312107953Sphkg_slice_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) 31392108Sphk{ 31492108Sphk struct g_slicer *gsp; 31592108Sphk 31692108Sphk gsp = gp->softc; 317106101Sphk if (indent == NULL) { 318106101Sphk sbuf_printf(sb, " i %u", pp->index); 319106101Sphk sbuf_printf(sb, " o %ju", 320106101Sphk (uintmax_t)gsp->slices[pp->index].offset); 321106101Sphk return; 322106101Sphk } 32392108Sphk if (pp != NULL) { 32492108Sphk sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index); 325105540Sphk sbuf_printf(sb, "%s<length>%ju</length>\n", 326105540Sphk indent, (uintmax_t)gsp->slices[pp->index].length); 327105540Sphk sbuf_printf(sb, "%s<seclength>%ju</seclength>\n", indent, 328105540Sphk (uintmax_t)gsp->slices[pp->index].length / 512); 329105540Sphk sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent, 330105540Sphk (uintmax_t)gsp->slices[pp->index].offset); 331105540Sphk sbuf_printf(sb, "%s<secoffset>%ju</secoffset>\n", indent, 332105540Sphk (uintmax_t)gsp->slices[pp->index].offset / 512); 33392108Sphk } 33492108Sphk} 33592108Sphk 336104064Sphkint 337107953Sphkg_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...) 338104064Sphk{ 339110710Sphk struct g_provider *pp, *pp2; 340104064Sphk struct g_slicer *gsp; 341104064Sphk struct g_slice *gsl; 342104064Sphk va_list ap; 343104064Sphk struct sbuf *sb; 344115506Sphk int acc; 345104064Sphk 346104195Sphk g_trace(G_T_TOPOLOGY, "g_slice_config(%s, %d, %d)", 347107953Sphk gp->name, idx, how); 348104064Sphk g_topology_assert(); 349104064Sphk gsp = gp->softc; 350107953Sphk if (idx >= gsp->nslice) 351104064Sphk return(EINVAL); 352107953Sphk gsl = &gsp->slices[idx]; 353104064Sphk pp = gsl->provider; 354104064Sphk if (pp != NULL) 355104064Sphk acc = pp->acr + pp->acw + pp->ace; 356104064Sphk else 357104064Sphk acc = 0; 358104064Sphk if (acc != 0 && how != G_SLICE_CONFIG_FORCE) { 359104064Sphk if (length < gsl->length) 360104064Sphk return(EBUSY); 361104064Sphk if (offset != gsl->offset) 362104064Sphk return(EBUSY); 363104064Sphk } 364104064Sphk /* XXX: check offset + length <= MEDIASIZE */ 365104064Sphk if (how == G_SLICE_CONFIG_CHECK) 366104064Sphk return (0); 367104064Sphk gsl->length = length; 368104064Sphk gsl->offset = offset; 369105542Sphk gsl->sectorsize = sectorsize; 370105957Sphk if (length == 0) { 371105957Sphk if (pp == NULL) 372105957Sphk return (0); 373105957Sphk if (bootverbose) 374105957Sphk printf("GEOM: Deconfigure %s\n", pp->name); 375157619Smarcel g_wither_provider(pp, ENXIO); 376104064Sphk gsl->provider = NULL; 377104064Sphk gsp->nprovider--; 378104064Sphk return (0); 379104064Sphk } 380105957Sphk if (pp != NULL) { 381105957Sphk if (bootverbose) 382105957Sphk printf("GEOM: Reconfigure %s, start %jd length %jd end %jd\n", 383105957Sphk pp->name, (intmax_t)offset, (intmax_t)length, 384105957Sphk (intmax_t)(offset + length - 1)); 385107116Sphk pp->mediasize = gsl->length; 386105957Sphk return (0); 387105957Sphk } 388181463Sdes sb = sbuf_new_auto(); 389104064Sphk va_start(ap, fmt); 390104064Sphk sbuf_vprintf(sb, fmt, ap); 391115949Sphk va_end(ap); 392104064Sphk sbuf_finish(sb); 393243333Sjh pp = g_new_providerf(gp, "%s", sbuf_data(sb)); 394110710Sphk pp2 = LIST_FIRST(&gp->consumer)->provider; 395201645Smav pp->stripesize = pp2->stripesize; 396201645Smav pp->stripeoffset = pp2->stripeoffset + offset; 397201645Smav if (pp->stripesize > 0) 398201645Smav pp->stripeoffset %= pp->stripesize; 399248722Smav if (gsp->nhotspot == 0) 400248722Smav pp->flags |= pp2->flags & G_PF_ACCEPT_UNMAPPED; 401137149Sphk if (0 && bootverbose) 402105957Sphk printf("GEOM: Configure %s, start %jd length %jd end %jd\n", 403105957Sphk pp->name, (intmax_t)offset, (intmax_t)length, 404105957Sphk (intmax_t)(offset + length - 1)); 405107953Sphk pp->index = idx; 406105542Sphk pp->mediasize = gsl->length; 407105542Sphk pp->sectorsize = gsl->sectorsize; 408104064Sphk gsl->provider = pp; 409104064Sphk gsp->nprovider++; 410104064Sphk g_error_provider(pp, 0); 411104064Sphk sbuf_delete(sb); 412104064Sphk return(0); 413104064Sphk} 414104064Sphk 415113713Sphk/* 416113713Sphk * Configure "hotspots". A hotspot is a piece of the parent device which 417113713Sphk * this particular slicer cares about for some reason. Typically because 418113713Sphk * it contains meta-data used to configure the slicer. 419113713Sphk * A hotspot is identified by its index number. The offset and length are 420113713Sphk * relative to the parent device, and the three "?act" fields specify 421113713Sphk * what action to take on BIO_READ, BIO_DELETE and BIO_WRITE. 422113713Sphk * 423113713Sphk * XXX: There may be a race relative to g_slice_start() here, if an existing 424113713Sphk * XXX: hotspot is changed wile I/O is happening. Should this become a problem 425113713Sphk * XXX: we can protect the hotspot stuff with a mutex. 426113713Sphk */ 427113713Sphk 428107522Sphkint 429113713Sphkg_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact) 430107522Sphk{ 431107522Sphk struct g_slicer *gsp; 432113712Sphk struct g_slice_hot *gsl, *gsl2; 433248722Smav struct g_provider *pp; 434107522Sphk 435113713Sphk g_trace(G_T_TOPOLOGY, "g_slice_conf_hot(%s, idx: %d, off: %jd, len: %jd)", 436113713Sphk gp->name, idx, (intmax_t)offset, (intmax_t)length); 437107522Sphk g_topology_assert(); 438107522Sphk gsp = gp->softc; 439248722Smav /* Deny unmapped I/O if hotspots are used. */ 440248722Smav if (gsp->nhotspot == 0) { 441248722Smav LIST_FOREACH(pp, &gp->provider, provider) 442248722Smav pp->flags &= ~G_PF_ACCEPT_UNMAPPED; 443248722Smav } 444113712Sphk gsl = gsp->hotspot; 445113712Sphk if(idx >= gsp->nhotspot) { 446111119Simp gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO); 447113712Sphk if (gsp->hotspot != NULL) 448113712Sphk bcopy(gsp->hotspot, gsl2, gsp->nhotspot * sizeof *gsl2); 449113712Sphk gsp->hotspot = gsl2; 450113712Sphk if (gsp->hotspot != NULL) 451107522Sphk g_free(gsl); 452107522Sphk gsl = gsl2; 453113712Sphk gsp->nhotspot = idx + 1; 454107522Sphk } 455107953Sphk gsl[idx].offset = offset; 456107953Sphk gsl[idx].length = length; 457113878Sphk KASSERT(!((ract | dact | wact) & G_SLICE_HOT_START) 458113878Sphk || gsp->start != NULL, ("G_SLICE_HOT_START but no slice->start")); 459113878Sphk /* XXX: check that we _have_ a start function if HOT_START specified */ 460113713Sphk gsl[idx].ract = ract; 461113713Sphk gsl[idx].dact = dact; 462113713Sphk gsl[idx].wact = wact; 463107522Sphk return (0); 464107522Sphk} 465107522Sphk 466114504Sphkvoid 467114504Sphkg_slice_spoiled(struct g_consumer *cp) 468114504Sphk{ 469114504Sphk struct g_geom *gp; 470114504Sphk struct g_slicer *gsp; 471114504Sphk 472114504Sphk g_topology_assert(); 473114504Sphk gp = cp->geom; 474114504Sphk g_trace(G_T_TOPOLOGY, "g_slice_spoiled(%p/%s)", cp, gp->name); 475238886Smav cp->flags |= G_CF_ORPHAN; 476114504Sphk gsp = gp->softc; 477114504Sphk gp->softc = NULL; 478114504Sphk g_slice_free(gsp); 479114504Sphk g_wither_geom(gp, ENXIO); 480114504Sphk} 481114504Sphk 482115506Sphkint 483115506Sphkg_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) 484115506Sphk{ 485115506Sphk 486115506Sphk g_slice_spoiled(LIST_FIRST(&gp->consumer)); 487115506Sphk return (0); 488115506Sphk} 489115506Sphk 49092108Sphkstruct g_geom * 491107522Sphkg_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) 49292108Sphk{ 49392108Sphk struct g_geom *gp; 49492108Sphk struct g_slicer *gsp; 49592108Sphk struct g_consumer *cp; 49692108Sphk void **vp; 497113390Sphk int error; 49892108Sphk 49992108Sphk g_topology_assert(); 50092108Sphk vp = (void **)extrap; 50192108Sphk gp = g_new_geomf(mp, "%s", pp->name); 502114493Sphk gsp = g_slice_alloc(slices, extra); 50392108Sphk gsp->start = start; 50493776Sphk gp->access = g_slice_access; 50593776Sphk gp->orphan = g_slice_orphan; 50692108Sphk gp->softc = gsp; 50792108Sphk gp->start = g_slice_start; 508114504Sphk gp->spoiled = g_slice_spoiled; 509133986Sphk if (gp->dumpconf == NULL) 510133986Sphk gp->dumpconf = g_slice_dumpconf; 511115506Sphk if (gp->class->destroy_geom == NULL) 512115506Sphk gp->class->destroy_geom = g_slice_destroy_geom; 51392108Sphk cp = g_new_consumer(gp); 514105551Sphk error = g_attach(cp, pp); 515105551Sphk if (error == 0) 516125755Sphk error = g_access(cp, 1, 0, 0); 51792108Sphk if (error) { 518114504Sphk g_wither_geom(gp, ENXIO); 51992108Sphk return (NULL); 52092108Sphk } 521131046Spjd if (extrap != NULL) 522131046Spjd *vp = gsp->softc; 52392108Sphk *cpp = cp; 52492108Sphk return (gp); 52592108Sphk} 52692108Sphk 527155802Spjdvoid 52893250Sphkg_slice_orphan(struct g_consumer *cp) 52992108Sphk{ 53092108Sphk 53192108Sphk g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name); 53292108Sphk g_topology_assert(); 53392108Sphk 534107522Sphk /* XXX: Not good enough we leak the softc and its suballocations */ 535114504Sphk g_slice_free(cp->geom->softc); 536238198Strasz g_wither_geom(cp->geom, ENXIO); 53792108Sphk} 538