s390/dasd: Implement block timeout handling
This patch implements generic block layer timeout handling callbacks for DASDs. When the timeout expires the respective cqr is aborted. With this timeout handler time-critical request abort is guaranteed as the abort does not depend on the internal state of the various DASD driver queues. Signed-off-by: Hannes Reinecke <hare@suse.de> Acked-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Родитель
1fbdb8be9b
Коммит
a2ace46632
|
@ -2573,8 +2573,10 @@ static void __dasd_process_request_queue(struct dasd_block *block)
|
|||
*/
|
||||
cqr->callback_data = (void *) req;
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
req->completion_data = cqr;
|
||||
blk_start_request(req);
|
||||
list_add_tail(&cqr->blocklist, &block->ccw_queue);
|
||||
INIT_LIST_HEAD(&cqr->devlist);
|
||||
dasd_profile_start(block, cqr, req);
|
||||
}
|
||||
}
|
||||
|
@ -2861,6 +2863,80 @@ static void do_dasd_request(struct request_queue *queue)
|
|||
spin_unlock(&block->queue_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Block timeout callback, called from the block layer
|
||||
*
|
||||
* request_queue lock is held on entry.
|
||||
*
|
||||
* Return values:
|
||||
* BLK_EH_RESET_TIMER if the request should be left running
|
||||
* BLK_EH_NOT_HANDLED if the request is handled or terminated
|
||||
* by the driver.
|
||||
*/
|
||||
enum blk_eh_timer_return dasd_times_out(struct request *req)
|
||||
{
|
||||
struct dasd_ccw_req *cqr = req->completion_data;
|
||||
struct dasd_block *block = req->q->queuedata;
|
||||
struct dasd_device *device;
|
||||
int rc = 0;
|
||||
|
||||
if (!cqr)
|
||||
return BLK_EH_NOT_HANDLED;
|
||||
|
||||
device = cqr->startdev ? cqr->startdev : block->base;
|
||||
DBF_DEV_EVENT(DBF_WARNING, device,
|
||||
" dasd_times_out cqr %p status %x",
|
||||
cqr, cqr->status);
|
||||
|
||||
spin_lock(&block->queue_lock);
|
||||
spin_lock(get_ccwdev_lock(device->cdev));
|
||||
cqr->retries = -1;
|
||||
cqr->intrc = -ETIMEDOUT;
|
||||
if (cqr->status >= DASD_CQR_QUEUED) {
|
||||
spin_unlock(get_ccwdev_lock(device->cdev));
|
||||
rc = dasd_cancel_req(cqr);
|
||||
} else if (cqr->status == DASD_CQR_FILLED ||
|
||||
cqr->status == DASD_CQR_NEED_ERP) {
|
||||
cqr->status = DASD_CQR_TERMINATED;
|
||||
spin_unlock(get_ccwdev_lock(device->cdev));
|
||||
} else if (cqr->status == DASD_CQR_IN_ERP) {
|
||||
struct dasd_ccw_req *searchcqr, *nextcqr, *tmpcqr;
|
||||
|
||||
list_for_each_entry_safe(searchcqr, nextcqr,
|
||||
&block->ccw_queue, blocklist) {
|
||||
tmpcqr = searchcqr;
|
||||
while (tmpcqr->refers)
|
||||
tmpcqr = tmpcqr->refers;
|
||||
if (tmpcqr != cqr)
|
||||
continue;
|
||||
/* searchcqr is an ERP request for cqr */
|
||||
searchcqr->retries = -1;
|
||||
searchcqr->intrc = -ETIMEDOUT;
|
||||
if (searchcqr->status >= DASD_CQR_QUEUED) {
|
||||
spin_unlock(get_ccwdev_lock(device->cdev));
|
||||
rc = dasd_cancel_req(searchcqr);
|
||||
spin_lock(get_ccwdev_lock(device->cdev));
|
||||
} else if ((searchcqr->status == DASD_CQR_FILLED) ||
|
||||
(searchcqr->status == DASD_CQR_NEED_ERP)) {
|
||||
searchcqr->status = DASD_CQR_TERMINATED;
|
||||
rc = 0;
|
||||
} else if (searchcqr->status == DASD_CQR_IN_ERP) {
|
||||
/*
|
||||
* Shouldn't happen; most recent ERP
|
||||
* request is at the front of queue
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
spin_unlock(get_ccwdev_lock(device->cdev));
|
||||
}
|
||||
dasd_schedule_block_bh(block);
|
||||
spin_unlock(&block->queue_lock);
|
||||
|
||||
return rc ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and initialize request queue and default I/O scheduler.
|
||||
*/
|
||||
|
|
|
@ -583,7 +583,10 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
|
|||
|
||||
static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
if (cqr->retries < 0)
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
else
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
};
|
||||
|
||||
/* Fill in IOCTL data for device. */
|
||||
|
|
|
@ -2381,6 +2381,10 @@ sleep:
|
|||
|
||||
static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
if (cqr->retries < 0) {
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
return;
|
||||
}
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
if (cqr->block && (cqr->startdev != cqr->block->base)) {
|
||||
dasd_eckd_reset_ccw_to_base_io(cqr);
|
||||
|
|
|
@ -428,7 +428,10 @@ out:
|
|||
|
||||
static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
if (cqr->retries < 0)
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
else
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
Загрузка…
Ссылка в новой задаче