diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2010-09-14 01:39:45 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2010-09-14 01:39:45 +0000 |
commit | e608ae4fa52e5c4c7fa3bb2cd69920040d244dcf (patch) | |
tree | 41895d40c09d2f90c144664a525a4c01bf88e028 | |
parent | 83869b13d617de819b3677377ce544704d8a1364 (diff) |
the openings member of scsi_link is the maximum number of commands that a
scsi device can have in flight. instead of counting users of openings on
the bus by taking away from the openings value, count the number of
pending commands on the bus in a new pending variable.
this lets us know how many outstanding commands there are. we can then use
that to make sure that all commands a device has generated get completed
before detaching the device. this helps avoid resource leaks and use after
frees.
tested by me on pci ehci/umass, fc mpi, and sas mpi.
tested by jakemsr on cardbus ohci umass.
it found issues in sas mpi which were fixed as a result of this diff.
ok krw@
-rw-r--r-- | sys/scsi/scsi_base.c | 24 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 3 |
2 files changed, 18 insertions, 9 deletions
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index 167faf4d357..d13c2017556 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_base.c,v 1.194 2010/09/08 11:04:39 dlg Exp $ */ +/* $OpenBSD: scsi_base.c,v 1.195 2010/09/14 01:39:44 dlg Exp $ */ /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ /* @@ -527,7 +527,9 @@ scsi_xsh_del(struct scsi_xshandler *xsh) break; case RUNQ_POOLQ: TAILQ_REMOVE(&link->pool->queue, &xsh->ioh, q_entry); - link->openings++; + link->pending--; + if (ISSET(link->state, SDEV_S_DYING) && link->pending == 0) + wakeup_one(&link->pending); break; default: panic("unexpected xsh state %u", xsh->ioh.q_state); @@ -552,9 +554,10 @@ scsi_xsh_runqueue(struct scsi_link *link) runq = 0; mtx_enter(&link->pool->mtx); - while (!ISSET(link->state, SDEV_S_DYING) && link->openings && + while (!ISSET(link->state, SDEV_S_DYING) && + link->pending < link->openings && ((ioh = TAILQ_FIRST(&link->queue)) != NULL)) { - link->openings--; + link->pending++; TAILQ_REMOVE(&link->queue, ioh, q_entry); TAILQ_INSERT_TAIL(&link->pool->queue, ioh, q_entry); @@ -681,11 +684,14 @@ scsi_link_shutdown(struct scsi_link *link) xsh->link == link) { TAILQ_REMOVE(&iopl->queue, &xsh->ioh, q_entry); xsh->ioh.q_state = RUNQ_IDLE; - link->openings++; + link->pending--; TAILQ_INSERT_TAIL(&sleepers, &xsh->ioh, q_entry); } } + + while (link->pending > 0) + msleep(&link->pending, &iopl->mtx, PRIBIO, "pendxs", 0); mtx_leave(&iopl->mtx); while ((ioh = TAILQ_FIRST(&sleepers)) != NULL) { @@ -700,8 +706,8 @@ scsi_link_open(struct scsi_link *link) int open = 0; mtx_enter(&link->pool->mtx); - if (link->openings) { - link->openings--; + if (link->pending < link->openings) { + link->pending++; open = 1; } mtx_leave(&link->pool->mtx); @@ -713,7 +719,9 @@ void scsi_link_close(struct scsi_link *link) { mtx_enter(&link->pool->mtx); - link->openings++; + link->pending--; + if (ISSET(link->state, SDEV_S_DYING) && link->pending == 0) + wakeup_one(&link->pending); mtx_leave(&link->pool->mtx); scsi_xsh_runqueue(link); diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index 89bfa4d426d..8cee11a3f72 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.h,v 1.137 2010/09/08 00:58:05 dlg Exp $ */ +/* $OpenBSD: scsiconf.h,v 1.138 2010/09/14 01:39:44 dlg Exp $ */ /* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */ /* @@ -396,6 +396,7 @@ struct scsi_link { struct scsi_runq queue; u_int running; + u_short pending; struct scsi_iopool *pool; }; |