diff options
author | ps <ps@FreeBSD.org> | 2006-04-08 02:23:27 +0000 |
---|---|---|
committer | ps <ps@FreeBSD.org> | 2006-04-08 02:23:27 +0000 |
commit | e8f84ee984b6589b7998e049b88f34d034eb7049 (patch) | |
tree | f23c1087558ca8d21c4abd3fd664e86f7a32a62b /sys/dev/amr | |
parent | aa6df7801fd5bc684cc428915dd295b33d1ba0c1 (diff) | |
download | FreeBSD-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.c | 25 | ||||
-rw-r--r-- | sys/dev/amr/amr_pci.c | 1 | ||||
-rw-r--r-- | sys/dev/amr/amrvar.h | 1 |
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; }; /* |