Index: sys/geom/eli/g_eli.c =================================================================== --- sys/geom/eli/g_eli.c +++ sys/geom/eli/g_eli.c @@ -972,6 +972,13 @@ */ pp = g_new_providerf(gp, "%s%s", bpp->name, G_ELI_SUFFIX); pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; + /* + * Don't use unmapped IO with data integrity verification. That module + * needs much more intimate access to the bio's data in order to + * add/remove HMAC fields, and split bios that exceed MAXPHYS. + */ + if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) + pp->flags |= G_PF_ACCEPT_UNMAPPED; pp->mediasize = sc->sc_mediasize; pp->sectorsize = sc->sc_sectorsize; LIST_FOREACH(gap, &bpp->aliases, ga_next) Index: sys/geom/eli/g_eli_privacy.c =================================================================== --- sys/geom/eli/g_eli_privacy.c +++ sys/geom/eli/g_eli_privacy.c @@ -98,8 +98,13 @@ */ if (bp->bio_inbed < bp->bio_children) return (0); - free(bp->bio_driver2, M_ELI); - bp->bio_driver2 = NULL; + MPASS(((bp->bio_flags & BIO_UNMAPPED) != 0) == + (bp->bio_driver2 != NULL)); + if (bp->bio_driver2 != NULL) { + g_io_bio_copyout(bp->bio_driver2, bp); + free(bp->bio_driver2, M_ELI); + bp->bio_driver2 = NULL; + } if (bp->bio_error != 0) { G_ELI_LOGREQ(0, bp, "Crypto READ request failed (error=%d).", bp->bio_error); @@ -166,7 +171,10 @@ atomic_subtract_int(&sc->sc_inflight, 1); return (0); } - cbp->bio_data = bp->bio_driver2; + if (bp->bio_driver2 != NULL) { + cbp->bio_data = bp->bio_driver2; + cbp->bio_flags &= ~BIO_UNMAPPED; + } cbp->bio_done = g_eli_write_done; cp = LIST_FIRST(&gp->consumer); cbp->bio_to = cp->provider; @@ -258,9 +266,20 @@ if (bp->bio_cmd == BIO_WRITE) { data = malloc(bp->bio_length, M_ELI, M_WAITOK); bp->bio_driver2 = data; - bcopy(bp->bio_data, data, bp->bio_length); - } else - data = bp->bio_data; + if ((bp->bio_flags & BIO_UNMAPPED) != 0) + g_io_bio_copyin(bp, data); + else + bcopy(bp->bio_data, data, bp->bio_length); + } else { + if ((bp->bio_flags & BIO_UNMAPPED) != 0) { + data = malloc(bp->bio_length, M_ELI, M_WAITOK); + bp->bio_driver2 = data; + g_io_bio_copyin(bp, data); + } else { + bp->bio_driver2 = NULL; + data = bp->bio_data; + } + } for (i = 0, dstoff = bp->bio_offset; i < nsec; i++, dstoff += secsize) { crp = crypto_getreq(wr->w_sid, M_WAITOK); Index: sys/geom/geom.h =================================================================== --- sys/geom/geom.h +++ sys/geom/geom.h @@ -417,6 +417,8 @@ }; \ DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); +void g_io_bio_copyin(struct bio *bp, void *kaddr); +void g_io_bio_copyout(void *kaddr, struct bio *bp); int g_is_geom_thread(struct thread *td); #ifndef _PATH_DEV Index: sys/geom/geom_io.c =================================================================== --- sys/geom/geom_io.c +++ sys/geom/geom_io.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -741,6 +742,48 @@ SYSCTL_INT(_kern_geom, OID_AUTO, inflight_transient_maps, CTLFLAG_RD, &inflight_transient_maps, 0, "Current count of the active transient maps"); + +static void +g_io_bio_copy(struct bio *bp, void *kaddr, bool in) +{ + struct uio uio; + struct iovec iov[1]; + + iov[0].iov_base = kaddr; + iov[0].iov_len = bp->bio_length; + uio.uio_iov = iov; + uio.uio_iovcnt = 1; + uio.uio_offset = 0; + uio.uio_resid = bp->bio_length; + uio.uio_segflg = UIO_SYSSPACE; + if (in) + uio.uio_rw = UIO_READ; + else + uio.uio_rw = UIO_WRITE; + uiomove_fromphys(bp->bio_ma, bp->bio_ma_offset, bp->bio_length, &uio); +} + +/* + * Copy data from a (potentially unmapped) bio to a kernelspace buffer. + * + * The buffer must have at least as much room as bp->bio_length. + */ +void +g_io_bio_copyin(struct bio *bp, void *kaddr) +{ + g_io_bio_copy(bp, kaddr, true); +} + +/* + * Copy data from a kernelspace buffer to a (potentially unmapped) bio + * + * The buffer must have at least as much room as bp->bio_length. + */ +void +g_io_bio_copyout(void *kaddr, struct bio *bp) +{ + g_io_bio_copy(bp, kaddr, false); +} static int g_io_transient_map_bio(struct bio *bp)