Work around the deadlock that occours when ATA waits for the taskqueue

to call back for completition and something else is holding the taskqueue
waiting for ATA to return data.
This should clear up the "semaphore timeout !! DANGER Will Robinson !!"
in most situations, and log "taskqueue timeout - completing request directly"
instead, with a delayed "WARNING - freeing taskqueue zombie request" when
the taskqueue finally calls us back with the now stale request.
(It would have been nice if there was a way to remove a scheduled item from
 a taskqueue, but that is not currently implemented in the kernel).

A real fix for this is in the works but wont make it to 6.1RELEASE

definite MFC candidate.
This commit is contained in:
sos 2006-03-01 07:48:41 +00:00
parent ff94cb013a
commit ba86c198c3
2 changed files with 24 additions and 7 deletions

View File

@ -372,6 +372,8 @@ struct ata_request {
#define ATA_R_DIRECT 0x00001000
#define ATA_R_DEBUG 0x10000000
#define ATA_R_DANGER1 0x20000000
#define ATA_R_DANGER2 0x40000000
u_int8_t status; /* ATA status */
u_int8_t error; /* ATA error */
@ -569,8 +571,10 @@ int ata_generic_command(struct ata_request *request);
/* macros for alloc/free of struct ata_request */
extern uma_zone_t ata_request_zone;
#define ata_alloc_request() uma_zalloc(ata_request_zone, M_NOWAIT | M_ZERO)
#define ata_free_request(request) uma_zfree(ata_request_zone, request)
#define ata_free_request(request) { \
if (!(request->flags & ATA_R_DANGER2)) \
uma_zfree(ata_request_zone, request); \
}
/* macros for alloc/free of struct ata_composite */
extern uma_zone_t ata_composite_zone;
#define ata_alloc_composite() uma_zalloc(ata_composite_zone, M_NOWAIT | M_ZERO)

View File

@ -95,12 +95,14 @@ ata_queue_request(struct ata_request *request)
/* if this is not a callback wait until request is completed */
if (!request->callback) {
ATA_DEBUG_RQ(request, "wait for completition");
while (!dumping &&
sema_timedwait(&request->done, request->timeout * hz * 4)) {
if (!dumping &&
sema_timedwait(&request->done, request->timeout * hz * 4)) {
device_printf(request->dev,
"req=%p %s semaphore timeout !! DANGER Will Robinson !!\n",
request, ata_cmd2str(request));
ata_start(ch->dev);
"WARNING - %s taskqueue timeout "
"- completing request directly\n",
ata_cmd2str(request));
request->flags |= ATA_R_DANGER1;
ata_completed(request, 0);
}
sema_destroy(&request->done);
}
@ -252,6 +254,17 @@ ata_completed(void *context, int dummy)
struct ata_device *atadev = device_get_softc(request->dev);
struct ata_composite *composite;
if (request->flags & ATA_R_DANGER2) {
device_printf(request->dev,
"WARNING - %s freeing taskqueue zombie request\n",
ata_cmd2str(request));
request->flags &= ~(ATA_R_DANGER1 | ATA_R_DANGER2);
ata_free_request(request);
return;
}
if (request->flags & ATA_R_DANGER1)
request->flags |= ATA_R_DANGER2
ATA_DEBUG_RQ(request, "completed entered");
/* if we had a timeout, reinit channel and deal with the falldown */