Add the MPIPE subsystem. This subsystem is used for 'pipelining' fixed-size
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 30 Nov 2003 20:14:18 +0000 (20:14 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 30 Nov 2003 20:14:18 +0000 (20:14 +0000)
allocations.  Pipelining is used to avoid lack-of-resource deadlocks by
still allowing resource allocations to 'block' by guarenteeing that an
already in-progress operation will soon free memory that will be immediately
used to satisfy the blocked resource.

Adjust the ATAold code to use the new mechanism and remove the code that
tried to back-off into PIO mode when resources were lacking.

15 files changed:
sys/conf/files
sys/dev/disk/ata/ata-all.c
sys/dev/disk/ata/ata-all.h
sys/dev/disk/ata/ata-disk.c
sys/dev/disk/ata/ata-dma.c
sys/dev/disk/ata/ata-isa.c
sys/dev/disk/ata/ata-raid.c
sys/dev/disk/ata/atapi-all.c
sys/dev/disk/ata/atapi-cam.c
sys/dev/disk/ata/atapi-cd.c
sys/dev/disk/ata/atapi-fd.c
sys/dev/disk/ata/atapi-tape.c
sys/kern/kern_mpipe.c [new file with mode: 0644]
sys/sys/malloc.h
sys/sys/mpipe.h [new file with mode: 0644]

index d78be7a..1a5249c 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/sys/conf/files,v 1.30 2003/11/21 05:29:05 dillon Exp $
+# $DragonFly: src/sys/conf/files,v 1.31 2003/11/30 20:13:51 dillon Exp $
 #
 # The long compile-with and dependency lines are required because of
 # limitations in config: backslash-newline doesn't work in strings, and
@@ -627,6 +627,7 @@ kern/kern_prot.c    standard
 kern/kern_random.c     standard
 kern/kern_resource.c   standard
 kern/kern_slaballoc.c  standard
+kern/kern_mpipe.c      standard
 kern/kern_shutdown.c   standard
 kern/kern_sig.c                standard
 kern/kern_upcall.c     standard
index e459d5b..64297f6 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/ata-all.c,v 1.50.2.45 2003/03/12 14:47:12 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/ata-all.c,v 1.8 2003/11/09 02:22:34 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/ata-all.c,v 1.9 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include "opt_ata.h"
 #include "ata-raid.h"
 #include "atapi-all.h"
 
+union ata_request {
+       struct ad_request       ad;
+       struct atapi_request    atapi;
+};
+
 /* device structures */
 static d_ioctl_t       ataioctl;
 static struct cdevsw ata_cdevsw = {  
@@ -97,6 +102,12 @@ static int ata_enclosure_status(struct ata_device *, int *, int *, int *, int *)
 /* sysctl vars */
 SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters");
 
+int ata_mpipe_size = 4;
+TUNABLE_INT("hw.ata.mpipe_size", &ata_mpipe_size);
+SYSCTL_INT(_hw_ata, OID_AUTO, mpipe_size, CTLFLAG_RW, &ata_mpipe_size, 0,
+           "ATA global I/O pipeline max size");
+
+
 /* global vars */
 devclass_t ata_devclass;
 
@@ -155,6 +166,10 @@ ata_probe(device_t dev)
     ch->device[SLAVE].mode = ATA_PIO;
     TAILQ_INIT(&ch->ata_queue);
     TAILQ_INIT(&ch->atapi_queue);
+
+    mpipe_init(&ch->req_mpipe, M_ATA, sizeof(union ata_request), 4, ata_mpipe_size);
+    mpipe_init(&ch->dma_mpipe, M_DEVBUF, PAGE_SIZE, 4, ata_mpipe_size);
+
     return 0;
     
 failure:
@@ -286,6 +301,9 @@ ata_detach(device_t dev)
     ch->r_altio = NULL;
     ch->r_bmio = NULL;
     ch->r_irq = NULL;
+    mpipe_done(&ch->req_mpipe);
+    mpipe_done(&ch->dma_mpipe);
+
     ATA_UNLOCK_CH(ch);
     return 0;
 }
@@ -435,7 +453,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
                                 ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE)))
                return ENODEV;
 
-           if (!(buf = malloc(iocmd->u.atapi.count, M_ATA, M_NOWAIT)))
+           if (!(buf = malloc(iocmd->u.atapi.count, M_ATA, M_WAITOK)))
                return ENOMEM;
 
            if (iocmd->u.atapi.flags & ATAPI_CMD_WRITE) {
@@ -473,7 +491,7 @@ ata_getparam(struct ata_device *atadev, u_int8_t command)
     struct ata_params *ata_parm;
     int retry = 0;
 
-    if (!(ata_parm = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT))) {
+    if (!(ata_parm = malloc(sizeof(struct ata_params), M_ATA, M_WAITOK))) {
        ata_prtdev(atadev, "malloc for identify data failed\n");
        return -1;
     }
@@ -1400,7 +1418,7 @@ ata_prtdev(struct ata_device *atadev, const char * fmt, ...)
 void
 ata_set_name(struct ata_device *atadev, char *name, int lun)
 {
-    atadev->name = malloc(strlen(name) + 4, M_ATA, M_NOWAIT);
+    atadev->name = malloc(strlen(name) + 4, M_ATA, M_WAITOK);
     if (atadev->name)
        sprintf(atadev->name, "%s%d", name, lun);
 }
@@ -1559,7 +1577,7 @@ ata_init(void)
     /* register boot attach to be run when interrupts are enabled */
     if (!(ata_delayed_attach = (struct intr_config_hook *)
                               malloc(sizeof(struct intr_config_hook),
-                                     M_TEMP, M_NOWAIT | M_ZERO))) {
+                                     M_TEMP, M_WAITOK | M_ZERO))) {
        printf("ata: malloc of delayed attach hook failed\n");
        return;
     }
index c6c1c8a..fbebbf6 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/ata-all.h,v 1.26.2.12 2003/01/30 07:19:59 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/ata-all.h,v 1.3 2003/07/19 21:14:18 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/ata-all.h,v 1.4 2003/11/30 20:14:18 dillon Exp $
  */
 
+#ifndef _SYS_MPIPE_H_
+#include <sys/mpipe.h>
+#endif
+
 /* ATA register defines */
 #define ATA_DATA                       0x00    /* data register */
 #define ATA_ERROR                      0x01    /* (R) error register */
@@ -225,6 +229,8 @@ struct ata_channel {
     TAILQ_HEAD(, ad_request)   ata_queue;      /* head of ATA queue */
     TAILQ_HEAD(, atapi_request) atapi_queue;   /* head of ATAPI queue */
     void                       *running;       /* currently running request */
+    struct malloc_pipe         req_mpipe;      /* request allocations */
+    struct malloc_pipe         dma_mpipe;      /* dma allocations */
 };
 
 /* disk bay/enclosure related */
@@ -236,6 +242,7 @@ struct ata_channel {
 
 /* externs */
 extern devclass_t ata_devclass;
+extern int     ata_mpipe_size;
  
 /* public prototypes */
 int ata_probe(device_t);
@@ -263,7 +270,8 @@ int ata_wmode(struct ata_params *);
 int ata_umode(struct ata_params *);
 int ata_find_dev(device_t, u_int32_t, u_int32_t);
 
-void *ata_dmaalloc(struct ata_channel *, int);
+void *ata_dmaalloc(struct ata_channel *, int, int);
+void ata_dmafree(struct ata_channel *, void *buf);
 void ata_dmainit(struct ata_channel *, int, int, int, int);
 int ata_dmasetup(struct ata_channel *, int, struct ata_dmaentry *, caddr_t, int);
 void ata_dmastart(struct ata_channel *, int, struct ata_dmaentry *, int);
index 235a828..71de56f 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/ata-disk.c,v 1.60.2.24 2003/01/30 07:19:59 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/ata-disk.c,v 1.7 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/ata-disk.c,v 1.8 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include "opt_ata.h"
@@ -115,10 +115,13 @@ ad_attach(struct ata_device *atadev)
     struct ad_softc *adp;
     dev_t dev;
 
-    if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) {
+    if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_WAITOK | M_ZERO))) {
        ata_prtdev(atadev, "failed to allocate driver storage\n");
        return;
     }
+
+    KKASSERT(atadev->channel->req_mpipe.max_count != 0);
+
     adp->device = atadev;
 #ifdef ATA_STATIC_ID
     adp->lun = (device_get_unit(atadev->channel->dev)<<1)+ATA_DEV(atadev->unit);
@@ -397,8 +400,14 @@ ad_start(struct ata_device *atadev)
            return;
     }
 
-    if (!(request = malloc(sizeof(struct ad_request), M_AD, M_NOWAIT|M_ZERO))) {
-       ata_prtdev(atadev, "out of memory in start\n");
+    /*
+     * Allocate a request.  The allocation can only fail if the pipeline
+     * is full, in which case the request will be picked up later when
+     * ad_start() is called after another request completes.
+     */
+    request = mpipe_alloc(&atadev->channel->req_mpipe, M_NOWAIT|M_ZERO);
+    if (request == NULL) {
+       ata_prtdev(atadev, "pipeline full allocating request in ad_start\n");
        return;
     }
 
@@ -412,8 +421,13 @@ ad_start(struct ata_device *atadev)
     if (bp->b_flags & B_READ) 
        request->flags |= ADR_F_READ;
     if (adp->device->mode >= ATA_DMA) {
-       if (!(request->dmatab = ata_dmaalloc(atadev->channel, atadev->unit)))
-           adp->device->mode = ATA_PIO;
+       request->dmatab = ata_dmaalloc(atadev->channel, atadev->unit, M_NOWAIT);
+       if (request->dmatab == NULL) {
+           mpipe_free(&atadev->channel->req_mpipe, request);
+           ata_prtdev(atadev, "pipeline full allocated dmabuf in ad_start\n");
+           /* do not revert to PIO, wait for ad_start after I/O completion */
+           return;
+       }
     }
 
     /* insert in tag array */
@@ -804,9 +818,9 @@ ad_free(struct ad_request *request)
     int s = splbio();
 
     if (request->dmatab)
-       free(request->dmatab, M_DEVBUF);
+       ata_dmafree(request->softc->device->channel, request->dmatab);
     request->softc->tags[request->tag] = NULL;
-    free(request, M_AD);
+    mpipe_free(&request->softc->device->channel->req_mpipe, request);
     splx(s);
 }
 
index 6d56be7..611fa73 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/ata-dma.c,v 1.35.2.31 2003/05/07 16:46:11 jhb Exp $
- * $DragonFly: src/sys/dev/disk/ata/ata-dma.c,v 1.5 2003/11/26 14:24:46 asmodai Exp $
+ * $DragonFly: src/sys/dev/disk/ata/ata-dma.c,v 1.6 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -34,6 +34,7 @@
 #include <sys/ata.h>
 #include <sys/buf.h>
 #include <sys/malloc.h> 
+#include <sys/mpipe.h> 
 #include <sys/bus.h>
 #include <sys/disk.h>
 #include <sys/devicestat.h>
@@ -60,19 +61,21 @@ static int hpt_cable80(struct ata_channel *);
         (device == ATA_SLAVE && ch->devices & ATA_ATAPI_SLAVE))
 
 void *
-ata_dmaalloc(struct ata_channel *ch, int device)
+ata_dmaalloc(struct ata_channel *ch, int device, int flags)
 {
     void *dmatab;
 
-    if ((dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT))) {
-       if (((uintptr_t)dmatab >> PAGE_SHIFT) ^
-           (((uintptr_t)dmatab + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
-           ata_printf(ch, device, "dmatab crosses page boundary, no DMA\n");
-           free(dmatab, M_DEVBUF);
-           dmatab = NULL;
-       }
-    }
-    return dmatab;
+    KKASSERT(ch->dma_mpipe.max_count != 0);
+    dmatab = mpipe_alloc(&ch->dma_mpipe, flags);
+    KKASSERT(((uintptr_t)dmatab & PAGE_MASK) == 0);
+    return (dmatab);
+}
+
+void
+ata_dmafree(struct ata_channel *ch, void *dmatab)
+{
+    if (dmatab)
+       mpipe_free(&ch->dma_mpipe, dmatab);
 }
 
 void
index 45d64f1..b818f80 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/ata-isa.c,v 1.4.2.1 2002/03/18 08:37:33 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/ata-isa.c,v 1.3 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/ata-isa.c,v 1.4 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -109,11 +109,16 @@ DRIVER_MODULE(ata, isa, ata_isa_driver, ata_devclass, 0, 0);
 #include "use_pci.h"
 #if NPCI == 0
 void *
-ata_dmaalloc(struct ata_channel *ch, int device)
+ata_dmaalloc(struct ata_channel *ch, int device, int flags)
 {
     return 0;
 }
 
+void
+ata_dmafree(struct ata_channel *ch, void *dmatab)
+{
+}
+
 void
 ata_dmainit(struct ata_channel *ch, int device,
            int piomode, int wdmamode, int udmamode)
index eee00df..a222672 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/ata-raid.c,v 1.3.2.19 2003/01/30 07:19:59 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/ata-raid.c,v 1.8 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/ata-raid.c,v 1.9 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include "opt_ata.h"
@@ -116,7 +116,7 @@ ata_raiddisk_attach(struct ad_softc *adp)
 
     if (!ar_table)
        ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
-                         M_AR, M_NOWAIT | M_ZERO);
+                         M_AR, M_WAITOK | M_ZERO);
     if (!ar_table) {
        ata_prtdev(adp->device, "no memory for ATA raid array\n");
        return 0;
@@ -250,7 +250,7 @@ ata_raid_create(struct raid_setup *setup)
 
     if (!ar_table)
        ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
-                         M_AR, M_NOWAIT | M_ZERO);
+                         M_AR, M_WAITOK | M_ZERO);
     if (!ar_table) {
        printf("ar: no memory for ATA raid array\n");
        return 0;
@@ -263,7 +263,7 @@ ata_raid_create(struct raid_setup *setup)
        return ENOSPC;
 
     if (!(rdp = (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
-                                        M_NOWAIT | M_ZERO))) {
+                                        M_WAITOK | M_ZERO))) {
        printf("ar%d: failed to allocate raid config storage\n", array);
        return ENOMEM;
     }
@@ -550,7 +550,7 @@ arstrategy(struct buf *bp)
            return;
        }
 
-       buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO);
+       buf1 = malloc(sizeof(struct ar_buf), M_AR, M_WAITOK | M_ZERO);
        BUF_LOCKINIT(&buf1->bp);
        BUF_LOCK(&buf1->bp, LK_EXCLUSIVE);
        buf1->bp.b_pblkno = lba;
@@ -631,7 +631,7 @@ arstrategy(struct buf *bp)
                        ((rdp->flags & AR_F_REBUILDING) &&
                         (rdp->disks[buf1->drive].flags & AR_DF_SPARE) &&
                         buf1->bp.b_pblkno < rdp->lock_start)) {
-                       buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT);
+                       buf2 = malloc(sizeof(struct ar_buf), M_AR, M_WAITOK);
                        bcopy(buf1, buf2, sizeof(struct ar_buf));
                        BUF_LOCKINIT(&buf2->bp);
                        BUF_LOCK(&buf2->bp, LK_EXCLUSIVE);
@@ -827,7 +827,7 @@ ar_rebuild(struct ar_softc *rdp)
     rdp->lock_end = rdp->lock_start + 256;
     rdp->flags |= AR_F_REBUILDING;
     splx(s);
-    buffer = malloc(256 * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO);
+    buffer = malloc(256 * DEV_BSIZE, M_AR, M_WAITOK | M_ZERO);
 
     /* now go copy entire disk(s) */
     while (rdp->lock_end < (rdp->total_sectors / rdp->width)) {
@@ -896,7 +896,7 @@ ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
     int array, disk_number = 0, retval = 0;
 
     if (!(info = (struct highpoint_raid_conf *)
-         malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
+         malloc(sizeof(struct highpoint_raid_conf), M_AR, M_WAITOK | M_ZERO)))
        return retval;
 
     if (ar_rw(adp, HPT_LBA, sizeof(struct highpoint_raid_conf),
@@ -925,7 +925,7 @@ ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
        if (!raidp[array]) {
            raidp[array] = 
                (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
-                                        M_NOWAIT | M_ZERO);
+                                        M_WAITOK | M_ZERO);
            if (!raidp[array]) {
                printf("ar%d: failed to allocate raid config storage\n", array);
                goto highpoint_out;
@@ -1045,7 +1045,7 @@ ar_highpoint_write_conf(struct ar_softc *rdp)
     for (disk = 0; disk < rdp->total_disks; disk++) {
        if (!(config = (struct highpoint_raid_conf *)
              malloc(sizeof(struct highpoint_raid_conf),
-                    M_AR, M_NOWAIT | M_ZERO))) {
+                    M_AR, M_WAITOK | M_ZERO))) {
            printf("ar%d: Highpoint write conf failed\n", rdp->lun);
            return -1;
        }
@@ -1125,7 +1125,7 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
     int array, count, disk, disksum = 0, retval = 0; 
 
     if (!(info = (struct promise_raid_conf *)
-         malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
+         malloc(sizeof(struct promise_raid_conf), M_AR, M_WAITOK | M_ZERO)))
        return retval;
 
     if (ar_rw(adp, PR_LBA(adp), sizeof(struct promise_raid_conf),
@@ -1171,7 +1171,7 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
        if (!raidp[array]) {
            raidp[array] = 
                (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
-                                        M_NOWAIT | M_ZERO);
+                                        M_WAITOK | M_ZERO);
            if (!raidp[array]) {
                printf("ar%d: failed to allocate raid config storage\n", array);
                goto promise_out;
@@ -1286,7 +1286,7 @@ ar_promise_write_conf(struct ar_softc *rdp)
 
     for (disk = 0; disk < rdp->total_disks; disk++) {
        if (!(config = (struct promise_raid_conf *)
-             malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) {
+             malloc(sizeof(struct promise_raid_conf), M_AR, M_WAITOK))) {
            printf("ar%d: %s write conf failed\n",
                   rdp->lun, local ? "FreeBSD" : "Promise");
            return -1;
@@ -1411,7 +1411,7 @@ ar_rw(struct ad_softc *adp, u_int32_t lba, int count, caddr_t data, int flags)
     struct buf *bp;
     int retry = 0, error = 0;
 
-    if (!(bp = (struct buf *)malloc(sizeof(struct buf), M_AR, M_NOWAIT|M_ZERO)))
+    if (!(bp = (struct buf *)malloc(sizeof(struct buf), M_AR, M_WAITOK|M_ZERO)))
        return ENOMEM;
     BUF_LOCKINIT(bp);
     BUF_LOCK(bp, LK_EXCLUSIVE);
index 52c69ad..379c37a 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/atapi-all.c,v 1.46.2.18 2002/10/31 23:10:33 thomas Exp $
- * $DragonFly: src/sys/dev/disk/ata/atapi-all.c,v 1.4 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/atapi-all.c,v 1.5 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include "opt_ata.h"
@@ -94,7 +94,7 @@ atapi_attach(struct ata_device *atadev)
     ATA_UNLOCK_CH(atadev->channel);
 
     if (!(atadev->result = malloc(sizeof(struct atapi_reqsense), M_ATAPI,
-                                 M_NOWAIT | M_ZERO)))
+                                 M_WAITOK | M_ZERO)))
        ata_prtdev(atadev, "no memory for sense data\n");
 
     switch (atadev->param->type) {
@@ -162,7 +162,7 @@ atapi_detach(struct ata_device *atadev)
            biodone(bp);
        }
        if (request->dmatab)
-           free(request->dmatab, M_DEVBUF);
+           ata_dmafree(atadev->channel, request->dmatab);
        free(request, M_ATAPI);
     }
     free(atadev->result, M_ATAPI);
@@ -178,10 +178,12 @@ atapi_queue_cmd(struct ata_device *atadev, int8_t *ccb, caddr_t data,
 {
     struct atapi_request *request;
     int error, s;
-    if (!(request = malloc(sizeof(struct atapi_request), M_ATAPI,
-                          M_NOWAIT | M_ZERO)))
-       return ENOMEM;
+
+    request = malloc(sizeof(struct atapi_request), M_ATAPI, M_NOWAIT|M_ZERO);
+    if (request == NULL) {
+       printf("WARNNIG: atapi_queue_cmd: malloc() would block\n");
+       request = malloc(sizeof(struct atapi_request), M_ATAPI, M_WAITOK|M_ZERO);
+    }
 
     request->device = atadev;
     request->data = data;
@@ -196,8 +198,12 @@ atapi_queue_cmd(struct ata_device *atadev, int8_t *ccb, caddr_t data,
        request->driver = driver;
     }
     if (atadev->mode >= ATA_DMA) {
-       if (!(request->dmatab = ata_dmaalloc(atadev->channel, atadev->unit)))
-           atadev->mode = ATA_PIO;
+       request->dmatab = ata_dmaalloc(atadev->channel, atadev->unit, M_NOWAIT);
+       if (request->dmatab == NULL) {
+           printf("WARNING: atapi_queue_cmd: ata_dmaalloc() would block\n");
+           request->dmatab = ata_dmaalloc(atadev->channel,
+                                       atadev->unit, M_WAITOK);
+       }
     }
 
 #ifdef ATAPI_DEBUG
@@ -226,7 +232,7 @@ atapi_queue_cmd(struct ata_device *atadev, int8_t *ccb, caddr_t data,
     if (error)
         bcopy(&request->sense, atadev->result, sizeof(struct atapi_reqsense));
     if (request->dmatab)
-       free(request->dmatab, M_DEVBUF);
+       ata_dmafree(atadev->channel, request->dmatab);
     free(request, M_ATAPI);
     return error;
 }
@@ -606,7 +612,7 @@ atapi_finish(struct atapi_request *request)
     if (request->callback) {
        if (!((request->callback)(request))) {
            if (request->dmatab)
-               free(request->dmatab, M_DEVBUF);
+               ata_dmafree(request->device->channel, request->dmatab);
            free(request, M_ATAPI);
        }
     }
index aa03c6d..731eea3 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/atapi-cam.c,v 1.10.2.3 2003/05/21 09:24:55 thomas Exp $
- * $DragonFly: src/sys/dev/disk/ata/atapi-cam.c,v 1.3 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/atapi-cam.c,v 1.4 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -119,7 +119,7 @@ atapi_cam_attach_bus(struct ata_channel *ata_ch)
     }
 
     if ((scp = malloc(sizeof(struct atapi_xpt_softc),
-                     M_ATACAM, M_NOWAIT | M_ZERO)) == NULL)
+                     M_ATACAM, M_WAITOK | M_ZERO)) == NULL)
        goto error;
 
     scp->ata_ch = ata_ch;
@@ -481,7 +481,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
        if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN && (len & 1)) {
            /* ATA always transfers an even number of bytes */
            if (!(buf = hcb->dxfer_alloc = malloc(++len, M_ATACAM,
-                                                 M_NOWAIT | M_ZERO)))
+                                                 M_WAITOK | M_ZERO)))
                goto action_oom;
        }
        s = splbio();
@@ -652,7 +652,7 @@ static struct atapi_hcb *
 allocate_hcb(struct atapi_xpt_softc *softc, int unit, int bus, union ccb *ccb)
 {
     struct atapi_hcb *hcb = (struct atapi_hcb *)
-    malloc(sizeof(struct atapi_hcb), M_ATACAM, M_NOWAIT | M_ZERO);
+    malloc(sizeof(struct atapi_hcb), M_ATACAM, M_WAITOK | M_ZERO);
 
     if (hcb != NULL) {
        hcb->softc = softc;
index 7fdb6da..533efc8 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/atapi-cd.c,v 1.48.2.20 2002/11/25 05:30:31 njl Exp $
- * $DragonFly: src/sys/dev/disk/ata/atapi-cd.c,v 1.8 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/atapi-cd.c,v 1.9 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include "opt_ata.h"
@@ -132,7 +132,7 @@ acdattach(struct ata_device *atadev)
                           sizeof(struct changer)>>8, sizeof(struct changer),
                           0, 0, 0, 0, 0, 0 };
 
-       chp = malloc(sizeof(struct changer), M_ACD, M_NOWAIT | M_ZERO);
+       chp = malloc(sizeof(struct changer), M_ACD, M_WAITOK | M_ZERO);
        if (chp == NULL) {
            ata_prtdev(atadev, "out of memory\n");
            free(cdp, M_ACD);
@@ -148,7 +148,7 @@ acdattach(struct ata_device *atadev)
 
            chp->table_length = htons(chp->table_length);
            if (!(cdparr = malloc(sizeof(struct acd_softc) * chp->slots,
-                                 M_ACD, M_NOWAIT))) {
+                                 M_ACD, M_WAITOK))) {
                ata_prtdev(atadev, "out of memory\n");
                free(chp, M_ACD);
                free(cdp, M_ACD);
@@ -172,7 +172,7 @@ acdattach(struct ata_device *atadev)
                                  DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
                                  DEVSTAT_PRIORITY_CD);
            }
-           name = malloc(strlen(atadev->name) + 2, M_ACD, M_NOWAIT);
+           name = malloc(strlen(atadev->name) + 2, M_ACD, M_WAITOK);
            strcpy(name, atadev->name);
            strcat(name, "-");
            ata_free_name(atadev);
@@ -248,7 +248,7 @@ acd_init_lun(struct ata_device *atadev)
 {
     struct acd_softc *cdp;
 
-    if (!(cdp = malloc(sizeof(struct acd_softc), M_ACD, M_NOWAIT | M_ZERO)))
+    if (!(cdp = malloc(sizeof(struct acd_softc), M_ACD, M_WAITOK | M_ZERO)))
        return NULL;
     TAILQ_INIT(&cdp->dev_list);
     bufq_init(&cdp->queue);
@@ -258,7 +258,7 @@ acd_init_lun(struct ata_device *atadev)
     cdp->slot = -1;
     cdp->changer_info = NULL;
     if (!(cdp->stats = malloc(sizeof(struct devstat), M_ACD,
-                             M_NOWAIT | M_ZERO))) {
+                             M_WAITOK | M_ZERO))) {
        free(cdp, M_ACD);
        return NULL;
     }
@@ -673,7 +673,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
            if (te->address_format == CD_MSF_FORMAT) {
                struct cd_toc_entry *entry;
 
-               toc = malloc(sizeof(struct toc), M_ACD, M_NOWAIT | M_ZERO);
+               toc = malloc(sizeof(struct toc), M_ACD, M_WAITOK | M_ZERO);
                bcopy(&cdp->toc, toc, sizeof(struct toc));
                entry = toc->tab + (toc->hdr.ending_track + 1 -
                        toc->hdr.starting_track) + 1;
@@ -718,7 +718,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
            if (te->address_format == CD_MSF_FORMAT) {
                struct cd_toc_entry *entry;
 
-               toc = malloc(sizeof(struct toc), M_ACD, M_NOWAIT | M_ZERO);
+               toc = malloc(sizeof(struct toc), M_ACD, M_WAITOK | M_ZERO);
                bcopy(&cdp->toc, toc, sizeof(struct toc));
 
                entry = toc->tab + (track - toc->hdr.starting_track);
@@ -858,7 +858,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
 #ifndef CD_BUFFER_BLOCKS
 #define CD_BUFFER_BLOCKS 13
 #endif
-           if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_ACD, M_NOWAIT))){
+           if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_ACD, M_WAITOK))){
                error = ENOMEM;
                break;
            }
@@ -1340,7 +1340,7 @@ acd_read_toc(struct acd_softc *cdp)
        char name[16];
 
        sprintf(name, "acd%dt%d", cdp->lun, track);
-       entry = malloc(sizeof(struct acd_devlist), M_ACD, M_NOWAIT | M_ZERO);
+       entry = malloc(sizeof(struct acd_devlist), M_ACD, M_WAITOK | M_ZERO);
        entry->dev = make_dev(&acd_cdevsw, (cdp->lun << 3) | (track << 16),
                              0, 0, 0644, name, NULL);
        entry->dev->si_drv1 = cdp->dev->si_drv1;
@@ -1649,7 +1649,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet)
     if ((error = acd_mode_select(cdp, (caddr_t)&param, param.page_length + 10)))
        return error;
 
-    buffer = malloc(cuesheet->len, M_ACD, M_NOWAIT);
+    buffer = malloc(cuesheet->len, M_ACD, M_WAITOK);
     if (!buffer)
        return ENOMEM;
     if ((error = copyin(cuesheet->entries, buffer, cuesheet->len)))
@@ -1711,7 +1711,7 @@ acd_report_key(struct acd_softc *cdp, struct dvd_authinfo *ai)
     ccb[9] = length & 0xff;
     ccb[10] = (ai->agid << 6) | ai->format;
 
-    d = malloc(length, M_ACD, M_NOWAIT | M_ZERO);
+    d = malloc(length, M_ACD, M_WAITOK | M_ZERO);
     d->length = htons(length - 2);
 
     error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length,
@@ -1775,19 +1775,19 @@ acd_send_key(struct acd_softc *cdp, struct dvd_authinfo *ai)
     switch (ai->format) {
     case DVD_SEND_CHALLENGE:
        length = 16;
-       d = malloc(length, M_ACD, M_NOWAIT | M_ZERO);
+       d = malloc(length, M_ACD, M_WAITOK | M_ZERO);
        bcopy(ai->keychal, &d->data[0], 10);
        break;
 
     case DVD_SEND_KEY2:
        length = 12;
-       d = malloc(length, M_ACD, M_NOWAIT | M_ZERO);
+       d = malloc(length, M_ACD, M_WAITOK | M_ZERO);
        bcopy(&ai->keychal[0], &d->data[0], 5);
        break;
     
     case DVD_SEND_RPC:
        length = 8;
-       d = malloc(length, M_ACD, M_NOWAIT | M_ZERO);
+       d = malloc(length, M_ACD, M_WAITOK | M_ZERO);
        d->data[0] = ai->region;
        break;
 
@@ -1850,7 +1850,7 @@ acd_read_structure(struct acd_softc *cdp, struct dvd_struct *s)
        return EINVAL;
     }
 
-    d = malloc(length, M_ACD, M_NOWAIT | M_ZERO);
+    d = malloc(length, M_ACD, M_WAITOK | M_ZERO);
     d->length = htons(length - 2);
        
     bzero(ccb, sizeof(ccb));
index aca7f50..374ca6f 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/atapi-fd.c,v 1.44.2.9 2002/07/31 11:19:26 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/atapi-fd.c,v 1.8 2003/11/15 21:05:41 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/atapi-fd.c,v 1.9 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -89,7 +89,7 @@ afdattach(struct ata_device *atadev)
     struct afd_softc *fdp;
     dev_t dev;
 
-    fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO);
+    fdp = malloc(sizeof(struct afd_softc), M_AFD, M_WAITOK | M_ZERO);
     if (!fdp) {
        ata_prtdev(atadev, "out of memory\n");
        return 0;
index 3401c9b..e1641e4 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/ata/atapi-tape.c,v 1.36.2.12 2002/07/31 11:19:26 sos Exp $
- * $DragonFly: src/sys/dev/disk/ata/atapi-tape.c,v 1.7 2003/08/07 21:16:51 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/ata/atapi-tape.c,v 1.8 2003/11/30 20:14:18 dillon Exp $
  */
 
 #include "opt_ata.h"
@@ -99,7 +99,7 @@ astattach(struct ata_device *atadev)
     struct ast_readposition position;
     dev_t dev;
 
-    stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO);
+    stp = malloc(sizeof(struct ast_softc), M_AST, M_WAITOK | M_ZERO);
     if (!stp) {
        ata_prtdev(atadev, "out of memory\n");
        return 0;
diff --git a/sys/kern/kern_mpipe.c b/sys/kern/kern_mpipe.c
new file mode 100644 (file)
index 0000000..b6cf456
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/kern/kern_mpipe.c,v 1.1 2003/11/30 20:13:54 dillon Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/slaballoc.h>
+#include <sys/mpipe.h>
+#include <sys/mbuf.h>
+#include <sys/vmmeter.h>
+#include <sys/lock.h>
+#include <sys/thread.h>
+#include <sys/globaldata.h>
+
+#include <sys/thread2.h>
+
+#define arysize(ary)   (sizeof(ary)/sizeof((ary)[0]))
+
+typedef struct mpipe_buf {
+       TAILQ_ENTRY(mpipe_buf)  entry;
+} *mpipe_buf_t;
+
+/*
+ * Initialize a malloc pipeline for the specified malloc type and allocation
+ * size, and immediately allocate nnow buffers and set the nominal maximum
+ * to nmax.
+ */
+void
+mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
+       int nnow, int nmax)
+{
+    if (bytes < sizeof(struct mpipe_buf))
+       bytes = sizeof(struct mpipe_buf);
+    bzero(mpipe, sizeof(struct malloc_pipe));
+    TAILQ_INIT(&mpipe->queue);
+    mpipe->type = type;
+    mpipe->bytes = bytes;
+    mpipe->max_count = nmax;
+    if (nnow > 0) {
+       void *buf;
+
+       buf = malloc(bytes, mpipe->type, M_WAITOK);
+       KKASSERT(buf != NULL);
+       ++mpipe->total_count;
+       mpipe_free(mpipe, buf);
+       while (--nnow > 0) {
+           buf = malloc(bytes, mpipe->type, M_NOWAIT);
+           if (buf == NULL)
+               break;
+           ++mpipe->total_count;
+           mpipe_free(mpipe, buf);
+       }
+    }
+    if (mpipe->max_count < mpipe->total_count)
+       mpipe->max_count = mpipe->total_count;
+}
+
+void
+mpipe_done(malloc_pipe_t mpipe)
+{
+    struct mpipe_buf *buf;
+
+    KKASSERT(mpipe->free_count == mpipe->total_count);
+    while (mpipe->free_count) {
+       buf = TAILQ_FIRST(&mpipe->queue);
+       KKASSERT(buf != NULL);
+       TAILQ_REMOVE(&mpipe->queue, buf, entry);
+       --mpipe->free_count;
+       --mpipe->total_count;
+       free(buf, mpipe->type);
+    }
+    KKASSERT(TAILQ_EMPTY(&mpipe->queue));
+}
+
+/*
+ * Allocate an entry.  flags can be M_NOWAIT which tells us not to block.
+ * Unlike a normal malloc, if we block in mpipe_alloc() no deadlock will occur
+ * because it will unblock the moment an existing in-use buffer is freed.
+ */
+void *
+mpipe_alloc(malloc_pipe_t mpipe, int flags)
+{
+    mpipe_buf_t buf;
+
+    crit_enter();
+    while (mpipe->free_count == 0) {
+       if (mpipe->total_count < mpipe->max_count) {
+           ++mpipe->total_count;
+           if ((buf = malloc(mpipe->bytes, mpipe->type, flags)) != NULL) {
+               crit_exit();
+               return(buf);
+           }
+           --mpipe->total_count;
+       } else if (flags & M_NOWAIT) {
+           crit_exit();
+           return(NULL);
+       } else {
+           mpipe->pending = 1;
+           tsleep(mpipe, 0, "mpipe", 0);
+       }
+    }
+    buf = TAILQ_FIRST(&mpipe->queue);
+    KKASSERT(buf != NULL);
+    TAILQ_REMOVE(&mpipe->queue, buf, entry);
+    --mpipe->free_count;
+    crit_exit();
+    if (flags & M_ZERO)
+       bzero(buf, mpipe->bytes);
+    return(buf);
+}
+
+/*
+ * Free an entry, unblock any waiters.
+ */
+void
+mpipe_free(malloc_pipe_t mpipe, void *vbuf)
+{
+    struct mpipe_buf *buf;
+
+    if ((buf = vbuf) != NULL) {
+       crit_enter();
+       if (mpipe->total_count > mpipe->max_count) {
+           --mpipe->total_count;
+           crit_exit();
+           free(buf, mpipe->type);
+       } else {
+           TAILQ_INSERT_TAIL(&mpipe->queue, buf, entry);
+           ++mpipe->free_count;
+           crit_exit();
+           if (mpipe->free_count >= (mpipe->total_count >> 2) + 1) {
+               if (mpipe->trigger) {
+                   mpipe->trigger(mpipe->trigger_data);
+               }
+               if (mpipe->pending) {
+                   mpipe->pending = 0;
+                   wakeup(mpipe);
+               }
+           }
+       }
+    }
+}
+
index edcc347..fb3e9e9 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)malloc.h    8.5 (Berkeley) 5/3/95
  * $FreeBSD: src/sys/sys/malloc.h,v 1.48.2.2 2002/03/16 02:19:16 archie Exp $
- * $DragonFly: src/sys/sys/malloc.h,v 1.15 2003/11/21 22:46:13 dillon Exp $
+ * $DragonFly: src/sys/sys/malloc.h,v 1.16 2003/11/30 20:13:53 dillon Exp $
  */
 
 #ifndef _SYS_MALLOC_H_
@@ -93,6 +93,8 @@ struct malloc_type {
        long    ks_reserved[4]; /* future use (module compatibility) */
 };
 
+typedef struct malloc_type     *malloc_type_t;
+
 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
 
 #define        MALLOC_DEFINE(type, shortdesc, longdesc)        \
diff --git a/sys/sys/mpipe.h b/sys/sys/mpipe.h
new file mode 100644 (file)
index 0000000..8ef7091
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/sys/mpipe.h,v 1.1 2003/11/30 20:13:53 dillon Exp $
+ */
+
+#ifndef _SYS_MPIPE_H_
+#define _SYS_MPIPE_H_
+
+#ifndef _SYS_MALLOC_H_
+#include <sys/malloc.h>
+#endif
+
+/*
+ * Pipeline memory allocations.  This implements a pipeline for allocations
+ * of a particular size.  It is used in order to allow memory allocations
+ * to block while at the same time guarenteeing that no deadlocks will occur.
+ */
+struct mpipe_buf;
+
+struct malloc_pipe {
+    TAILQ_HEAD(, mpipe_buf) queue;
+    malloc_type_t type;                /* malloc bucket */
+    int                bytes;          /* allocation size */
+    int                pending;        /* there is a request pending */
+    int                free_count;     /* entries in free list */
+    int                total_count;    /* total free + outstanding */
+    int                max_count;      /* maximum cache size */
+    void       (*trigger)(void *data); /* trigger function on free */
+    void       *trigger_data;
+};
+
+typedef struct malloc_pipe *malloc_pipe_t;
+
+#ifdef _KERNEL
+
+void mpipe_init(malloc_pipe_t mpipe, malloc_type_t type,
+               int bytes, int nnow, int nmax);
+void mpipe_done(malloc_pipe_t mpipe);
+void *mpipe_alloc(malloc_pipe_t mpipe, int flags);
+void mpipe_free(malloc_pipe_t mpipe, void *vbuf);
+
+#endif
+
+#endif
+