diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-06-29 18:52:21 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-06-29 18:52:21 +0000 |
commit | d39a9ee347bd5a3e56a3272fbf50afe828620da6 (patch) | |
tree | 7b9e57dde86b7685fc2cb1cfc4dafb0b434991bf /sys/kern/kern_bufq.c | |
parent | 6393ccd109d17c92e6427fba5730a05c7e4ac29c (diff) |
Introduce bufq_quiesce(), which will block I/O ifrom getting on the queues,
and waits until all I/O currently on the queues has been completed. To get
I/O going again, call bufq_restart().
To be used for suspend/resume.
Joint effort with thib@, tedu@; tested by mlarkin@, marco@
Diffstat (limited to 'sys/kern/kern_bufq.c')
-rw-r--r-- | sys/kern/kern_bufq.c | 113 |
1 files changed, 101 insertions, 12 deletions
diff --git a/sys/kern/kern_bufq.c b/sys/kern/kern_bufq.c index c0d0c3774bd..23f209abe25 100644 --- a/sys/kern/kern_bufq.c +++ b/sys/kern/kern_bufq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_bufq.c,v 1.8 2010/06/27 22:05:28 thib Exp $ */ +/* $OpenBSD: kern_bufq.c,v 1.9 2010/06/29 18:52:20 kettenis Exp $ */ /* * Copyright (c) 2010 Thordur I. Bjornsson <thib@openbsd.org> * @@ -26,15 +26,19 @@ #include <sys/disklabel.h> -struct buf *(*bufq_dequeue[BUFQ_HOWMANY])(struct bufq *, int) = { +SLIST_HEAD(, bufq) bufqs = SLIST_HEAD_INITIALIZER(&bufq); +struct mutex bufqs_mtx = MUTEX_INITIALIZER(IPL_BIO); +int bufqs_stop; + +struct buf *(*bufq_dequeuev[BUFQ_HOWMANY])(struct bufq *, int) = { bufq_disksort_dequeue, bufq_fifo_dequeue }; -void (*bufq_queue[BUFQ_HOWMANY])(struct bufq *, struct buf *) = { +void (*bufq_queuev[BUFQ_HOWMANY])(struct bufq *, struct buf *) = { bufq_disksort_queue, bufq_fifo_queue }; -void (*bufq_requeue[BUFQ_HOWMANY])(struct bufq *, struct buf *) = { +void (*bufq_requeuev[BUFQ_HOWMANY])(struct bufq *, struct buf *) = { bufq_disksort_requeue, bufq_fifo_requeue }; @@ -66,6 +70,10 @@ bufq_init(int type) KASSERT(error == 0); + mtx_enter(&bufqs_mtx); + SLIST_INSERT_HEAD(&bufqs, bq, bufq_entries); + mtx_leave(&bufqs_mtx); + return (bq); } @@ -77,10 +85,39 @@ bufq_destroy(struct bufq *bq) if (bq->bufq_data != NULL) free(bq->bufq_data, M_DEVBUF); + mtx_enter(&bufqs_mtx); + while (bufqs_stop) { + msleep(&bufqs_stop, &bufqs_mtx, PRIBIO, "bufqstop", 0); + } + SLIST_REMOVE(&bufqs, bq, bufq, bufq_entries); + mtx_leave(&bufqs_mtx); + free(bq, M_DEVBUF); } void +bufq_queue(struct bufq *bq, struct buf *bp) +{ + mtx_enter(&bq->bufq_mtx); + while (bq->bufq_stop) { + msleep(&bq->bufq_stop, &bq->bufq_mtx, PRIBIO, "bufqstop", 0); + } + bufq_queuev[bq->bufq_type](bq, bp); + mtx_leave(&bq->bufq_mtx); +} + +void +bufq_requeue(struct bufq *bq, struct buf *bp) +{ + mtx_enter(&bq->bufq_mtx); + while (bq->bufq_stop) { + msleep(&bq->bufq_stop, &bq->bufq_mtx, PRIBIO, "bufqstop", 0); + } + bufq_requeuev[bq->bufq_type](bq, bp); + mtx_leave(&bq->bufq_mtx); +} + +void bufq_drain(struct bufq *bq) { struct buf *bp; @@ -96,15 +133,67 @@ bufq_drain(struct bufq *bq) } void +bufq_done(struct bufq *bq, struct buf *bp) +{ + mtx_enter(&bq->bufq_mtx); + bq->bufq_outstanding--; + KASSERT(bq->bufq_outstanding >= 0); + if (bq->bufq_outstanding == 0) + wakeup(&bq->bufq_outstanding); + mtx_leave(&bq->bufq_mtx); + bp->b_bq = NULL; +} + +void +bufq_quiesce(void) +{ + struct bufq *bq; + +restart: + mtx_enter(&bufqs_mtx); + bufqs_stop = 1; + SLIST_FOREACH(bq, &bufqs, bufq_entries) { + mtx_enter(&bq->bufq_mtx); + bq->bufq_stop = 1; + if (bq->bufq_outstanding) { + mtx_leave(&bufqs_mtx); + msleep(&bq->bufq_outstanding, &bq->bufq_mtx, PRIBIO, + "bufqqui", 0); + mtx_leave(&bq->bufq_mtx); + goto restart; + } + mtx_leave(&bq->bufq_mtx); + } + mtx_leave(&bufqs_mtx); +} + +void +bufq_restart(void) +{ + struct bufq *bq; + + mtx_enter(&bufqs_mtx); + SLIST_FOREACH(bq, &bufqs, bufq_entries) { + mtx_enter(&bq->bufq_mtx); + bq->bufq_stop = 0; + wakeup(&bq->bufq_stop); + mtx_leave(&bq->bufq_mtx); + } + bufqs_stop = 0; + wakeup(&bufqs_stop); + mtx_leave(&bufqs_mtx); +} + +void bufq_disksort_queue(struct bufq *bq, struct buf *bp) { struct buf *bufq; bufq = (struct buf *)bq->bufq_data; - mtx_enter(&bq->bufq_mtx); + bq->bufq_outstanding++; + bp->b_bq = bq; disksort(bufq, bp); - mtx_leave(&bq->bufq_mtx); } void @@ -114,12 +203,12 @@ bufq_disksort_requeue(struct bufq *bq, struct buf *bp) bufq = (struct buf *)bq->bufq_data; - mtx_enter(&bq->bufq_mtx); + bq->bufq_outstanding++; + bp->b_bq = bq; bp->b_actf = bufq->b_actf; bufq->b_actf = bp; if (bp->b_actf == NULL) bufq->b_actb = &bp->b_actf; - mtx_leave(&bq->bufq_mtx); } struct buf * @@ -160,9 +249,9 @@ bufq_fifo_queue(struct bufq *bq, struct buf *bp) { struct bufq_fifo_head *head = bq->bufq_data; - mtx_enter(&bq->bufq_mtx); + bq->bufq_outstanding++; + bp->b_bq = bq; TAILQ_INSERT_TAIL(head, bp, b_bufq.bufq_data_fifo.bqf_entries); - mtx_leave(&bq->bufq_mtx); } void @@ -170,9 +259,9 @@ bufq_fifo_requeue(struct bufq *bq, struct buf *bp) { struct bufq_fifo_head *head = bq->bufq_data; - mtx_enter(&bq->bufq_mtx); + bq->bufq_outstanding++; + bp->b_bq = bq;; TAILQ_INSERT_HEAD(head, bp, b_bufq.bufq_data_fifo.bqf_entries); - mtx_leave(&bq->bufq_mtx); } struct buf * |