summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2013-03-25 05:45:24 +0000
committermav <mav@FreeBSD.org>2013-03-25 05:45:24 +0000
commitaebf1ef11e8f2abf5947d3499979a1ed6d9be89b (patch)
tree652cb462ca6e44dc4c31c8fcb9f0cc5255cde7e6
parent6fa7e98571a4ba3ef27bb02c1c5bdf9328da7333 (diff)
downloadFreeBSD-src-aebf1ef11e8f2abf5947d3499979a1ed6d9be89b.zip
FreeBSD-src-aebf1ef11e8f2abf5947d3499979a1ed6d9be89b.tar.gz
In GEOM DISK:
- Replace single done mutex with per-disk ones. On system with several disks on several HBAs that removes small, but measurable lock congestion. - Modify disk destruction process to not destroy the mutex prematurely. - Remove some extra pointer derefences.
-rw-r--r--sys/geom/geom_disk.c84
1 files changed, 28 insertions, 56 deletions
diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c
index 7fec9da..af0316a 100644
--- a/sys/geom/geom_disk.c
+++ b/sys/geom/geom_disk.c
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <dev/led/led.h>
struct g_disk_softc {
+ struct mtx done_mtx;
struct disk *dp;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
@@ -67,11 +68,7 @@ struct g_disk_softc {
uint32_t state;
};
-static struct mtx g_disk_done_mtx;
-
static g_access_t g_disk_access;
-static g_init_t g_disk_init;
-static g_fini_t g_disk_fini;
static g_start_t g_disk_start;
static g_ioctl_t g_disk_ioctl;
static g_dumpconf_t g_disk_dumpconf;
@@ -80,8 +77,6 @@ static g_provgone_t g_disk_providergone;
static struct g_class g_disk_class = {
.name = "DISK",
.version = G_VERSION,
- .init = g_disk_init,
- .fini = g_disk_fini,
.start = g_disk_start,
.access = g_disk_access,
.ioctl = g_disk_ioctl,
@@ -93,20 +88,6 @@ SYSCTL_DECL(_kern_geom);
static SYSCTL_NODE(_kern_geom, OID_AUTO, disk, CTLFLAG_RW, 0,
"GEOM_DISK stuff");
-static void
-g_disk_init(struct g_class *mp __unused)
-{
-
- mtx_init(&g_disk_done_mtx, "g_disk_done", NULL, MTX_DEF);
-}
-
-static void
-g_disk_fini(struct g_class *mp __unused)
-{
-
- mtx_destroy(&g_disk_done_mtx);
-}
-
DECLARE_GEOM_CLASS(g_disk_class, g_disk);
static void __inline
@@ -135,7 +116,7 @@ g_disk_access(struct g_provider *pp, int r, int w, int e)
g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
pp->name, r, w, e);
g_topology_assert();
- sc = pp->geom->softc;
+ sc = pp->private;
if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
/*
* Allow decreasing access count even if disk is not
@@ -240,42 +221,36 @@ static void
g_disk_done(struct bio *bp)
{
struct bio *bp2;
- struct disk *dp;
struct g_disk_softc *sc;
/* See "notes" for why we need a mutex here */
/* XXX: will witness accept a mix of Giant/unGiant drivers here ? */
- mtx_lock(&g_disk_done_mtx);
- bp->bio_completed = bp->bio_length - bp->bio_resid;
-
bp2 = bp->bio_parent;
+ sc = bp2->bio_to->private;
+ bp->bio_completed = bp->bio_length - bp->bio_resid;
+ mtx_lock(&sc->done_mtx);
if (bp2->bio_error == 0)
bp2->bio_error = bp->bio_error;
bp2->bio_completed += bp->bio_completed;
- if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) != 0 &&
- (sc = bp2->bio_to->geom->softc) != NULL &&
- (dp = sc->dp) != NULL) {
- devstat_end_transaction_bio(dp->d_devstat, bp);
- }
+ if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) != 0)
+ devstat_end_transaction_bio(sc->dp->d_devstat, bp);
g_destroy_bio(bp);
bp2->bio_inbed++;
if (bp2->bio_children == bp2->bio_inbed) {
bp2->bio_resid = bp2->bio_bcount - bp2->bio_completed;
g_io_deliver(bp2, bp2->bio_error);
}
- mtx_unlock(&g_disk_done_mtx);
+ mtx_unlock(&sc->done_mtx);
}
static int
g_disk_ioctl(struct g_provider *pp, u_long cmd, void * data, int fflag, struct thread *td)
{
- struct g_geom *gp;
struct disk *dp;
struct g_disk_softc *sc;
int error;
- gp = pp->geom;
- sc = gp->softc;
+ sc = pp->private;
dp = sc->dp;
if (dp->d_ioctl == NULL)
@@ -295,7 +270,7 @@ g_disk_start(struct bio *bp)
int error;
off_t off;
- sc = bp->bio_to->geom->softc;
+ sc = bp->bio_to->private;
if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
g_io_deliver(bp, ENXIO);
return;
@@ -496,6 +471,7 @@ g_disk_create(void *arg, int flag)
g_topology_assert();
dp = arg;
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
+ mtx_init(&sc->done_mtx, "g_disk_done", NULL, MTX_DEF);
sc->dp = dp;
gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit);
gp->softc = sc;
@@ -539,19 +515,22 @@ g_disk_providergone(struct g_provider *pp)
struct disk *dp;
struct g_disk_softc *sc;
- sc = (struct g_disk_softc *)pp->geom->softc;
-
- /*
- * If the softc is already NULL, then we've probably been through
- * g_disk_destroy already; there is nothing for us to do anyway.
- */
- if (sc == NULL)
- return;
-
+ sc = (struct g_disk_softc *)pp->private;
dp = sc->dp;
-
- if (dp->d_gone != NULL)
+ if (dp != NULL && dp->d_gone != NULL)
dp->d_gone(dp);
+ if (sc->sysctl_tree != NULL) {
+ sysctl_ctx_free(&sc->sysctl_ctx);
+ sc->sysctl_tree = NULL;
+ }
+ if (sc->led[0] != 0) {
+ led_set(sc->led, "0");
+ sc->led[0] = 0;
+ }
+ pp->private = NULL;
+ pp->geom->softc = NULL;
+ mtx_destroy(&sc->done_mtx);
+ g_free(sc);
}
static void
@@ -566,16 +545,9 @@ g_disk_destroy(void *ptr, int flag)
gp = dp->d_geom;
if (gp != NULL) {
sc = gp->softc;
- if (sc->sysctl_tree != NULL) {
- sysctl_ctx_free(&sc->sysctl_ctx);
- sc->sysctl_tree = NULL;
- }
- if (sc->led[0] != 0) {
- led_set(sc->led, "0");
- sc->led[0] = 0;
- }
- g_free(sc);
- gp->softc = NULL;
+ if (sc != NULL)
+ sc->dp = NULL;
+ dp->d_geom = NULL;
g_wither_geom(gp, ENXIO);
}
g_free(dp);
OpenPOWER on IntegriCloud