summaryrefslogtreecommitdiffstats
path: root/sys/dev/amr
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2006-04-08 02:23:27 +0000
committerps <ps@FreeBSD.org>2006-04-08 02:23:27 +0000
commite8f84ee984b6589b7998e049b88f34d034eb7049 (patch)
treef23c1087558ca8d21c4abd3fd664e86f7a32a62b /sys/dev/amr
parentaa6df7801fd5bc684cc428915dd295b33d1ba0c1 (diff)
downloadFreeBSD-src-e8f84ee984b6589b7998e049b88f34d034eb7049.zip
FreeBSD-src-e8f84ee984b6589b7998e049b88f34d034eb7049.tar.gz
Close a pesky race where after checking the BUSY flag in amr_wait_command,
the completion of the command can occur before tsleep is called and the command ends up blocking forever since the wakeup has already been called. Submitted by: ups
Diffstat (limited to 'sys/dev/amr')
-rw-r--r--sys/dev/amr/amr.c25
-rw-r--r--sys/dev/amr/amr_pci.c1
-rw-r--r--sys/dev/amr/amrvar.h1
3 files changed, 21 insertions, 6 deletions
diff --git a/sys/dev/amr/amr.c b/sys/dev/amr/amr.c
index c8bb39e..d7e806c 100644
--- a/sys/dev/amr/amr.c
+++ b/sys/dev/amr/amr.c
@@ -383,6 +383,9 @@ amr_free(struct amr_softc *sc)
if (mtx_initialized(&sc->amr_list_lock))
mtx_destroy(&sc->amr_list_lock);
+
+ if (mtx_initialized(&sc->amr_wait_lock))
+ mtx_destroy(&sc->amr_wait_lock);
}
/*******************************************************************************
@@ -1322,7 +1325,8 @@ static int
amr_wait_command(struct amr_command *ac)
{
int error = 0;
-
+ struct amr_softc *sc = ac->ac_sc;
+
debug_called(1);
ac->ac_complete = NULL;
@@ -1331,9 +1335,12 @@ amr_wait_command(struct amr_command *ac)
return(error);
}
+ mtx_lock(&sc->amr_wait_lock);
while ((ac->ac_flags & AMR_CMD_BUSY) && (error != EWOULDBLOCK)) {
- error = tsleep(ac, PRIBIO, "amrwcmd", 0);
+ error = msleep(ac,&sc->amr_wait_lock, PRIBIO, "amrwcmd", 0);
}
+ mtx_unlock(&sc->amr_wait_lock);
+
return(error);
}
@@ -1995,21 +2002,27 @@ amr_complete(void *context, int pending)
/* unmap the command's data buffer */
amr_unmapcmd(ac);
- /* unbusy the command */
- ac->ac_flags &= ~AMR_CMD_BUSY;
-
/*
* Is there a completion handler?
*/
if (ac->ac_complete != NULL) {
+ /* unbusy the command */
+ ac->ac_flags &= ~AMR_CMD_BUSY;
ac->ac_complete(ac);
/*
* Is someone sleeping on this one?
*/
} else if (ac->ac_flags & AMR_CMD_SLEEP) {
+ mtx_lock(&sc->amr_wait_lock);
+ /* unbusy the command */
+ ac->ac_flags &= ~AMR_CMD_BUSY;
+ mtx_unlock(&sc->amr_wait_lock);
wakeup(ac);
- }
+ } else {
+ /* unbusy the command */
+ ac->ac_flags &= ~AMR_CMD_BUSY;
+ }
if(!sc->amr_busyslots) {
wakeup(sc);
diff --git a/sys/dev/amr/amr_pci.c b/sys/dev/amr/amr_pci.c
index f873edf..fafd9f2 100644
--- a/sys/dev/amr/amr_pci.c
+++ b/sys/dev/amr/amr_pci.c
@@ -331,6 +331,7 @@ amr_pci_attach(device_t dev)
*/
mtx_init(&sc->amr_list_lock, "AMR List Lock", NULL, MTX_DEF);
mtx_init(&sc->amr_hw_lock, "AMR HW Lock", NULL, MTX_DEF);
+ mtx_init(&sc->amr_wait_lock, "AMR Wait Lock", NULL, MTX_DEF);
if ((error = amr_setup_mbox(sc)) != 0)
goto out;
diff --git a/sys/dev/amr/amrvar.h b/sys/dev/amr/amrvar.h
index 2f9a728..4ff0c90 100644
--- a/sys/dev/amr/amrvar.h
+++ b/sys/dev/amr/amrvar.h
@@ -244,6 +244,7 @@ struct amr_softc
int amr_linux_no_adapters;
int amr_ld_del_supported;
struct mtx amr_hw_lock;
+ struct mtx amr_wait_lock;
};
/*
OpenPOWER on IntegriCloud