Found a race in scsipi_execute_xs(): if an asynchronous transfer completes

(probably due to an interrupt) between the time it is scheduled and the
time we get around to setting the SCSI_ASYNCREQ flag, we can lose the xs.

Fix this by checking to see if the transfer has already completed after
the scsi_cmd function returns SUCCESSFULLY_QUEUED, and just return to the
caller if so.
This commit is contained in:
scottr 1998-09-16 05:35:50 +00:00
parent 43f5b65e23
commit 4963603d0f
1 changed files with 13 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsipi_base.c,v 1.9 1998/09/14 05:49:21 scottr Exp $ */
/* $NetBSD: scsipi_base.c,v 1.10 1998/09/16 05:35:50 scottr Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -417,19 +417,30 @@ retry:
#endif
switch (scsipi_command_direct(xs)) {
case SUCCESSFULLY_QUEUED:
s = splbio();
if (xs->flags & ITSDONE) {
/*
* The request has already completed, probably due
* to an interrupt arriving between the time the
* request was scheduled and when we arrived at this
* point.
*/
splx(s);
return (0);
}
if ((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP) {
/*
* The request will complete asynchronously. In this
* case, we need scsipi_done() to free the scsipi_xfer.
*/
xs->flags |= SCSI_ASYNCREQ;
splx(s);
return (EJUSTRETURN);
}
#ifdef DIAGNOSTIC
if (xs->flags & SCSI_NOSLEEP)
panic("scsipi_execute_xs: NOSLEEP and POLL");
#endif
s = splbio();
while ((xs->flags & ITSDONE) == 0)
tsleep(xs, PRIBIO + 1, "scsipi_cmd", 0);
splx(s);