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.
This commit is contained in:
Luigi Rizzo 2009-06-11 09:55:26 +00:00
parent e4e5e663e0
commit 6231f75bcf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=193981
3 changed files with 95 additions and 0 deletions

View File

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

View File

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

View File

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