summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/geom/geom_bsd.c27
-rw-r--r--sys/geom/geom_slice.c75
-rw-r--r--sys/geom/geom_slice.h13
3 files changed, 77 insertions, 38 deletions
diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c
index b812e9a..b528361 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 aff9103..5bca219 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;
+ case G_SLICE_HOT_START:
+ error = gsp->start(bp);
+ if (error && error != EJUSTRETURN)
+ g_io_deliver(bp, error);
return;
- else if (error) {
- g_io_deliver(bp, error);
+ 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 ff66d7e..4460c28 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_ */
OpenPOWER on IntegriCloud