From 7220a9e779cdcff454d877f116eab944871fe793 Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Sat, 19 Apr 2003 10:14:39 +0000 Subject: [PATCH] Make more of the "hotspot" stuff generic: Give the class a way to specify the necessary action for read/delete/write: ALLOW, DENY, START or CALL. Update geom_bsd to use this. --- sys/geom/geom_bsd.c | 27 +++++++--------- sys/geom/geom_slice.c | 75 +++++++++++++++++++++++++++++++------------ sys/geom/geom_slice.h | 13 +++++++- 3 files changed, 77 insertions(+), 38 deletions(-) diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c index b812e9a012b8..b528361822d5 100644 --- a/sys/geom/geom_bsd.c +++ b/sys/geom/geom_bsd.c @@ -58,6 +58,7 @@ #define ALPHA_LABEL_OFFSET 64 +static void g_bsd_hotwrite(void *arg, int flag); /* * Our private data about one instance. All the rest is handled by the * slice code and stored in its softc, so this is just the stuff @@ -190,6 +191,7 @@ g_bsd_modify(struct g_geom *gp, struct disklabel *dl) struct partition *ppp; struct g_slicer *gsp; struct g_consumer *cp; + struct g_bsd_softc *ms; u_int secsize, u; off_t mediasize; @@ -244,6 +246,7 @@ g_bsd_modify(struct g_geom *gp, struct disklabel *dl) /* Don't munge open partitions. */ gsp = gp->softc; + ms = gsp->softc; for (i = 0; i < dl->d_npartitions; i++) { ppp = &dl->d_partitions[i]; @@ -267,6 +270,9 @@ g_bsd_modify(struct g_geom *gp, struct disklabel *dl) dl->d_secsize, "%s%c", gp->name, 'a' + u); } + g_slice_conf_hot(gp, 0, ms->labeloffset, g_bsd_ondisk_size(), + G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); + gsp->hot = g_bsd_hotwrite; return (0); } @@ -332,13 +338,7 @@ g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int se /* Remember to free the buffer g_read_data() gave us. */ g_free(buf); - /* If we had a label, record it properly. */ - if (error == 0) { - ms->labeloffset = offset; - g_topology_lock(); - g_slice_conf_hot(gp, 0, offset, g_bsd_ondisk_size()); - g_topology_unlock(); - } + ms->labeloffset = offset; return (error); } @@ -494,6 +494,10 @@ g_bsd_hotwrite(void *arg, int flag) u_char *p; int error; + /* + * We should never get canceled, because that would amount to a removal + * of the geom while there was outstanding I/O requests. + */ KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled")); bp = arg; gp = bp->bio_to->geom; @@ -551,15 +555,6 @@ g_bsd_start(struct bio *bp) gsp = gp->softc; ms = gsp->softc; switch(bp->bio_cmd) { - case BIO_READ: - /* We allow reading of our hot spots */ - return (0); - case BIO_DELETE: - /* We do not allow deleting our hot spots */ - return (EPERM); - case BIO_WRITE: - g_call_me(g_bsd_hotwrite, bp, gp, NULL); - return (EJUSTRETURN); case BIO_GETATTR: if (g_handleattr(bp, "BSD::labelsum", ms->labelsum, sizeof(ms->labelsum))) diff --git a/sys/geom/geom_slice.c b/sys/geom/geom_slice.c index aff9103b44d0..5bca2191e098 100644 --- a/sys/geom/geom_slice.c +++ b/sys/geom/geom_slice.c @@ -112,6 +112,13 @@ g_slice_access(struct g_provider *pp, int dr, int dw, int de) return (error); } +/* + * 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: 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: so making that considerably harder is not a bad idea anyway. + */ void g_slice_finish_hot(struct bio *bp) { @@ -122,8 +129,10 @@ g_slice_finish_hot(struct bio *bp) struct g_slice *gsl; int idx; - KASSERT(bp->bio_to != NULL, ("NULL bio_to in g_slice_finish_hot(%p)", bp)); - KASSERT(bp->bio_from != NULL, ("NULL bio_from in g_slice_finish_hot(%p)", bp)); + KASSERT(bp->bio_to != NULL, + ("NULL bio_to in g_slice_finish_hot(%p)", bp)); + KASSERT(bp->bio_from != NULL, + ("NULL bio_from in g_slice_finish_hot(%p)", bp)); gp = bp->bio_to->geom; gsp = gp->softc; cp = LIST_FIRST(&gp->consumer); @@ -153,7 +162,7 @@ g_slice_start(struct bio *bp) struct g_consumer *cp; struct g_slicer *gsp; struct g_slice *gsl; - struct g_slice_hot *gmp; + struct g_slice_hot *ghp; int idx, error; u_int m_index; off_t t; @@ -177,22 +186,33 @@ g_slice_start(struct bio *bp) * method once if so. */ t = bp->bio_offset + gsl->offset; - /* .ctl devices may take us negative */ - if (t < 0 || (t + bp->bio_length) < 0) { - g_io_deliver(bp, EINVAL); - return; - } for (m_index = 0; m_index < gsp->nhotspot; m_index++) { - gmp = &gsp->hotspot[m_index]; - if (t >= gmp->offset + gmp->length) + ghp = &gsp->hotspot[m_index]; + if (t >= ghp->offset + ghp->length) continue; - if (t + bp->bio_length <= gmp->offset) + if (t + bp->bio_length <= ghp->offset) continue; - error = gsp->start(bp); - if (error == EJUSTRETURN) + switch(bp->bio_cmd) { + case BIO_READ: idx = ghp->ract; break; + case BIO_WRITE: idx = ghp->wact; break; + case BIO_DELETE: idx = ghp->dact; break; + } + switch(idx) { + case G_SLICE_HOT_ALLOW: + /* Fall out and continue normal processing */ + continue; + case G_SLICE_HOT_DENY: + g_io_deliver(bp, EROFS); return; - else if (error) { - g_io_deliver(bp, error); + case G_SLICE_HOT_START: + error = gsp->start(bp); + if (error && error != EJUSTRETURN) + g_io_deliver(bp, error); + return; + case G_SLICE_HOT_CALL: + error = g_call_me(gsp->hot, bp, gp, NULL); + if (error) + g_io_deliver(bp, error); return; } break; @@ -338,13 +358,27 @@ g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length return(0); } +/* + * Configure "hotspots". A hotspot is a piece of the parent device which + * this particular slicer cares about for some reason. Typically because + * it contains meta-data used to configure the slicer. + * A hotspot is identified by its index number. The offset and length are + * relative to the parent device, and the three "?act" fields specify + * what action to take on BIO_READ, BIO_DELETE and BIO_WRITE. + * + * XXX: There may be a race relative to g_slice_start() here, if an existing + * XXX: hotspot is changed wile I/O is happening. Should this become a problem + * XXX: we can protect the hotspot stuff with a mutex. + */ + int -g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length) +g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact) { struct g_slicer *gsp; struct g_slice_hot *gsl, *gsl2; - g_trace(G_T_TOPOLOGY, "g_slice_conf_hot()"); + g_trace(G_T_TOPOLOGY, "g_slice_conf_hot(%s, idx: %d, off: %jd, len: %jd)", + gp->name, idx, (intmax_t)offset, (intmax_t)length); g_topology_assert(); gsp = gp->softc; gsl = gsp->hotspot; @@ -358,12 +392,11 @@ g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length) gsl = gsl2; gsp->nhotspot = idx + 1; } - if (bootverbose) - printf("GEOM: Add %s hot[%d] start %jd length %jd end %jd\n", - gp->name, idx, (intmax_t)offset, (intmax_t)length, - (intmax_t)(offset + length - 1)); gsl[idx].offset = offset; gsl[idx].length = length; + gsl[idx].ract = ract; + gsl[idx].dact = dact; + gsl[idx].wact = wact; return (0); } diff --git a/sys/geom/geom_slice.h b/sys/geom/geom_slice.h index ff66d7ed61c0..4460c28a756e 100644 --- a/sys/geom/geom_slice.h +++ b/sys/geom/geom_slice.h @@ -48,6 +48,9 @@ struct g_slice { struct g_slice_hot { off_t offset; off_t length; + int ract; + int dact; + int wact; }; typedef int g_slice_start_t (struct bio *bp); @@ -56,10 +59,13 @@ struct g_slicer { u_int nslice; u_int nprovider; struct g_slice *slices; + u_int nhotspot; struct g_slice_hot *hotspot; + void *softc; g_slice_start_t *start; + g_call_me_t *hot; }; g_dumpconf_t g_slice_dumpconf; @@ -69,7 +75,12 @@ int g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t le #define G_SLICE_CONFIG_FORCE 2 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); -int g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length); +int g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact); +#define G_SLICE_HOT_ALLOW 1 +#define G_SLICE_HOT_DENY 2 +#define G_SLICE_HOT_START 4 +#define G_SLICE_HOT_CALL 8 + void g_slice_finish_hot(struct bio *bp); #endif /* _GEOM_GEOM_SLICE_H_ */