On Sun, Aug 29, 2010 at 10:26:14PM +1000, David Gwynne wrote:
> this diff is largely a mechanical change.
>
> firstly, it makes struct bufq a member of the softc for devices
> that use it, rather than it being a pointer to something that needs
> to be allocated at attach. since all these devices need a bufq to
> operate, it makes sense to have it allocated as part of the softc
> and get bufq_init to just initialise all its fields. it also gets
> rid of the possibility that you wont be able to allocate teh bufq
> struct during attach, which is something you dont want to happen.
>
> secondly, it consistently implements a split between wrapper functions
> and the per discipline implementation of the bufq handlers. it
> consistently does the locking in the wrappers rather than doing
> half in the wrappers and the other half in the implementations.
>
> it also consistently handles the outstanding bufq bq pointer in the
> wrappers.
>
> this hides most of the implementation inside kern_bufq.c. the only
> stuff left in buf.h is for the bits each implementation needs to
> put bufs on their queues.
>
> ive tested this extensively on sd(4) and thib has tested this on
> wd(4). we'd like some wider exposure, especially over suspends and
> resumes on a variety of machines. i have tried to preserve the
> locking semantics, but testing would be lovely.
>
> ok?
I like this a lot, and I will do some testing on st and cd at least as
soon as I can rebuild the appropriate box.
.... Ken
>
> dlg
>
> Index: dev/ata/wd.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ata/wd.c,v
> retrieving revision 1.85
> diff -u -p -r1.85 wd.c
> --- dev/ata/wd.c 28 Jun 2010 08:35:46 -0000 1.85
> +++ dev/ata/wd.c 25 Aug 2010 12:05:33 -0000
> @@ -121,7 +121,7 @@ struct wd_softc {
> /* General disk infos */
> struct device sc_dev;
> struct disk sc_dk;
> - struct bufq *sc_bufq;
> + struct bufq sc_bufq;
>
> /* IDE disk soft states */
> struct ata_bio sc_wdc_bio; /* current transfer */
> @@ -369,7 +369,7 @@ wdattach(struct device *parent, struct d
> */
> wd->sc_dk.dk_driver = &wddkdriver;
> wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
> - wd->sc_bufq = bufq_init(BUFQ_DEFAULT);
> + bufq_init(&wd->sc_bufq, BUFQ_DEFAULT);
> wd->sc_sdhook = shutdownhook_establish(wd_shutdown, wd);
> if (wd->sc_sdhook == NULL)
> printf("%s: WARNING: unable to establish shutdown hook\n",
> @@ -413,7 +413,7 @@ wddetach(struct device *self, int flags)
>
> /* Remove unprocessed buffers from queue */
> s = splbio();
> - while ((bp = BUFQ_DEQUEUE(sc->sc_bufq)) != NULL) {
> + while ((bp = bufq_dequeue(&sc->sc_bufq)) != NULL) {
> bp->b_error = ENXIO;
> bp->b_flags |= B_ERROR;
> biodone(bp);
> @@ -435,7 +435,7 @@ wddetach(struct device *self, int flags)
> shutdownhook_disestablish(sc->sc_sdhook);
>
> /* Detach disk. */
> - bufq_destroy(sc->sc_bufq);
> + bufq_destroy(&sc->sc_bufq);
> disk_detach(&sc->sc_dk);
>
> return (0);
> @@ -486,7 +486,7 @@ wdstrategy(struct buf *bp)
> (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
> goto done;
> /* Queue transfer on drive, activate drive and controller if idle. */
> - BUFQ_QUEUE(wd->sc_bufq, bp);
> + bufq_queue(&wd->sc_bufq, bp);
> s = splbio();
> wdstart(wd);
> splx(s);
> @@ -518,7 +518,7 @@ wdstart(void *arg)
> while (wd->openings > 0) {
>
> /* Is there a buf for us ? */
> - if ((bp = BUFQ_DEQUEUE(wd->sc_bufq)) == NULL)
> + if ((bp = bufq_dequeue(&wd->sc_bufq)) == NULL)
> return;
> /*
> * Make the command. First lock the device
> Index: kern/kern_bufq.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_bufq.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 kern_bufq.c
> --- kern/kern_bufq.c 19 Jul 2010 21:39:15 -0000 1.14
> +++ kern/kern_bufq.c 25 Aug 2010 12:05:33 -0000
> @@ -30,45 +30,70 @@ SLIST_HEAD(, bufq) bufqs = SLIST_HEAD_IN
> struct mutex bufqs_mtx = MUTEX_INITIALIZER(IPL_NONE);
> int bufqs_stop;
>
> -struct buf *(*bufq_dequeuev[BUFQ_HOWMANY])(struct bufq *, int) = {
> - bufq_disksort_dequeue,
> - bufq_fifo_dequeue
> +struct bufq_impl {
> + void *(*impl_create)(void);
> + void (*impl_destroy)(void *);
> +
> + void (*impl_queue)(void *, struct buf *);
> + struct buf *(*impl_dequeue)(void *);
> + void (*impl_requeue)(void *, struct buf *);
> + int (*impl_peek)(void *);
> };
> -void (*bufq_queuev[BUFQ_HOWMANY])(struct bufq *, struct buf *) = {
> +
> +void *bufq_disksort_create(void);
> +void bufq_disksort_destroy(void *);
> +void bufq_disksort_queue(void *, struct buf *);
> +struct buf *bufq_disksort_dequeue(void *);
> +void bufq_disksort_requeue(void *, struct buf *);
> +int bufq_disksort_peek(void *);
> +
> +struct bufq_impl bufq_impl_disksort = {
> + bufq_disksort_create,
> + bufq_disksort_destroy,
> bufq_disksort_queue,
> - bufq_fifo_queue
> -};
> -void (*bufq_requeuev[BUFQ_HOWMANY])(struct bufq *, struct buf *) = {
> + bufq_disksort_dequeue,
> bufq_disksort_requeue,
> - bufq_fifo_requeue
> + bufq_disksort_peek
> };
>
> +void *bufq_fifo_create(void);
> +void bufq_fifo_destroy(void *);
> +void bufq_fifo_queue(void *, struct buf *);
> +struct buf *bufq_fifo_dequeue(void *);
> +void bufq_fifo_requeue(void *, struct buf *);
> +int bufq_fifo_peek(void *);
> +
> +struct bufq_impl bufq_impl_fifo = {
> + bufq_fifo_create,
> + bufq_fifo_destroy,
> + bufq_fifo_queue,
> + bufq_fifo_dequeue,
> + bufq_fifo_requeue,
> + bufq_fifo_peek
> +};
>
> -struct bufq *
> -bufq_init(int type)
> -{
> - struct bufq *bq;
> - int error;
> +struct bufq_impl *bufq_impls[BUFQ_HOWMANY] = {
> + &bufq_impl_disksort,
> + &bufq_impl_fifo
> +};
>
> - bq = malloc(sizeof(*bq), M_DEVBUF, M_NOWAIT|M_ZERO);
> - KASSERT(bq != NULL);
> +int
> +bufq_init(struct bufq *bq, int type)
> +{
> + if (type > BUFQ_HOWMANY)
> + panic("bufq_init: type %i unknown", type);
>
> mtx_init(&bq->bufq_mtx, IPL_BIO);
> bq->bufq_type = type;
> -
> - switch (type) {
> - case BUFQ_DISKSORT:
> - error = bufq_disksort_init(bq);
> - break;
> - case BUFQ_FIFO:
> - error = bufq_fifo_init(bq);
> - break;
> - default:
> - panic("bufq_init: type %i unknown", type);
> - break;
> - };
> -
> - KASSERT(error == 0);
> + bq->bufq_impl = bufq_impls[type];
> + bq->bufq_data = bq->bufq_impl->impl_create();
> + if (bq->bufq_data == NULL) {
> + /*
> + * we should actually return failure so disks attaching after
> + * boot in low memory situations dont panic the system.
> + */
> + panic("bufq init fail");
> + }
>
> mtx_enter(&bufqs_mtx);
> while (bufqs_stop) {
> @@ -77,7 +102,48 @@ bufq_init(int type)
> SLIST_INSERT_HEAD(&bufqs, bq, bufq_entries);
> mtx_leave(&bufqs_mtx);
>
> - return (bq);
> + return (0);
> +}
> +
> +int
> +bufq_switch(struct bufq *bq, int type)
> +{
> + void *data;
> + void *odata;
> + int otype;
> + struct buf *bp;
> + int ret;
> +
> + mtx_enter(&bq->bufq_mtx);
> + ret = (bq->bufq_type == type);
> + mtx_leave(&bq->bufq_mtx);
> + if (ret)
> + return (0);
> +
> + data = bufq_impls[type]->impl_create();
> + if (data == NULL)
> + return (ENOMEM);
> +
> + mtx_enter(&bq->bufq_mtx);
> + if (bq->bufq_type != type) { /* might have changed during create */
> + odata = bq->bufq_data;
> + otype = bq->bufq_type;
> +
> + while ((bp = bufq_impls[otype]->impl_dequeue(odata)) != NULL)
> + bufq_impls[type]->impl_queue(data, bp);
> +
> + bq->bufq_data = data;
> + bq->bufq_type = type;
> + bq->bufq_impl = bufq_impls[type];
> + } else {
> + otype = type;
> + odata = data;
> + }
> + mtx_leave(&bq->bufq_mtx);
> +
> + bufq_impls[otype]->impl_destroy(odata);
> +
> + return (0);
> }
>
> void
> @@ -85,8 +151,8 @@ bufq_destroy(struct bufq *bq)
> {
> bufq_drain(bq);
>
> - if (bq->bufq_data != NULL)
> - free(bq->bufq_data, M_DEVBUF);
> + bq->bufq_impl->impl_destroy(bq->bufq_data);
> + bq->bufq_data = NULL;
>
> mtx_enter(&bufqs_mtx);
> while (bufqs_stop) {
> @@ -94,10 +160,9 @@ bufq_destroy(struct bufq *bq)
> }
> SLIST_REMOVE(&bufqs, bq, bufq, bufq_entries);
> mtx_leave(&bufqs_mtx);
> -
> - free(bq, M_DEVBUF);
> }
>
> +
> void
> bufq_queue(struct bufq *bq, struct buf *bp)
> {
> @@ -105,16 +170,43 @@ bufq_queue(struct bufq *bq, struct buf *
> while (bq->bufq_stop) {
> msleep(&bq->bufq_stop, &bq->bufq_mtx, PRIBIO, "bqqueue", 0);
> }
> - bufq_queuev[bq->bufq_type](bq, bp);
> +
> + bp->b_bq = bq;
> + bq->bufq_outstanding++;
> + bq->bufq_impl->impl_queue(bq->bufq_data, bp);
> + mtx_leave(&bq->bufq_mtx);
> +}
> +
> +struct buf *
> +bufq_dequeue(struct bufq *bq)
> +{
> + struct buf *bp;
> +
> + mtx_enter(&bq->bufq_mtx);
> + bp = bq->bufq_impl->impl_dequeue(bq->bufq_data);
> mtx_leave(&bq->bufq_mtx);
> +
> + return (bp);
> }
>
> void
> bufq_requeue(struct bufq *bq, struct buf *bp)
> {
> mtx_enter(&bq->bufq_mtx);
> - bufq_requeuev[bq->bufq_type](bq, bp);
> + bq->bufq_impl->impl_requeue(bq->bufq_data, bp);
> + mtx_leave(&bq->bufq_mtx);
> +}
> +
> +int
> +bufq_peek(struct bufq *bq)
> +{
> + int rv;
> +
> + mtx_enter(&bq->bufq_mtx);
> + rv = bq->bufq_impl->impl_peek(bq->bufq_data);
> mtx_leave(&bq->bufq_mtx);
> +
> + return (rv);
> }
>
> void
> @@ -123,7 +215,7 @@ bufq_drain(struct bufq *bq)
> struct buf *bp;
> int s;
>
> - while ((bp = BUFQ_DEQUEUE(bq)) != NULL) {
> + while ((bp = bufq_dequeue(bq)) != NULL) {
> bp->b_error = ENXIO;
> bp->b_flags |= B_ERROR;
> s = splbio();
> @@ -138,7 +230,7 @@ bufq_done(struct bufq *bq, struct buf *b
> mtx_enter(&bq->bufq_mtx);
> bq->bufq_outstanding--;
> KASSERT(bq->bufq_outstanding >= 0);
> - if (bq->bufq_outstanding == 0)
> + if (bq->bufq_outstanding == 0 /* XXX and quiesced */)
> wakeup(&bq->bufq_outstanding);
> mtx_leave(&bq->bufq_mtx);
> bp->b_bq = NULL;
> @@ -152,7 +244,7 @@ bufq_quiesce(void)
> mtx_enter(&bufqs_mtx);
> bufqs_stop = 1;
> mtx_leave(&bufqs_mtx);
> - SLIST_FOREACH(bq, &bufqs, bufq_entries) {
> + SLIST_FOREACH(bq, &bufqs, bufq_entries) { /* XXX */
> mtx_enter(&bq->bufq_mtx);
> bq->bufq_stop = 1;
> while (bq->bufq_outstanding) {
> @@ -180,24 +272,47 @@ bufq_restart(void)
> mtx_leave(&bufqs_mtx);
> }
>
> +/*
> + * disksort implementation.
> + */
> +
> +void *
> +bufq_disksort_create(void)
> +{
> + return (malloc(sizeof(struct buf), M_DEVBUF, M_NOWAIT | M_ZERO));
> +}
> +
> void
> -bufq_disksort_queue(struct bufq *bq, struct buf *bp)
> +bufq_disksort_destroy(void *data)
> {
> - struct buf *bufq;
> + free(data, M_DEVBUF);
> +}
>
> - bufq = (struct buf *)bq->bufq_data;
> +void
> +bufq_disksort_queue(void *data, struct buf *bp)
> +{
> + disksort((struct buf *)data, bp);
> +}
>
> - bq->bufq_outstanding++;
> - bp->b_bq = bq;
> - disksort(bufq, bp);
> +struct buf *
> +bufq_disksort_dequeue(void *data)
> +{
> + struct buf *bufq = data;
> + struct buf *bp;
> +
> + bp = bufq->b_actf;
> + if (bp != NULL)
> + bufq->b_actf = bp->b_actf;
> + if (bufq->b_actf == NULL)
> + bufq->b_actb = &bufq->b_actf;
> +
> + return (bp);
> }
>
> void
> -bufq_disksort_requeue(struct bufq *bq, struct buf *bp)
> +bufq_disksort_requeue(void *data, struct buf *bp)
> {
> - struct buf *bufq;
> -
> - bufq = (struct buf *)bq->bufq_data;
> + struct buf *bufq = data;
>
> bp->b_actf = bufq->b_actf;
> bufq->b_actf = bp;
> @@ -205,83 +320,71 @@ bufq_disksort_requeue(struct bufq *bq, s
> bufq->b_actb = &bp->b_actf;
> }
>
> -struct buf *
> -bufq_disksort_dequeue(struct bufq *bq, int peeking)
> +int
> +bufq_disksort_peek(void *data)
> {
> - struct buf *bufq, *bp;
> + struct buf *bufq = data;
>
> - mtx_enter(&bq->bufq_mtx);
> - bufq = (struct buf *)bq->bufq_data;
> - bp = bufq->b_actf;
> - if (!peeking) {
> - if (bp != NULL)
> - bufq->b_actf = bp->b_actf;
> - if (bufq->b_actf == NULL)
> - bufq->b_actb = &bufq->b_actf;
> - }
> - mtx_leave(&bq->bufq_mtx);
> -
> - return (bp);
> + return (bufq->b_actf != NULL);
> }
>
> -int
> -bufq_disksort_init(struct bufq *bq)
> +/*
> + * fifo implementation
> + */
> +
> +void *
> +bufq_fifo_create(void)
> {
> - int error = 0;
> + struct bufq_fifo_head *head;
>
> - bq->bufq_data = malloc(sizeof(struct buf), M_DEVBUF,
> - M_NOWAIT|M_ZERO);
> + head = malloc(sizeof(*head), M_DEVBUF, M_NOWAIT | M_ZERO);
> + if (head == NULL)
> + return (NULL);
>
> - if (bq->bufq_data == NULL)
> - error = ENOMEM;
> + SIMPLEQ_INIT(head);
>
> - return (error);
> + return (head);
> }
>
> void
> -bufq_fifo_queue(struct bufq *bq, struct buf *bp)
> +bufq_fifo_destroy(void *data)
> {
> - struct bufq_fifo_head *head = bq->bufq_data;
> -
> - bq->bufq_outstanding++;
> - bp->b_bq = bq;
> - SIMPLEQ_INSERT_TAIL(head, bp, b_bufq.bufq_data_fifo.bqf_entries);
> + free(data, M_DEVBUF);
> }
>
> void
> -bufq_fifo_requeue(struct bufq *bq, struct buf *bp)
> +bufq_fifo_queue(void *data, struct buf *bp)
> {
> - struct bufq_fifo_head *head = bq->bufq_data;
> + struct bufq_fifo_head *head = data;
>
> - SIMPLEQ_INSERT_HEAD(head, bp, b_bufq.bufq_data_fifo.bqf_entries);
> + SIMPLEQ_INSERT_TAIL(head, bp, b_bufq.bufq_data_fifo.bqf_entries);
> }
>
> struct buf *
> -bufq_fifo_dequeue(struct bufq *bq, int peeking)
> +bufq_fifo_dequeue(void *data)
> {
> - struct bufq_fifo_head *head = bq->bufq_data;
> - struct buf *bp;
> + struct bufq_fifo_head *head = data;
> + struct buf *bp;
>
> - mtx_enter(&bq->bufq_mtx);
> bp = SIMPLEQ_FIRST(head);
> - if (bp != NULL && !peeking)
> + if (bp != NULL)
> SIMPLEQ_REMOVE_HEAD(head, b_bufq.bufq_data_fifo.bqf_entries);
> - mtx_leave(&bq->bufq_mtx);
>
> return (bp);
> }
>
> -int
> -bufq_fifo_init(struct bufq *bq)
> +void
> +bufq_fifo_requeue(void *data, struct buf *bp)
> {
> - struct bufq_fifo_head *head;
> + struct bufq_fifo_head *head = data;
>
> - head = malloc(sizeof(*head), M_DEVBUF, M_NOWAIT);
> - if (head == NULL)
> - return (ENOMEM);
> + SIMPLEQ_INSERT_HEAD(head, bp, b_bufq.bufq_data_fifo.bqf_entries);
> +}
>
> - SIMPLEQ_INIT(head);
> - bq->bufq_data = head;
> +int
> +bufq_fifo_peek(void *data)
> +{
> + struct bufq_fifo_head *head = data;
>
> - return (0);
> + return (SIMPLEQ_FIRST(head) != NULL);
> }
> Index: scsi/cd.c
> ===================================================================
> RCS file: /cvs/src/sys/scsi/cd.c,v
> retrieving revision 1.181
> diff -u -p -r1.181 cd.c
> --- scsi/cd.c 28 Jul 2010 23:47:43 -0000 1.181
> +++ scsi/cd.c 25 Aug 2010 12:05:33 -0000
> @@ -111,7 +111,7 @@ struct cd_softc {
> u_int32_t blksize;
> daddr64_t disksize; /* total number sectors */
> } sc_params;
> - struct bufq *sc_bufq;
> + struct bufq sc_bufq;
> struct scsi_xshandler sc_xsh;
> struct timeout sc_timeout;
> void *sc_cdpwrhook; /* our power hook */
> @@ -219,7 +219,7 @@ cdattach(struct device *parent, struct d
> */
> sc->sc_dk.dk_driver = &cddkdriver;
> sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
> - sc->sc_bufq = bufq_init(BUFQ_DEFAULT);
> + bufq_init(&sc->sc_bufq, BUFQ_DEFAULT);
>
> /*
> * Note if this device is ancient. This is used in cdminphys().
> @@ -255,7 +255,7 @@ cdactivate(struct device *self, int act)
>
> case DVACT_DEACTIVATE:
> sc->sc_flags |= CDF_DYING;
> - bufq_drain(sc->sc_bufq);
> + bufq_drain(&sc->sc_bufq);
> break;
> }
> return (rv);
> @@ -268,7 +268,7 @@ cddetach(struct device *self, int flags)
> struct cd_softc *sc = (struct cd_softc *)self;
> int bmaj, cmaj, mn;
>
> - bufq_drain(sc->sc_bufq);
> + bufq_drain(&sc->sc_bufq);
>
> /* Locate the lowest minor number to be detached. */
> mn = DISKMINOR(self->dv_unit, 0);
> @@ -285,7 +285,7 @@ cddetach(struct device *self, int flags)
> powerhook_disestablish(sc->sc_cdpwrhook);
>
> /* Detach disk. */
> - bufq_destroy(sc->sc_bufq);
> + bufq_destroy(&sc->sc_bufq);
> disk_detach(&sc->sc_dk);
>
> return (0);
> @@ -530,7 +530,7 @@ cdstrategy(struct buf *bp)
> goto done;
>
> /* Place it in the queue of disk activities for this disk. */
> - BUFQ_QUEUE(sc->sc_bufq, bp);
> + bufq_queue(&sc->sc_bufq, bp);
>
> /*
> * Tell the device to get going on the transfer if it's
> @@ -596,12 +596,12 @@ cdstart(struct scsi_xfer *xs)
> * re-opened
> */
> if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
> - bufq_drain(sc->sc_bufq);
> + bufq_drain(&sc->sc_bufq);
> scsi_xs_put(xs);
> return;
> }
>
> - bp = BUFQ_DEQUEUE(sc->sc_bufq);
> + bp = bufq_dequeue(&sc->sc_bufq);
> if (bp == NULL) {
> scsi_xs_put(xs);
> return;
> @@ -665,7 +665,7 @@ cdstart(struct scsi_xfer *xs)
>
> if (ISSET(sc->sc_flags, CDF_WAITING))
> CLR(sc->sc_flags, CDF_WAITING);
> - else if (BUFQ_PEEK(sc->sc_bufq))
> + else if (bufq_peek(&sc->sc_bufq))
> scsi_xsh_add(&sc->sc_xsh);
> }
>
> @@ -686,7 +686,7 @@ cd_buf_done(struct scsi_xfer *xs)
> /* The adapter is busy, requeue the buf and try it later. */
> disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
> bp->b_flags & B_READ);
> - BUFQ_REQUEUE(sc->sc_bufq, bp);
> + bufq_requeue(&sc->sc_bufq, bp);
> scsi_xs_put(xs);
> SET(sc->sc_flags, CDF_WAITING);
> timeout_add(&sc->sc_timeout, 1);
> Index: scsi/sd.c
> ===================================================================
> RCS file: /cvs/src/sys/scsi/sd.c,v
> retrieving revision 1.205
> diff -u -p -r1.205 sd.c
> --- scsi/sd.c 3 Aug 2010 19:37:17 -0000 1.205
> +++ scsi/sd.c 25 Aug 2010 12:05:33 -0000
> @@ -175,7 +175,7 @@ sdattach(struct device *parent, struct d
> */
> sc->sc_dk.dk_driver = &sddkdriver;
> sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
> - sc->sc_bufq = bufq_init(BUFQ_DEFAULT);
> + bufq_init(&sc->sc_bufq, BUFQ_DEFAULT);
>
> if ((sc_link->flags & SDEV_ATAPI) && (sc_link->flags & SDEV_REMOVABLE))
> sc_link->quirks |= SDEV_NOSYNCCACHE;
> @@ -279,7 +279,7 @@ sdactivate(struct device *self, int act)
>
> case DVACT_DEACTIVATE:
> sc->flags |= SDF_DYING;
> - bufq_drain(sc->sc_bufq);
> + bufq_drain(&sc->sc_bufq);
> break;
>
> case DVACT_SUSPEND:
> @@ -309,7 +309,7 @@ sddetach(struct device *self, int flags)
> struct sd_softc *sc = (struct sd_softc *)self;
> int bmaj, cmaj, mn;
>
> - bufq_drain(sc->sc_bufq);
> + bufq_drain(&sc->sc_bufq);
>
> /* Locate the lowest minor number to be detached. */
> mn = DISKMINOR(self->dv_unit, 0);
> @@ -326,7 +326,7 @@ sddetach(struct device *self, int flags)
> shutdownhook_disestablish(sc->sc_sdhook);
>
> /* Detach disk. */
> - bufq_destroy(sc->sc_bufq);
> + bufq_destroy(&sc->sc_bufq);
> disk_detach(&sc->sc_dk);
>
> return (0);
> @@ -581,7 +581,7 @@ sdstrategy(struct buf *bp)
> goto done;
>
> /* Place it in the queue of disk activities for this disk. */
> - BUFQ_QUEUE(sc->sc_bufq, bp);
> + bufq_queue(&sc->sc_bufq, bp);
>
> /*
> * Tell the device to get going on the transfer if it's
> @@ -683,12 +683,12 @@ sdstart(struct scsi_xfer *xs)
> return;
> }
> if ((link->flags & SDEV_MEDIA_LOADED) == 0) {
> - bufq_drain(sc->sc_bufq);
> + bufq_drain(&sc->sc_bufq);
> scsi_xs_put(xs);
> return;
> }
>
> - bp = BUFQ_DEQUEUE(sc->sc_bufq);
> + bp = bufq_dequeue(&sc->sc_bufq);
> if (bp == NULL) {
> scsi_xs_put(xs);
> return;
> @@ -739,7 +739,7 @@ sdstart(struct scsi_xfer *xs)
> /* move onto the next io */
> if (ISSET(sc->flags, SDF_WAITING))
> CLR(sc->flags, SDF_WAITING);
> - else if (BUFQ_PEEK(sc->sc_bufq) != NULL)
> + else if (bufq_peek(&sc->sc_bufq) != NULL)
> scsi_xsh_add(&sc->sc_xsh);
> }
>
> @@ -760,7 +760,7 @@ sd_buf_done(struct scsi_xfer *xs)
> /* The adapter is busy, requeue the buf and try it later. */
> disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
> bp->b_flags & B_READ);
> - BUFQ_REQUEUE(sc->sc_bufq, bp);
> + bufq_requeue(&sc->sc_bufq, bp);
> scsi_xs_put(xs);
> SET(sc->flags, SDF_WAITING);
> timeout_add(&sc->sc_timeout, 1);
> Index: scsi/sdvar.h
> ===================================================================
> RCS file: /cvs/src/sys/scsi/sdvar.h,v
> retrieving revision 1.31
> diff -u -p -r1.31 sdvar.h
> --- scsi/sdvar.h 2 Jun 2010 13:32:13 -0000 1.31
> +++ scsi/sdvar.h 25 Aug 2010 12:05:33 -0000
> @@ -51,7 +51,7 @@
> struct sd_softc {
> struct device sc_dev;
> struct disk sc_dk;
> - struct bufq *sc_bufq;
> + struct bufq sc_bufq;
>
> int flags;
> #define SDF_LOCKED 0x01
> Index: scsi/st.c
> ===================================================================
> RCS file: /cvs/src/sys/scsi/st.c,v
> retrieving revision 1.106
> diff -u -p -r1.106 st.c
> --- scsi/st.c 22 Jul 2010 05:26:34 -0000 1.106
> +++ scsi/st.c 25 Aug 2010 12:05:33 -0000
> @@ -215,7 +215,7 @@ struct st_softc {
> #define BLKSIZE_SET_BY_USER 0x04
> #define BLKSIZE_SET_BY_QUIRK 0x08
>
> - struct bufq *sc_bufq;
> + struct bufq sc_bufq;
> struct timeout sc_timeout;
> struct scsi_xshandler sc_xsh;
> };
> @@ -331,7 +331,7 @@ stattach(struct device *parent, struct d
> &st->sc_xsh);
>
> /* Set up the buf queue for this device. */
> - st->sc_bufq = bufq_init(BUFQ_FIFO);
> + bufq_init(&st->sc_bufq, BUFQ_FIFO);
>
> /* Start up with media position unknown. */
> st->media_fileno = -1;
> @@ -357,7 +357,7 @@ stactivate(struct device *self, int act)
>
> case DVACT_DEACTIVATE:
> st->flags |= ST_DYING;
> - bufq_drain(st->sc_bufq);
> + bufq_drain(&st->sc_bufq);
> break;
> }
>
> @@ -370,7 +370,7 @@ stdetach(struct device *self, int flags)
> struct st_softc *st = (struct st_softc *)self;
> int bmaj, cmaj, mn;
>
> - bufq_drain(st->sc_bufq);
> + bufq_drain(&st->sc_bufq);
>
> /* Locate the lowest minor number to be detached. */
> mn = STUNIT(self->dv_unit);
> @@ -390,7 +390,7 @@ stdetach(struct device *self, int flags)
> vdevgone(cmaj, mn, mn + 3, VCHR);
> }
>
> - bufq_destroy(st->sc_bufq);
> + bufq_destroy(&st->sc_bufq);
>
> return (0);
> }
> @@ -877,7 +877,7 @@ ststrategy(struct buf *bp)
> * at the end (a bit silly because we only have on user..
> * (but it could fork()))
> */
> - BUFQ_QUEUE(st->sc_bufq, bp);
> + bufq_queue(&st->sc_bufq, bp);
>
> /*
> * Tell the device to get going on the transfer if it's
> @@ -922,13 +922,13 @@ ststart(struct scsi_xfer *xs)
> !(sc_link->flags & SDEV_MEDIA_LOADED)) {
> /* make sure that one implies the other.. */
> sc_link->flags &= ~SDEV_MEDIA_LOADED;
> - bufq_drain(st->sc_bufq);
> + bufq_drain(&st->sc_bufq);
> scsi_xs_put(xs);
> return;
> }
>
> for (;;) {
> - bp = BUFQ_DEQUEUE(st->sc_bufq);
> + bp = bufq_dequeue(&st->sc_bufq);
> if (bp == NULL) {
> scsi_xs_put(xs);
> return;
> @@ -1041,7 +1041,7 @@ ststart(struct scsi_xfer *xs)
> */
> if (ISSET(st->flags, ST_WAITING))
> CLR(st->flags, ST_WAITING);
> - else if (BUFQ_PEEK(st->sc_bufq))
> + else if (bufq_peek(&st->sc_bufq))
> scsi_xsh_add(&st->sc_xsh);
> }
>
> @@ -1060,7 +1060,7 @@ st_buf_done(struct scsi_xfer *xs)
>
> case XS_NO_CCB:
> /* The adapter is busy, requeue the buf and try it later. */
> - BUFQ_REQUEUE(st->sc_bufq, bp);
> + bufq_requeue(&st->sc_bufq, bp);
> scsi_xs_put(xs);
> SET(st->flags, ST_WAITING); /* dont let ststart xsh_add */
> timeout_add(&st->sc_timeout, 1);
> Index: sys/buf.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/buf.h,v
> retrieving revision 1.70
> diff -u -p -r1.70 buf.h
> --- sys/buf.h 30 Jun 2010 02:26:58 -0000 1.70
> +++ sys/buf.h 25 Aug 2010 12:05:33 -0000
> @@ -67,6 +67,8 @@ LIST_HEAD(workhead, worklist);
> #define BUFQ_DEFAULT BUFQ_DISKSORT
> #define BUFQ_HOWMANY 2
>
> +struct bufq_impl;
> +
> struct bufq {
> SLIST_ENTRY(bufq) bufq_entries;
> struct mutex bufq_mtx;
> @@ -74,51 +76,40 @@ struct bufq {
> u_int bufq_outstanding;
> int bufq_stop;
> int bufq_type;
> + struct bufq_impl *bufq_impl;
> };
>
> -struct buf *bufq_disksort_dequeue(struct bufq *, int);
> -void bufq_disksort_queue(struct bufq *, struct buf *);
> -void bufq_disksort_requeue(struct bufq *, struct buf *);
> -int bufq_disksort_init(struct bufq *);
> +int bufq_init(struct bufq *, int);
> +int bufq_switch(struct bufq *, int);
> +void bufq_destroy(struct bufq *);
> +
> +void bufq_queue(struct bufq *, struct buf *);
> +struct buf *bufq_dequeue(struct bufq *);
> +void bufq_requeue(struct bufq *, struct buf *);
> +int bufq_peek(struct bufq *);
> +void bufq_drain(struct bufq *);
> +
> +void bufq_done(struct bufq *, struct buf *);
> +void bufq_quiesce(void);
> +void bufq_restart(void);
> +
> +/* disksort */
> struct bufq_disksort {
> struct buf *bqd_actf;
> struct buf **bqd_actb;
> };
>
> -struct buf *bufq_fifo_dequeue(struct bufq *, int);
> -void bufq_fifo_queue(struct bufq *, struct buf *);
> -void bufq_fifo_requeue(struct bufq *, struct buf *);
> -int bufq_fifo_init(struct bufq *);
> +/* fifo */
> SIMPLEQ_HEAD(bufq_fifo_head, buf);
> struct bufq_fifo {
> SIMPLEQ_ENTRY(buf) bqf_entries;
> };
>
> +/* bufq link in struct buf */
> union bufq_data {
> struct bufq_disksort bufq_data_disksort;
> struct bufq_fifo bufq_data_fifo;
> };
> -
> -extern struct buf *(*bufq_dequeuev[BUFQ_HOWMANY])(struct bufq *, int);
> -extern void (*bufq_queuev[BUFQ_HOWMANY])(struct bufq *, struct buf *);
> -extern void (*bufq_requeuev[BUFQ_HOWMANY])(struct bufq *, struct buf *);
> -
> -#define BUFQ_QUEUE(_bufq, _bp) bufq_queue(_bufq, _bp)
> -#define BUFQ_REQUEUE(_bufq, _bp) bufq_requeue(_bufq, _bp)
> -#define BUFQ_DEQUEUE(_bufq) \
> - bufq_dequeuev[(_bufq)->bufq_type](_bufq, 0)
> -#define BUFQ_PEEK(_bufq) \
> - bufq_dequeuev[(_bufq)->bufq_type](_bufq, 1)
> -
> -struct bufq *bufq_init(int);
> -void bufq_queue(struct bufq *, struct buf *);
> -void bufq_requeue(struct bufq *, struct buf *);
> -void bufq_destroy(struct bufq *);
> -void bufq_drain(struct bufq *);
> -void bufq_done(struct bufq *, struct buf *);
> -void bufq_quiesce(void);
> -void bufq_restart(void);
> -
>
> /*
> * These are currently used only by the soft dependency code, hence