summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_io.c
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2009-06-11 09:55:26 +0000
committerluigi <luigi@FreeBSD.org>2009-06-11 09:55:26 +0000
commit39676e4ab432d3a8127aa1cf32f00f5fed51c6b0 (patch)
tree6b14985cd3ab66c96dc7e48867c3a445738966c9 /sys/geom/geom_io.c
parentf62faa022463a57f0265698b7af9ad62f465f417 (diff)
downloadFreeBSD-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.
Diffstat (limited to 'sys/geom/geom_io.c')
-rw-r--r--sys/geom/geom_io.c75
1 files changed, 75 insertions, 0 deletions
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)
OpenPOWER on IntegriCloud