Changeset View
Changeset View
Standalone View
Standalone View
head/sys/geom/geom_slice.c
Show All 37 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/bio.h> | #include <sys/bio.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/kthread.h> | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <geom/geom.h> | #include <geom/geom.h> | ||||
#include <geom/geom_slice.h> | #include <geom/geom_slice.h> | ||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | g_slice_access(struct g_provider *pp, int dr, int dw, int de) | ||||
} | } | ||||
/* On first open, grab an extra "exclusive" bit */ | /* On first open, grab an extra "exclusive" bit */ | ||||
if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) | if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) | ||||
de++; | de++; | ||||
/* ... and let go of it on last close */ | /* ... and let go of it on last close */ | ||||
if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) | if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) | ||||
de--; | de--; | ||||
error = g_access(cp, dr, dw, de); | error = g_access(cp, dr, dw, de); | ||||
/* | |||||
* Free the softc if all providers have been closed and this geom | |||||
* is being removed. | |||||
*/ | |||||
if (error == 0 && (gp->flags & G_GEOM_WITHER) != 0 && | |||||
(cp->acr + cp->acw + cp->ace) == 0) | |||||
g_slice_free(gsp); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* XXX: It should be possible to specify here if we should finish all of the | * XXX: It should be possible to specify here if we should finish all of the | ||||
* XXX: bio, or only the non-hot bits. This would get messy if there were | * XXX: bio, or only the non-hot bits. This would get messy if there were | ||||
* XXX: two hot spots in the same bio, so for now we simply finish off the | * XXX: two hot spots in the same bio, so for now we simply finish off the | ||||
* XXX: entire bio. Modifying hot data on the way to disk is frowned on | * XXX: entire bio. Modifying hot data on the way to disk is frowned on | ||||
▲ Show 20 Lines • Show All 327 Lines • ▼ Show 20 Lines | g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact) | ||||
/* XXX: check that we _have_ a start function if HOT_START specified */ | /* XXX: check that we _have_ a start function if HOT_START specified */ | ||||
gsl[idx].ract = ract; | gsl[idx].ract = ract; | ||||
gsl[idx].dact = dact; | gsl[idx].dact = dact; | ||||
gsl[idx].wact = wact; | gsl[idx].wact = wact; | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
g_slice_spoiled(struct g_consumer *cp) | g_slice_orphan(struct g_consumer *cp) | ||||
{ | { | ||||
struct g_geom *gp; | struct g_geom *gp; | ||||
struct g_slicer *gsp; | |||||
g_topology_assert(); | g_topology_assert(); | ||||
gp = cp->geom; | gp = cp->geom; | ||||
g_trace(G_T_TOPOLOGY, "g_slice_spoiled(%p/%s)", cp, gp->name); | g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, gp->name); | ||||
cp->flags |= G_CF_ORPHAN; | |||||
gsp = gp->softc; | |||||
gp->softc = NULL; | |||||
g_slice_free(gsp); | |||||
g_wither_geom(gp, ENXIO); | g_wither_geom(gp, ENXIO); | ||||
/* | |||||
* We can safely free the softc now if there are no accesses, | |||||
* otherwise g_slice_access() will do that after the last close. | |||||
*/ | |||||
if ((cp->acr + cp->acw + cp->ace) == 0) | |||||
g_slice_free(gp->softc); | |||||
} | } | ||||
void | |||||
g_slice_spoiled(struct g_consumer *cp) | |||||
{ | |||||
g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->geom->name); | |||||
cp->flags |= G_CF_ORPHAN; | |||||
g_slice_orphan(cp); | |||||
} | |||||
int | int | ||||
g_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) | g_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) | ||||
{ | { | ||||
g_slice_spoiled(LIST_FIRST(&gp->consumer)); | g_slice_spoiled(LIST_FIRST(&gp->consumer)); | ||||
return (0); | return (0); | ||||
} | } | ||||
struct g_geom * | struct g_geom * | ||||
g_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) | g_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) | ||||
{ | { | ||||
struct g_geom *gp; | struct g_geom *gp; | ||||
struct g_slicer *gsp; | struct g_slicer *gsp; | ||||
struct g_consumer *cp; | struct g_consumer *cp; | ||||
void **vp; | void **vp; | ||||
int error; | int error; | ||||
g_topology_assert(); | g_topology_assert(); | ||||
vp = (void **)extrap; | vp = (void **)extrap; | ||||
gp = g_new_geomf(mp, "%s", pp->name); | gp = g_new_geomf(mp, "%s", pp->name); | ||||
gsp = g_slice_alloc(slices, extra); | gsp = g_slice_alloc(slices, extra); | ||||
gsp->start = start; | gsp->start = start; | ||||
gp->access = g_slice_access; | |||||
gp->orphan = g_slice_orphan; | |||||
gp->softc = gsp; | gp->softc = gsp; | ||||
gp->start = g_slice_start; | gp->start = g_slice_start; | ||||
gp->access = g_slice_access; | |||||
gp->orphan = g_slice_orphan; | |||||
gp->spoiled = g_slice_spoiled; | gp->spoiled = g_slice_spoiled; | ||||
if (gp->dumpconf == NULL) | if (gp->dumpconf == NULL) | ||||
gp->dumpconf = g_slice_dumpconf; | gp->dumpconf = g_slice_dumpconf; | ||||
if (gp->class->destroy_geom == NULL) | if (gp->class->destroy_geom == NULL) | ||||
gp->class->destroy_geom = g_slice_destroy_geom; | gp->class->destroy_geom = g_slice_destroy_geom; | ||||
cp = g_new_consumer(gp); | cp = g_new_consumer(gp); | ||||
cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; | cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; | ||||
error = g_attach(cp, pp); | error = g_attach(cp, pp); | ||||
if (error == 0) | if (error == 0) | ||||
error = g_access(cp, 1, 0, 0); | error = g_access(cp, 1, 0, 0); | ||||
if (error) { | if (error) { | ||||
g_wither_geom(gp, ENXIO); | g_wither_geom(gp, ENXIO); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (extrap != NULL) | if (extrap != NULL) | ||||
*vp = gsp->softc; | *vp = gsp->softc; | ||||
*cpp = cp; | *cpp = cp; | ||||
return (gp); | return (gp); | ||||
} | |||||
void | |||||
g_slice_orphan(struct g_consumer *cp) | |||||
{ | |||||
struct g_slicer *gsp; | |||||
g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name); | |||||
g_topology_assert(); | |||||
/* XXX: Not good enough we leak the softc and its suballocations */ | |||||
gsp = cp->geom->softc; | |||||
cp->geom->softc = NULL; | |||||
g_slice_free(gsp); | |||||
g_wither_geom(cp->geom, ENXIO); | |||||
} | } |