Fix a FWXF_INQ race in the firewire driver.

sys/dev/firewire/firewire.c:
	In fw_xfer_unload() expand lock coverage so that
	the test for FWXF_INQ doesn't race with it being
	cleared in another thread.

Submitted by:	gibbs
MFC after:	1 week
Sponsored by:	Spectra Logic
MFSpectraBSD:	1110207 on 2015/01/02
This commit is contained in:
Will Andrews 2015-01-21 20:02:16 +00:00
parent 26f1289e49
commit ff9ae2210b

View File

@ -1022,9 +1022,7 @@ static void
fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer)
{
struct fw_xfer *txfer;
int s;
s = splfw();
mtx_lock(&fc->tlabel_lock);
if (xfer->tl < 0) {
mtx_unlock(&fc->tlabel_lock);
@ -1042,14 +1040,12 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer)
fw_dump_hdr(&xfer->recv.hdr, "recv");
kdb_backtrace();
mtx_unlock(&fc->tlabel_lock);
splx(s);
return;
}
STAILQ_REMOVE(&fc->tlabels[xfer->tl], xfer, fw_xfer, tlabel);
xfer->tl = -1;
mtx_unlock(&fc->tlabel_lock);
splx(s);
return;
}
@ -1157,22 +1153,18 @@ fw_xfer_done(struct fw_xfer *xfer)
void
fw_xfer_unload(struct fw_xfer *xfer)
{
int s;
if (xfer == NULL)
return;
FW_GLOCK(xfer->fc);
if (xfer->flag & FWXF_INQ) {
printf("fw_xfer_free FWXF_INQ\n");
s = splfw();
FW_GLOCK(xfer->fc);
STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link);
xfer->flag &= ~FWXF_INQ;
#if 0
xfer->q->queued--;
#endif
FW_GUNLOCK(xfer->fc);
splx(s);
}
FW_GUNLOCK(xfer->fc);
if (xfer->fc != NULL) {
/*
* Ensure that any tlabel owner can't access this