summaryrefslogtreecommitdiff
path: root/sys/kern/kern_bufq.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-06-29 18:52:21 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-06-29 18:52:21 +0000
commitd39a9ee347bd5a3e56a3272fbf50afe828620da6 (patch)
tree7b9e57dde86b7685fc2cb1cfc4dafb0b434991bf /sys/kern/kern_bufq.c
parent6393ccd109d17c92e6427fba5730a05c7e4ac29c (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.c113
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 *