diff --git a/sys/geom/concat/g_concat.c b/sys/geom/concat/g_concat.c index 8838e1aca7e6..9dae373bffd7 100644 --- a/sys/geom/concat/g_concat.c +++ b/sys/geom/concat/g_concat.c @@ -211,6 +211,42 @@ g_concat_access(struct g_provider *pp, int dr, int dw, int de) return (error); } +static void +g_concat_flush(struct g_concat_softc *sc, struct bio *bp) +{ + struct bio_queue_head queue; + struct g_consumer *cp; + struct bio *cbp; + u_int no; + + bioq_init(&queue); + for (no = 0; no < sc->sc_ndisks; no++) { + cbp = g_clone_bio(bp); + if (cbp == NULL) { + for (cbp = bioq_first(&queue); cbp != NULL; + cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + 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_caller1 = sc->sc_disks[no].d_consumer; + cbp->bio_to = sc->sc_disks[no].d_consumer->provider; + } + for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + G_CONCAT_LOGREQ(cbp, "Sending request."); + cp = cbp->bio_caller1; + cbp->bio_caller1 = NULL; + g_io_request(cbp, cp); + } +} + static void g_concat_start(struct bio *bp) { @@ -240,6 +276,9 @@ g_concat_start(struct bio *bp) case BIO_WRITE: case BIO_DELETE: break; + case BIO_FLUSH: + g_concat_flush(sc, bp); + return; case BIO_GETATTR: /* To which provider it should be delivered? */ default: diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index 4c58fdd982b0..a1965b80bd85 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -258,6 +258,7 @@ g_eli_start(struct bio *bp) case BIO_READ: case BIO_WRITE: case BIO_GETATTR: + case BIO_FLUSH: break; case BIO_DELETE: /* @@ -298,6 +299,7 @@ g_eli_start(struct bio *bp) wakeup(sc); break; case BIO_GETATTR: + case BIO_FLUSH: cbp->bio_done = g_std_done; cp = LIST_FIRST(&sc->sc_geom->consumer); cbp->bio_to = cp->provider; diff --git a/sys/geom/geom_slice.c b/sys/geom/geom_slice.c index 2cf3385085da..c85e4a082b72 100644 --- a/sys/geom/geom_slice.c +++ b/sys/geom/geom_slice.c @@ -260,6 +260,8 @@ g_slice_start(struct bio *bp) gkd->length = gsp->slices[idx].length; /* now, pass it on downwards... */ } + /* FALLTHROUGH */ + case BIO_FLUSH: bp2 = g_clone_bio(bp); if (bp2 == NULL) { g_io_deliver(bp, ENOMEM); diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index fa956e25fb5b..f03da3bceaa9 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -1041,6 +1041,48 @@ g_mirror_kernel_dump(struct bio *bp) g_mirror_get_diskname(disk)); } +static void +g_mirror_flush(struct g_mirror_softc *sc, struct bio *bp) +{ + struct bio_queue_head queue; + struct g_mirror_disk *disk; + struct g_consumer *cp; + struct bio *cbp; + + bioq_init(&queue); + LIST_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_state != G_MIRROR_DISK_STATE_ACTIVE) + continue; + cbp = g_clone_bio(bp); + if (cbp == NULL) { + for (cbp = bioq_first(&queue); cbp != NULL; + cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + 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_caller1 = disk; + cbp->bio_to = disk->d_consumer->provider; + } + for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + G_MIRROR_LOGREQ(3, cbp, "Sending request."); + disk = cbp->bio_caller1; + cbp->bio_caller1 = NULL; + cp = disk->d_consumer; + KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, + ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, + cp->acr, cp->acw, cp->ace)); + g_io_request(cbp, disk->d_consumer); + } +} + static void g_mirror_start(struct bio *bp) { @@ -1061,6 +1103,9 @@ g_mirror_start(struct bio *bp) case BIO_WRITE: case BIO_DELETE: break; + case BIO_FLUSH: + g_mirror_flush(sc, bp); + return; case BIO_GETATTR: if (strcmp("GEOM::kerneldump", bp->bio_attribute) == 0) { g_mirror_kernel_dump(bp); diff --git a/sys/geom/raid3/g_raid3.c b/sys/geom/raid3/g_raid3.c index 66383bc8406c..3cb1c6c37db1 100644 --- a/sys/geom/raid3/g_raid3.c +++ b/sys/geom/raid3/g_raid3.c @@ -1369,6 +1369,50 @@ g_raid3_sync_done(struct bio *bp) mtx_unlock(&sc->sc_queue_mtx); } +static void +g_raid3_flush(struct g_raid3_softc *sc, struct bio *bp) +{ + struct bio_queue_head queue; + struct g_raid3_disk *disk; + struct g_consumer *cp; + struct bio *cbp; + u_int i; + + bioq_init(&queue); + for (i = 0; i < sc->sc_ndisks; i++) { + disk = &sc->sc_disks[i]; + if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) + continue; + cbp = g_clone_bio(bp); + if (cbp == NULL) { + for (cbp = bioq_first(&queue); cbp != NULL; + cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + 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_caller1 = disk; + cbp->bio_to = disk->d_consumer->provider; + } + for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + G_RAID3_LOGREQ(3, cbp, "Sending request."); + disk = cbp->bio_caller1; + cbp->bio_caller1 = NULL; + cp = disk->d_consumer; + KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, + ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, + cp->acr, cp->acw, cp->ace)); + g_io_request(cbp, disk->d_consumer); + } +} + static void g_raid3_start(struct bio *bp) { @@ -1390,6 +1434,9 @@ g_raid3_start(struct bio *bp) case BIO_WRITE: case BIO_DELETE: break; + case BIO_FLUSH: + g_raid3_flush(sc, bp); + return; case BIO_GETATTR: default: g_io_deliver(bp, EOPNOTSUPP); diff --git a/sys/geom/stripe/g_stripe.c b/sys/geom/stripe/g_stripe.c index 4f99ba425b5e..8f8de353fa48 100644 --- a/sys/geom/stripe/g_stripe.c +++ b/sys/geom/stripe/g_stripe.c @@ -519,6 +519,42 @@ g_stripe_start_economic(struct bio *bp, u_int no, off_t offset, off_t length) return (error); } +static void +g_stripe_flush(struct g_stripe_softc *sc, struct bio *bp) +{ + struct bio_queue_head queue; + struct g_consumer *cp; + struct bio *cbp; + u_int no; + + bioq_init(&queue); + for (no = 0; no < sc->sc_ndisks; no++) { + cbp = g_clone_bio(bp); + if (cbp == NULL) { + for (cbp = bioq_first(&queue); cbp != NULL; + cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + 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_caller1 = sc->sc_disks[no]; + cbp->bio_to = sc->sc_disks[no]->provider; + } + for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) { + bioq_remove(&queue, cbp); + G_STRIPE_LOGREQ(cbp, "Sending request."); + cp = cbp->bio_caller1; + cbp->bio_caller1 = NULL; + g_io_request(cbp, cp); + } +} + static void g_stripe_start(struct bio *bp) { @@ -542,10 +578,10 @@ g_stripe_start(struct bio *bp) case BIO_READ: case BIO_WRITE: case BIO_DELETE: - /* - * Only those requests are supported. - */ break; + case BIO_FLUSH: + g_stripe_flush(sc, bp); + return; case BIO_GETATTR: /* To which provider it should be delivered? */ default: