diff options
author | luigi <luigi@FreeBSD.org> | 2009-06-11 09:55:26 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2009-06-11 09:55:26 +0000 |
commit | 39676e4ab432d3a8127aa1cf32f00f5fed51c6b0 (patch) | |
tree | 6b14985cd3ab66c96dc7e48867c3a445738966c9 | |
parent | f62faa022463a57f0265698b7af9ad62f465f417 (diff) | |
download | FreeBSD-src-39676e4ab432d3a8127aa1cf32f00f5fed51c6b0.zip FreeBSD-src-39676e4ab432d3a8127aa1cf32f00f5fed51c6b0.tar.gz |
As discussed in the devsummit, introduce two fields in the
struct bio to store classification information, and a hook
for classifier functions that can be called by g_io_request().
This code is from Fabio Checconi as part of his GSOC work.
-rw-r--r-- | sys/geom/geom.h | 13 | ||||
-rw-r--r-- | sys/geom/geom_io.c | 75 | ||||
-rw-r--r-- | sys/sys/bio.h | 7 |
3 files changed, 95 insertions, 0 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h index a916ec5..c89083f 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -195,6 +195,17 @@ struct g_provider { u_int index; }; +/* + * Descriptor of a classifier. We can register a function and + * an argument, which is called by g_io_request() on bio's + * that are not previously classified. + */ +struct g_classifier_hook { + TAILQ_ENTRY(g_classifier_hook) link; + int (*func)(void *arg, struct bio *bp); + void *arg; +}; + /* geom_dev.c */ struct cdev; void g_dev_print(void); @@ -272,6 +283,8 @@ void g_destroy_bio(struct bio *); void g_io_deliver(struct bio *bp, int error); int g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr); int g_io_flush(struct g_consumer *cp); +int g_register_classifier(struct g_classifier_hook *hook); +void g_unregister_classifier(struct g_classifier_hook *hook); void g_io_request(struct bio *bp, struct g_consumer *cp); struct bio *g_new_bio(void); struct bio *g_alloc_bio(void); diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index 572dc75..cfb8c74 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -59,6 +59,15 @@ static struct g_bioq g_bio_run_task; static u_int pace; static uma_zone_t biozone; +/* + * The head of the list of classifiers used in g_io_request. + * Use g_register_classifier() and g_unregister_classifier() + * to add/remove entries to the list. + * Classifiers are invoked in registration order. + */ +static TAILQ_HEAD(g_classifier_tailq, g_classifier_hook) + g_classifier_tailq = TAILQ_HEAD_INITIALIZER(g_classifier_tailq); + #include <machine/atomic.h> static void @@ -172,6 +181,9 @@ g_clone_bio(struct bio *bp) bp2->bio_offset = bp->bio_offset; bp2->bio_data = bp->bio_data; bp2->bio_attribute = bp->bio_attribute; + /* Inherit classification info from the parent */ + bp2->bio_classifier1 = bp->bio_classifier1; + bp2->bio_classifier2 = bp->bio_classifier2; bp->bio_children++; } #ifdef KTR @@ -318,6 +330,63 @@ g_io_check(struct bio *bp) return (0); } +/* + * bio classification support. + * + * g_register_classifier() and g_unregister_classifier() + * are used to add/remove a classifier from the list. + * The list is protected using the g_bio_run_down lock, + * because the classifiers are called in this path. + * + * g_io_request() passes bio's that are not already classified + * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers(). + * Classifiers can store their result in the two fields + * bio_classifier1 and bio_classifier2. + * A classifier that updates one of the fields should + * return a non-zero value. + * If no classifier updates the field, g_run_classifiers() sets + * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls. + */ + +int +g_register_classifier(struct g_classifier_hook *hook) +{ + + g_bioq_lock(&g_bio_run_down); + TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link); + g_bioq_unlock(&g_bio_run_down); + + return (0); +} + +void +g_unregister_classifier(struct g_classifier_hook *hook) +{ + struct g_classifier_hook *entry; + + g_bioq_lock(&g_bio_run_down); + TAILQ_FOREACH(entry, &g_classifier_tailq, link) { + if (entry == hook) { + TAILQ_REMOVE(&g_classifier_tailq, hook, link); + break; + } + } + g_bioq_unlock(&g_bio_run_down); +} + +static void +g_run_classifiers(struct bio *bp) +{ + struct g_classifier_hook *hook; + int classified = 0; + + TAILQ_FOREACH(hook, &g_classifier_tailq, link) + classified |= hook->func(hook->arg, bp); + + if (!classified) + bp->bio_classifier1 = BIO_NOTCLASSIFIED; +} + void g_io_request(struct bio *bp, struct g_consumer *cp) { @@ -379,8 +448,14 @@ g_io_request(struct bio *bp, struct g_consumer *cp) * The statistics collection is lockless, as such, but we * can not update one instance of the statistics from more * than one thread at a time, so grab the lock first. + * + * We also use the lock to protect the list of classifiers. */ g_bioq_lock(&g_bio_run_down); + + if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1) + g_run_classifiers(bp); + if (g_collectstats & 1) devstat_start_transaction(pp->stat, &bp->bio_t0); if (g_collectstats & 2) diff --git a/sys/sys/bio.h b/sys/sys/bio.h index 3635963..5af902b 100644 --- a/sys/sys/bio.h +++ b/sys/sys/bio.h @@ -43,6 +43,9 @@ struct disk; struct bio; +/* Empty classifier tag, to prevent further classification. */ +#define BIO_NOTCLASSIFIED (void *)(~0UL) + typedef void bio_task_t(void *); /* @@ -78,6 +81,10 @@ struct bio { bio_task_t *bio_task; /* Task_queue handler */ void *bio_task_arg; /* Argument to above */ + + void *bio_classifier1; /* Classifier tag. */ + void *bio_classifier2; /* Classifier tag. */ + #ifdef DIAGNOSTIC void *_bio_caller1; void *_bio_caller2; |