diff options
author | scottl <scottl@FreeBSD.org> | 2005-02-09 11:44:15 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2005-02-09 11:44:15 +0000 |
commit | c7b1a38815c93b4ae58373b7d449d694687fb0e3 (patch) | |
tree | c841b26e8adf09333f9af8bddb1d96c032a0439a /sys | |
parent | 5770c8b1bdd946a156d6649a9993cb0f8e3b1cad (diff) | |
download | FreeBSD-src-c7b1a38815c93b4ae58373b7d449d694687fb0e3.zip FreeBSD-src-c7b1a38815c93b4ae58373b7d449d694687fb0e3.tar.gz |
Provide locking for the ccb_bioq. This allows xpt_done() to be called without
Giant held. In camisr(), move the ccb_bioq elements to a temporary local list
and then process the elements off of that list. This enables the list to be
processed by only taking the ccb_bioq_lock once and only for a very short
time.
ccb_bioq_lock is a leaf mutex, so it's fine to call xpt_done() with other
locks held. This is just a very minor step in the work to lock CAM, but
it allows us to avoid some messy locking/unlock dances in certain drivers.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/cam/cam_xpt.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index e522b62..128d729 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -43,6 +43,9 @@ __FBSDID("$FreeBSD$"); #include <sys/interrupt.h> #include <sys/sbuf.h> +#include <sys/lock.h> +#include <sys/mutex.h> + #ifdef PC98 #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ #endif @@ -613,6 +616,7 @@ static struct xpt_softc xsoftc; /* Queues for our software interrupt handler */ typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; static cam_isrq_t cam_bioq; +static struct mtx cam_bioq_lock; /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ static SLIST_HEAD(,ccb_hdr) ccb_freeq; @@ -1383,6 +1387,8 @@ xpt_init(dummy) SLIST_INIT(&ccb_freeq); STAILQ_INIT(&highpowerq); + mtx_init(&cam_bioq_lock, "CAM BIOQ lock", NULL, MTX_DEF); + /* * The xpt layer is, itself, the equivelent of a SIM. * Allow 16 ccbs in the ccb pool for it. This should @@ -4830,8 +4836,6 @@ xpt_done(union ccb *done_ccb) { int s; - GIANT_REQUIRED; - s = splcam(); CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); @@ -4842,9 +4846,11 @@ xpt_done(union ccb *done_ccb) */ switch (done_ccb->ccb_h.path->periph->type) { case CAM_PERIPH_BIO: + mtx_lock(&cam_bioq_lock); TAILQ_INSERT_TAIL(&cam_bioq, &done_ccb->ccb_h, sim_links.tqe); done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; + mtx_unlock(&cam_bioq_lock); swi_sched(cambio_ih, 0); break; default: @@ -6973,15 +6979,26 @@ xptpoll(struct cam_sim *sim) static void camisr(void *V_queue) { - cam_isrq_t *queue = V_queue; + cam_isrq_t *oqueue = V_queue; + cam_isrq_t queue; int s; struct ccb_hdr *ccb_h; + /* + * Transfer the ccb_bioq list to a temporary list so we can operate + * on it without needing to lock/unlock on every loop. The concat + * function with re-init the real list for us. + */ s = splcam(); - while ((ccb_h = TAILQ_FIRST(queue)) != NULL) { + mtx_lock(&cam_bioq_lock); + TAILQ_INIT(&queue); + TAILQ_CONCAT(&queue, oqueue, sim_links.tqe); + mtx_unlock(&cam_bioq_lock); + + while ((ccb_h = TAILQ_FIRST(&queue)) != NULL) { int runq; - TAILQ_REMOVE(queue, ccb_h, sim_links.tqe); + TAILQ_REMOVE(&queue, ccb_h, sim_links.tqe); ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; splx(s); |