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:
parent
ff94cb013a
commit
ba86c198c3
@ -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)
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user