Date: Thu, 11 Jun 2009 09:55:27 +0000 (UTC) From: Luigi Rizzo <luigi@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r193981 - in head/sys: geom sys Message-ID: <200906110955.n5B9tR6T042284@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: luigi Date: Thu Jun 11 09:55:26 2009 New Revision: 193981 URL: http://svn.freebsd.org/changeset/base/193981 Log: 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. Modified: head/sys/geom/geom.h head/sys/geom/geom_io.c head/sys/sys/bio.h Modified: head/sys/geom/geom.h ============================================================================== --- head/sys/geom/geom.h Thu Jun 11 09:51:21 2009 (r193980) +++ head/sys/geom/geom.h Thu Jun 11 09:55:26 2009 (r193981) @@ -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); Modified: head/sys/geom/geom_io.c ============================================================================== --- head/sys/geom/geom_io.c Thu Jun 11 09:51:21 2009 (r193980) +++ head/sys/geom/geom_io.c Thu Jun 11 09:55:26 2009 (r193981) @@ -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_co * 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) Modified: head/sys/sys/bio.h ============================================================================== --- head/sys/sys/bio.h Thu Jun 11 09:51:21 2009 (r193980) +++ head/sys/sys/bio.h Thu Jun 11 09:55:26 2009 (r193981) @@ -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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906110955.n5B9tR6T042284>