svn commit: r193981 - in head/sys: geom sys

Luigi Rizzo luigi at FreeBSD.org
Thu Jun 11 09:55:27 UTC 2009


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;


More information about the svn-src-all mailing list