From 0b03bcd2f93d7766d3bfd31c6bb8f7fa39299edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Schmidt?= Date: Wed, 1 Mar 2006 07:48:41 +0000 Subject: [PATCH] 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. --- sys/dev/ata/ata-all.h | 8 ++++++-- sys/dev/ata/ata-queue.c | 23 ++++++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 1b98e040738..436182495cd 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -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) diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 036b0081f9a..5de54ffadc9 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -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 */