--- //depot/vendor/freebsd/src/sys/geom/geom.h 2009/06/30 14:35:13 +++ //depot/user/jhb/bio/geom/geom.h 2009/09/02 18:56:14 @@ -293,6 +293,9 @@ int g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length); int g_delete_data(struct g_consumer *cp, off_t offset, off_t length); void g_print_bio(struct bio *bp); +#if defined INVARIANTS || defined(INVARIANT_SUPPORT) +void g_check_bio(struct bio *bp); +#endif /* geom_kern.c / geom_kernsim.c */ --- //depot/vendor/freebsd/src/sys/geom/geom_disk.c 2009/04/10 04:15:21 +++ //depot/user/jhb/bio/geom/geom_disk.c 2009/09/02 18:56:14 @@ -267,7 +267,10 @@ do { bp2->bio_offset += off; bp2->bio_length -= off; - bp2->bio_data += off; + if (bp->bio_data != 0) + bp2->bio_data += off; + if (bp2->bio_sglist != NULL) + bp2->bio_start += off; if (bp2->bio_length > dp->d_maxsize) { /* * XXX: If we have a stripesize we should really @@ -289,6 +292,9 @@ bp2->bio_disk = dp; devstat_start_transaction_bio(dp->d_devstat, bp2); g_disk_lock_giant(dp); +#ifdef INVARIANTS + g_check_bio(bp2); +#endif dp->d_strategy(bp2); g_disk_unlock_giant(dp); bp2 = bp3; @@ -324,6 +330,9 @@ bp2->bio_done = g_disk_done; bp2->bio_disk = dp; g_disk_lock_giant(dp); +#ifdef INVARIANTS + g_check_bio(bp2); +#endif dp->d_strategy(bp2); g_disk_unlock_giant(dp); break; --- //depot/vendor/freebsd/src/sys/geom/geom_io.c 2009/06/30 14:35:13 +++ //depot/user/jhb/bio/geom/geom_io.c 2009/09/02 18:56:14 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -165,6 +166,8 @@ CTRSTACK(KTR_GEOM, &st, 3, 0); } #endif + if (bp->bio_sglist) + sglist_free(bp->bio_sglist); uma_zfree(biozone, bp); } @@ -180,6 +183,8 @@ bp2->bio_length = bp->bio_length; bp2->bio_offset = bp->bio_offset; bp2->bio_data = bp->bio_data; + if (bp->bio_sglist) + bp2->bio_sglist = sglist_hold(bp->bio_sglist); bp2->bio_attribute = bp->bio_attribute; /* Inherit classification info from the parent */ bp2->bio_classifier1 = bp->bio_classifier1; @@ -209,6 +214,8 @@ bp2->bio_length = bp->bio_length; bp2->bio_offset = bp->bio_offset; bp2->bio_data = bp->bio_data; + if (bp->bio_sglist) + bp2->bio_sglist = sglist_hold(bp->bio_sglist); bp2->bio_attribute = bp->bio_attribute; bp->bio_children++; #ifdef KTR @@ -413,11 +420,11 @@ #endif if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) { - KASSERT(bp->bio_data != NULL, + KASSERT(bp->bio_data != NULL || bp->bio_sglist != NULL, ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); } if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) { - KASSERT(bp->bio_data == NULL, + KASSERT(bp->bio_data == NULL && bp->bio_sglist == NULL, ("non-NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); } @@ -429,6 +436,9 @@ ("wrong length %jd for sectorsize %u", bp->bio_length, cp->provider->sectorsize)); } +#ifdef INVARIANTS + g_check_bio(bp); +#endif g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); @@ -786,3 +796,68 @@ } /* NOTREACHED */ } + +#ifdef INVARIANT_SUPPORT +void +g_check_bio(struct bio *bp) +{ + const char *cmd; + size_t space; + + space = 0; + if (bp->bio_sglist != NULL) + space = sglist_length(bp->bio_sglist); + + cmd = NULL; + switch (bp->bio_cmd) { + case BIO_GETATTR: + if (bp->bio_attribute == NULL) + panic("BIO_GETATTR with no attribute"); + if (bp->bio_length != 0 && bp->bio_data == NULL) + panic("BIO_GETATTR with no data"); + if (bp->bio_sglist) + panic("BIO_GETATTR with sglist"); + break; + case BIO_FLUSH: + if (bp->bio_attribute != NULL) + panic("BIO_FLUSH with attribute"); + if (bp->bio_data != NULL || bp->bio_length != 0 || + bp->bio_sglist != NULL) + panic("BIO_FLUSH with data"); + break; + case BIO_READ: + cmd = "BIO_READ"; + /* FALLTHROUGH */ + case BIO_WRITE: + if (cmd == NULL) + cmd = "BIO_WRITE"; + + if (bp->bio_attribute != NULL) + panic("%s with attribute", cmd); + if (bp->bio_length == 0) { + /* panic("%s with zero length", cmd); */ + } else { + if (bp->bio_data == NULL && bp->bio_sglist == NULL) + panic("%s with no data", cmd); + if (bp->bio_sglist != NULL && + (space < bp->bio_start + bp->bio_length)) + panic( + "%s sglist too short (bio_length %jd, bio_start %zd, sg %zd)", + cmd, (uintmax_t)bp->bio_length, + bp->bio_start, space); + } + break; + case BIO_DELETE: + if (bp->bio_attribute != NULL) + panic("BIO_DELETE with attribute"); + if (bp->bio_data != NULL || bp->bio_sglist != NULL) + panic("BIO_DELETE with data"); + if (bp->bio_length == 0) + panic("BIO_DELETE with zero length"); + break; + default: + panic("Unknown bio command %d", bp->bio_cmd); + break; + } +} +#endif --- //depot/vendor/freebsd/src/sys/sys/bio.h 2009/06/11 10:00:15 +++ //depot/user/jhb/bio/sys/bio.h 2009/09/02 18:56:14 @@ -42,6 +42,7 @@ struct disk; struct bio; +struct sglist; /* Empty classifier tag, to prevent further classification. */ #define BIO_NOTCLASSIFIED (void *)(~0UL) @@ -60,7 +61,9 @@ struct disk *bio_disk; /* Valid below geom_disk.c only */ off_t bio_offset; /* Offset into file. */ long bio_bcount; /* Valid bytes in buffer. */ + size_t bio_start; /* Offset into buffer. (XXX sgl only) */ caddr_t bio_data; /* Memory, superblocks, indirect etc. */ + struct sglist *bio_sglist; /* Scatter/gather list. */ int bio_error; /* Errno for BIO_ERROR. */ long bio_resid; /* Remaining I/O in bytes. */ void (*bio_done)(struct bio *); --- //depot/vendor/freebsd/src/sys/sys/bus_dma.h 2009/02/08 23:00:22 +++ //depot/user/jhb/bio/sys/bus_dma.h 2009/09/02 18:56:14 @@ -110,7 +110,8 @@ #define BUS_DMA_KEEP_PG_OFFSET 0x400 /* Forwards needed by prototypes below. */ +struct bio; struct mbuf; struct uio; /* @@ -231,6 +233,13 @@ void *callback_arg, int flags); /* + * Like bus_dmamap_load but takes a bio instead. + */ +int bus_dmamap_load_bio(bus_dma_tag_t dmat, bus_dmamap_t map, struct bio *bip, + bus_dmamap_callback_t *callback, void *callback_arg, + int flags); + +/* * Like bus_dmamap_load but for mbufs. Note the use of the * bus_dmamap_callback2_t interface. */