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.
This commit is contained in:
phk 2003-04-19 10:14:39 +00:00
parent a41f716e91
commit db4d21ffaf
3 changed files with 77 additions and 38 deletions

View File

@ -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)))

View File

@ -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);
}

View File

@ -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_ */