From 03513bccad33667ed738cfd96dc5757e539e0bdb Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Tue, 19 Feb 2008 15:29:27 +0100 Subject: [S390] dasd: fix locking in __dasd_device_process_final_queue After setting the status of the cqr and releasing the lock for the block cqr queue, we call the cqr callback function, which will usually just trigger the dasd_block_tasklet. But when the tasklet is already running the cqr might be processed before we invoke the callback function. In rare cases the callback pointer may already be invalid by the time we want to call it, which will result in a panic. Solution: Call the callback function first and then release the lock. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/s390/block') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d984e0fae63..ccf46c96adb 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1149,12 +1149,14 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, { struct list_head *l, *n; struct dasd_ccw_req *cqr; + struct dasd_block *block; list_for_each_safe(l, n, final_queue) { cqr = list_entry(l, struct dasd_ccw_req, devlist); list_del_init(&cqr->devlist); - if (cqr->block) - spin_lock_bh(&cqr->block->queue_lock); + block = cqr->block; + if (block) + spin_lock_bh(&block->queue_lock); switch (cqr->status) { case DASD_CQR_SUCCESS: cqr->status = DASD_CQR_DONE; @@ -1172,15 +1174,13 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, cqr, cqr->status); BUG(); } - if (cqr->block) - spin_unlock_bh(&cqr->block->queue_lock); if (cqr->callback != NULL) (cqr->callback)(cqr, cqr->callback_data); + if (block) + spin_unlock_bh(&block->queue_lock); } } - - /* * Take a look at the first request on the ccw queue and check * if it reached its expire time. If so, terminate the IO. -- cgit v1.2.3