From e608ae4fa52e5c4c7fa3bb2cd69920040d244dcf Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Tue, 14 Sep 2010 01:39:45 +0000 Subject: 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@ --- sys/scsi/scsi_base.c | 24 ++++++++++++++++-------- 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; }; -- cgit v1.2.3