svn commit: r186945 - in user/luigi/geom_sched:
sbin/geom/class/sched sys/geom sys/geom/sched
Luigi Rizzo
luigi at FreeBSD.org
Fri Jan 9 03:48:54 PST 2009
Author: luigi
Date: Fri Jan 9 11:48:53 2009
New Revision: 186945
URL: http://svn.freebsd.org/changeset/base/186945
Log:
documentation and small reorganization of the code
Modified:
user/luigi/geom_sched/sbin/geom/class/sched/gsched.8
user/luigi/geom_sched/sys/geom/geom_sched.c
user/luigi/geom_sched/sys/geom/sched/g_rr.c
Modified: user/luigi/geom_sched/sbin/geom/class/sched/gsched.8
==============================================================================
--- user/luigi/geom_sched/sbin/geom/class/sched/gsched.8 Fri Jan 9 11:47:14 2009 (r186944)
+++ user/luigi/geom_sched/sbin/geom/class/sched/gsched.8 Fri Jan 9 11:48:53 2009 (r186945)
@@ -27,7 +27,7 @@
.Os
.Sh NAME
.Nm gsched
-.Nd "control utility for SCHED GEOM class"
+.Nd "control utility for disk scheduler GEOM class"
.Sh SYNOPSIS
.Nm
.Cm create
@@ -46,13 +46,7 @@
.Op Fl v
.Ar prov ...
.Nm
-.Cm list
-.Nm
-.Cm status
-.Nm
-.Cm load
-.Nm
-.Cm unload
+.Cm { list | status | load | unload }
.Sh DESCRIPTION
The
.Nm
@@ -121,8 +115,8 @@ The following example shows how to creat
.Pa /dev/da0
, and how to destroy it.
.Bd -literal -offset indent
-gnop create -v da0
-gnop destroy -v da0.nop
+gsched create -v da0
+gsched destroy -v da0.nop
.Ed
.Pp
.Ed
Modified: user/luigi/geom_sched/sys/geom/geom_sched.c
==============================================================================
--- user/luigi/geom_sched/sys/geom/geom_sched.c Fri Jan 9 11:47:14 2009 (r186944)
+++ user/luigi/geom_sched/sys/geom/geom_sched.c Fri Jan 9 11:48:53 2009 (r186945)
@@ -24,6 +24,14 @@
* SUCH DAMAGE.
*/
+/*
+ * This file implements the glue for device-level pluggable disk schedulers.
+ * The actual scheduling policy is implemented by external modules which
+ * register with this one, e.g. gs_as or gs_rr ...
+ * Functions defined here are exported to geom_disk and to individual
+ * device drivers. XXX to be completed
+ */
+
#include <sys/cdefs.h>
#include <sys/param.h>
@@ -46,12 +54,17 @@
/* Debug sysctl stuff. */
SYSCTL_DECL(_kern_geom);
-SYSCTL_NODE(_kern_geom, OID_AUTO, sched, CTLFLAG_RW, 0, "I/O scheduler stuff");
-u_int g_sched_debug;
+SYSCTL_NODE(_kern_geom, OID_AUTO, sched, CTLFLAG_RW, 0,
+ "Disk I/O scheduler");
+u_int g_sched_debug; /* also used by children modules */
SYSCTL_UINT(_kern_geom_sched, OID_AUTO, debug, CTLFLAG_RW, &g_sched_debug, 0,
"Debug level");
/*
+ * The variables below store the list of schedulers registered
+ * with this class. A scheduler registers through the DECLARE_GSCHED_MODULE
+ * macro which in eventually causes the invocation of g_sched_register().
+ *
* Global mutex, protecting the registered schedulers' list and their
* gs_refs field.
*/
@@ -102,9 +115,9 @@ g_sched_disk_init(struct disk *dp)
}
/*
- * Flush the scheduler, assuming that the disk d_sched_lock mutex is
- * held. This function tries to dispatch all the requests queued in
- * the target scheduler and to wait until they're completed. Flushing
+ * Flush the scheduler. Called with the disk d_sched_lock mutex held.
+ * This function tries to dispatch all the requests queued in
+ * the target scheduler and to wait until they are completed. Flushing
* is implemented avoiding queueing for all the requests arriving while
* the flush is in progres.
*/
@@ -129,6 +142,11 @@ g_sched_flush_locked(struct disk *dp)
dp->d_sched_flags &= ~G_SCHED_FLUSHING;
}
+/*
+ * This function is called by geom_disk when a disk has been detached.
+ * We may have requests still queued, and need to dispose them because
+ * there is no underlying device anymore.
+ */
void
g_sched_disk_gone(struct disk *dp)
{
@@ -145,6 +163,7 @@ g_sched_disk_gone(struct disk *dp)
* an appropriate error. Need to release the disk
* lock since completion callbacks may reenter the
* scheduler.
+ * gsp should remain unchanged across the loop.
*/
biofinish(bp, NULL, ENXIO);
mtx_lock(&dp->d_sched_lock);
@@ -159,8 +178,9 @@ g_sched_disk_fini(struct disk *dp)
g_sched_disk_gone(dp);
/*
- * Here we assume that no new requests reach the scheduler, since
- * the disk is almost already destroyed.
+ * No new requests can reach the scheduler, as the disk
+ * is almost already destroyed (almost meaning that no more
+ * requests should arrive and the queue is empty).
*/
g_sched_configure(dp, "none");
mtx_destroy(&dp->d_sched_lock);
@@ -175,45 +195,36 @@ g_sched_start(struct disk *dp, struct bi
gsp = dp->d_sched;
/*
- * Don't try to queue a request if we have no scheduler for
- * this disk, or if the request is not one of the type we care
- * about (i.e., it is not a read or write).
- */
- if (gsp == NULL || (bp->bio_cmd & (BIO_READ | BIO_WRITE)) == 0)
- goto nosched;
-
- /*
- * When flushing is in progress we don't want the scheduler
- * queue to grow, so we dispatch new requests directly to the
- * driver.
- */
- if ((dp->d_sched_flags & G_SCHED_FLUSHING) != 0)
- goto nosched;
-
- dp->d_nr_sorted++;
- gsp->gs_start(dp->d_sched_data, bp);
- mtx_unlock(&dp->d_sched_lock);
-
- /*
- * Try to immediately start the queue. It is up to the scheduler
- * to freeze it if needed (returning NULL on the next invocation
- * of gs_next()). The scheduler will also be responsible of
- * restarting the dispatches to the driver, invoking d_kick()
- * directly.
- */
- dp->d_kick(dp);
- return;
+ * Only queue a request if
+ * 1. we have a scheduler (gsp != NULL);
+ * 2. this is a read or write request;
+ * 3. we are not flushing the scheduler.
+ * In all other cases, dispatch directly to the driver.
+ */
+ if (gsp != NULL && (bp->bio_cmd & (BIO_READ | BIO_WRITE)) != 0 &&
+ (dp->d_sched_flags & G_SCHED_FLUSHING) == 0) {
+ dp->d_nr_sorted++;
+ gsp->gs_start(dp->d_sched_data, bp);
+ mtx_unlock(&dp->d_sched_lock);
-nosched:
- mtx_unlock(&dp->d_sched_lock);
+ /*
+ * Try to immediately start the queue. It is up to
+ * the scheduler to freeze it if needed (returning NULL
+ * on the next invocation of gs_next()). In this case
+ * the scheduler will also be in charge of restarting
+ * the dispatches to the driver, invoking d_kick()
+ * directly.
+ */
+ dp->d_kick(dp);
+ } else {
+ mtx_unlock(&dp->d_sched_lock);
- /*
- * Mark the request as not sorted by the scheduler. Schedulers
- * are supposed to store a non-NULL value in the bio_caller1 field
- * (they will need it anyway, unless they're really really simple.)
- */
- bp->bio_caller1 = NULL;
- dp->d_strategy(bp);
+ /*
+ * Mark the request as not sorted by the scheduler.
+ */
+ bp->bio_caller1 = NULL;
+ dp->d_strategy(bp);
+ }
}
struct bio *
@@ -227,18 +238,14 @@ g_sched_next(struct disk *dp)
mtx_lock(&dp->d_sched_lock);
gsp = dp->d_sched;
- /* If the disk is not using a scheduler, just always return NULL. */
- if (gsp == NULL)
- goto out;
-
- /* Get the next request from the scheduler. */
- bp = gsp->gs_next(dp->d_sched_data,
- (dp->d_sched_flags & G_SCHED_FLUSHING) != 0);
+ if (gsp != NULL) { /* make sure we have a scheduler */
+ /* Get the next request from the scheduler. */
+ bp = gsp->gs_next(dp->d_sched_data,
+ (dp->d_sched_flags & G_SCHED_FLUSHING) != 0);
- KASSERT(bp == NULL || bp->bio_caller1 != NULL,
- ("bio_caller1 == NULL"));
-
-out:
+ KASSERT(bp == NULL || bp->bio_caller1 != NULL,
+ ("bio_caller1 == NULL"));
+ }
mtx_unlock(&dp->d_sched_lock);
return (bp);
@@ -262,22 +269,19 @@ g_sched_done(struct bio *bp)
* Don't call the completion callback if we have no scheduler
* or if the request that completed was not one we sorted.
*/
- if (gsp == NULL || bp->bio_caller1 == NULL)
- goto out;
-
- kick = gsp->gs_done(dp->d_sched_data, bp);
+ if (gsp != NULL && bp->bio_caller1 != NULL) {
+ kick = gsp->gs_done(dp->d_sched_data, bp);
- /*
- * If flush is in progress and we have no more requests queued,
- * wake up the flushing process.
- */
- if (--dp->d_nr_sorted == 0 &&
- (dp->d_sched_flags & G_SCHED_FLUSHING) != 0) {
- G_SCHED_DEBUG(2, "geom_sched: flush complete");
- wakeup(&dp->d_sched);
+ /*
+ * If flush is in progress and we have no more requests queued,
+ * wake up the flushing process.
+ */
+ if (--dp->d_nr_sorted == 0 &&
+ (dp->d_sched_flags & G_SCHED_FLUSHING) != 0) {
+ G_SCHED_DEBUG(2, "geom_sched: flush complete");
+ wakeup(&dp->d_sched);
+ }
}
-
-out:
mtx_unlock(&dp->d_sched_lock);
if (kick)
@@ -333,13 +337,14 @@ g_sched_unregister(struct g_sched *gsp)
G_SCHED_DEBUG(1, "geom_sched: %s still in use",
gsp->gs_name);
error = EBUSY;
- } else if (gsp->gs_refs == 1)
+ } else if (gsp->gs_refs == 1) {
/*
* The list reference is the last one
* that can be removed, so it is safe to
* just decrement the counter elsewhere.
*/
LIST_REMOVE(gsp, gs_list);
+ }
goto out;
}
}
Modified: user/luigi/geom_sched/sys/geom/sched/g_rr.c
==============================================================================
--- user/luigi/geom_sched/sys/geom/sched/g_rr.c Fri Jan 9 11:47:14 2009 (r186944)
+++ user/luigi/geom_sched/sys/geom/sched/g_rr.c Fri Jan 9 11:48:53 2009 (r186945)
@@ -24,6 +24,10 @@
* SUCH DAMAGE.
*/
+/*
+ * GEOM-based round robin disk scheduler.
+ */
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -43,7 +47,7 @@
*/
/* Timeout for anticipation. */
-#define G_RR_WAIT_EXPIRE (hz/200 > 0 ? hz/200 : 2)
+#define G_RR_WAIT_EXPIRE (hz/400 > 0 ? hz/200 : 2)
#define G_QUEUE_NOWAIT 0 /* Ready to dispatch. */
#define G_QUEUE_WAITREQ 1 /* Waiting for a completion. */
@@ -129,6 +133,7 @@ g_rr_queue_get(struct g_rr_softc *sc, u_
bioq_init(&qp->q_bioq);
qp->q_budget = G_RR_DEFAULT_BUDGET;
LIST_INSERT_HEAD(bucket, qp, q_hash);
+ printf("new queue for key %lu\n", key);
}
return (qp);
@@ -177,7 +182,6 @@ g_rr_fini(void *data)
KASSERT(TAILQ_EMPTY(&sc->sc_rr_tailq), ("still scheduled queues"));
for (i = 0; i < G_RR_HASH_SIZE; i++) {
LIST_FOREACH_SAFE(qp, &sc->sc_hash[i], q_hash, qp2) {
- LIST_REMOVE(qp, q_hash);
g_rr_queue_put(qp);
}
}
@@ -246,6 +250,9 @@ g_rr_dispatch(struct g_rr_softc *sc)
g_io_request(bp, LIST_FIRST(&sc->sc_geom->consumer));
}
+/*
+ * Called when a real request for disk I/O arrives.
+ */
static void
g_rr_start(void *data, struct bio *bp)
{
More information about the svn-src-user
mailing list