summaryrefslogtreecommitdiffstats
path: root/sys/geom/mirror
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2014-01-07 01:32:23 +0000
committerscottl <scottl@FreeBSD.org>2014-01-07 01:32:23 +0000
commit0a34594b9cd7c8b87f719ed058da6be2b756a8e5 (patch)
tree9702de6a6a50f2bb1a6829d66c26686ca7a160cc /sys/geom/mirror
parent1bce546983c144fd6d05af45e88abd3186b87b1b (diff)
downloadFreeBSD-src-0a34594b9cd7c8b87f719ed058da6be2b756a8e5.zip
FreeBSD-src-0a34594b9cd7c8b87f719ed058da6be2b756a8e5.tar.gz
MFC Alexander Motin's GEOM direct dispatch work:
r256603: Introduce new function devstat_end_transaction_bio_bt(), adding new argument to specify present time. Use this function to move binuptime() out of lock, substantially reducing lock congestion when slow timecounter is used. r256606: Move g_io_deliver() out of the lock, as required for direct dispatch. Move g_destroy_bio() out too to reduce lock scope even more. r256607: Fix passing uninitialized bio_resid argument to g_trace(). r256610: Add unmapped I/O support to GEOM RAID. r256830: Restore BIO_UNMAPPED and BIO_TRANSIENT_MAPPING in biodonne() when unmapping temporary mapped buffer. That fixes double unmap if biodone() called twice for the same BIO (but with different done methods). r256880: Merge GEOM direct dispatch changes from the projects/camlock branch. When safety requirements are met, it allows to avoid passing I/O requests to GEOM g_up/g_down thread, executing them directly in the caller context. That allows to avoid CPU bottlenecks in g_up/g_down threads, plus avoid several context switches per I/O. r259247: Fix bug introduced at r256607. We have to recalculate bp_resid here since sizes of original and completed requests may differ due to end of media. Testing of the stable/10 merge was done by Netflix, but all of the credit goes to Alexander and iX Systems. Submitted by: mav Sponsored by: iX Systems
Diffstat (limited to 'sys/geom/mirror')
-rw-r--r--sys/geom/mirror/g_mirror.c58
-rw-r--r--sys/geom/mirror/g_mirror.h2
2 files changed, 37 insertions, 23 deletions
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c
index 04233fe..b4be912 100644
--- a/sys/geom/mirror/g_mirror.c
+++ b/sys/geom/mirror/g_mirror.c
@@ -394,6 +394,7 @@ g_mirror_connect_disk(struct g_mirror_disk *disk, struct g_provider *pp)
g_topology_lock();
cp = g_new_consumer(disk->d_softc->sc_geom);
+ cp->flags |= G_CF_DIRECT_RECEIVE;
error = g_attach(cp, pp);
if (error != 0) {
g_destroy_consumer(cp);
@@ -554,6 +555,7 @@ g_mirror_destroy_device(struct g_mirror_softc *sc)
g_topology_unlock();
mtx_destroy(&sc->sc_queue_mtx);
mtx_destroy(&sc->sc_events_mtx);
+ mtx_destroy(&sc->sc_done_mtx);
sx_xunlock(&sc->sc_lock);
sx_destroy(&sc->sc_lock);
}
@@ -852,6 +854,27 @@ g_mirror_unidle(struct g_mirror_softc *sc)
}
static void
+g_mirror_flush_done(struct bio *bp)
+{
+ struct g_mirror_softc *sc;
+ struct bio *pbp;
+
+ pbp = bp->bio_parent;
+ sc = pbp->bio_to->geom->softc;
+ mtx_lock(&sc->sc_done_mtx);
+ if (pbp->bio_error == 0)
+ pbp->bio_error = bp->bio_error;
+ pbp->bio_completed += bp->bio_completed;
+ pbp->bio_inbed++;
+ if (pbp->bio_children == pbp->bio_inbed) {
+ mtx_unlock(&sc->sc_done_mtx);
+ g_io_deliver(pbp, pbp->bio_error);
+ } else
+ mtx_unlock(&sc->sc_done_mtx);
+ g_destroy_bio(bp);
+}
+
+static void
g_mirror_done(struct bio *bp)
{
struct g_mirror_softc *sc;
@@ -1037,23 +1060,19 @@ g_mirror_flush(struct g_mirror_softc *sc, struct bio *bp)
continue;
cbp = g_clone_bio(bp);
if (cbp == NULL) {
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL)
g_destroy_bio(cbp);
- }
if (bp->bio_error == 0)
bp->bio_error = ENOMEM;
g_io_deliver(bp, bp->bio_error);
return;
}
bioq_insert_tail(&queue, cbp);
- cbp->bio_done = g_std_done;
+ cbp->bio_done = g_mirror_flush_done;
cbp->bio_caller1 = disk;
cbp->bio_to = disk->d_consumer->provider;
}
- for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL) {
G_MIRROR_LOGREQ(3, cbp, "Sending request.");
disk = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
@@ -1538,11 +1557,8 @@ g_mirror_request_split(struct g_mirror_softc *sc, struct bio *bp)
continue;
cbp = g_clone_bio(bp);
if (cbp == NULL) {
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
+ while ((cbp = bioq_takefirst(&queue)) != NULL)
bioq_remove(&queue, cbp);
- g_destroy_bio(cbp);
- }
if (bp->bio_error == 0)
bp->bio_error = ENOMEM;
g_io_deliver(bp, bp->bio_error);
@@ -1561,8 +1577,7 @@ g_mirror_request_split(struct g_mirror_softc *sc, struct bio *bp)
offset += cbp->bio_length;
data += cbp->bio_length;
}
- for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL) {
G_MIRROR_LOGREQ(3, cbp, "Sending request.");
disk = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
@@ -1643,11 +1658,8 @@ g_mirror_register_request(struct bio *bp)
continue;
cbp = g_clone_bio(bp);
if (cbp == NULL) {
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL)
g_destroy_bio(cbp);
- }
if (bp->bio_error == 0)
bp->bio_error = ENOMEM;
g_io_deliver(bp, bp->bio_error);
@@ -1662,9 +1674,7 @@ g_mirror_register_request(struct bio *bp)
("Consumer %s not opened (r%dw%de%d).",
cp->provider->name, cp->acr, cp->acw, cp->ace));
}
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL) {
G_MIRROR_LOGREQ(3, cbp, "Sending request.");
cp = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
@@ -1920,6 +1930,7 @@ g_mirror_sync_start(struct g_mirror_disk *disk)
sx_xunlock(&sc->sc_lock);
g_topology_lock();
cp = g_new_consumer(sc->sc_sync.ds_geom);
+ cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
error = g_attach(cp, sc->sc_provider);
KASSERT(error == 0,
("Cannot attach to %s (error=%d).", sc->sc_name, error));
@@ -2034,6 +2045,7 @@ g_mirror_launch_provider(struct g_mirror_softc *sc)
g_topology_lock();
pp = g_new_providerf(sc->sc_geom, "mirror/%s", sc->sc_name);
+ pp->flags |= G_PF_DIRECT_RECEIVE;
pp->mediasize = sc->sc_mediasize;
pp->sectorsize = sc->sc_sectorsize;
pp->stripesize = 0;
@@ -2082,10 +2094,8 @@ g_mirror_destroy_provider(struct g_mirror_softc *sc)
g_topology_lock();
g_error_provider(sc->sc_provider, ENXIO);
mtx_lock(&sc->sc_queue_mtx);
- while ((bp = bioq_first(&sc->sc_queue)) != NULL) {
- bioq_remove(&sc->sc_queue, bp);
+ while ((bp = bioq_takefirst(&sc->sc_queue)) != NULL)
g_io_deliver(bp, ENXIO);
- }
mtx_unlock(&sc->sc_queue_mtx);
G_MIRROR_DEBUG(0, "Device %s: provider %s destroyed.", sc->sc_name,
sc->sc_provider->name);
@@ -2896,6 +2906,7 @@ g_mirror_create(struct g_class *mp, const struct g_mirror_metadata *md)
TAILQ_INIT(&sc->sc_events);
mtx_init(&sc->sc_events_mtx, "gmirror:events", NULL, MTX_DEF);
callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
+ mtx_init(&sc->sc_done_mtx, "gmirror:done", NULL, MTX_DEF);
sc->sc_state = G_MIRROR_DEVICE_STATE_STARTING;
gp->softc = sc;
sc->sc_geom = gp;
@@ -2914,6 +2925,7 @@ g_mirror_create(struct g_class *mp, const struct g_mirror_metadata *md)
G_MIRROR_DEBUG(1, "Cannot create kernel thread for %s.",
sc->sc_name);
g_destroy_geom(sc->sc_sync.ds_geom);
+ mtx_destroy(&sc->sc_done_mtx);
mtx_destroy(&sc->sc_events_mtx);
mtx_destroy(&sc->sc_queue_mtx);
sx_destroy(&sc->sc_lock);
diff --git a/sys/geom/mirror/g_mirror.h b/sys/geom/mirror/g_mirror.h
index 44ea18a..96270c8 100644
--- a/sys/geom/mirror/g_mirror.h
+++ b/sys/geom/mirror/g_mirror.h
@@ -212,6 +212,8 @@ struct g_mirror_softc {
struct callout sc_callout;
struct root_hold_token *sc_rootmount;
+
+ struct mtx sc_done_mtx;
};
#define sc_name sc_geom->name
OpenPOWER on IntegriCloud