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:
parent
e4e5e663e0
commit
6231f75bcf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=193981
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user