提交 03513bcc 编写于 作者: S Stefan Weinhuber 提交者: Martin Schwidefsky

[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: NStefan Weinhuber <wein@de.ibm.com>
Signed-off-by: NMartin Schwidefsky <schwidefsky@de.ibm.com>
上级 11ab244c
...@@ -1149,12 +1149,14 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, ...@@ -1149,12 +1149,14 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
{ {
struct list_head *l, *n; struct list_head *l, *n;
struct dasd_ccw_req *cqr; struct dasd_ccw_req *cqr;
struct dasd_block *block;
list_for_each_safe(l, n, final_queue) { list_for_each_safe(l, n, final_queue) {
cqr = list_entry(l, struct dasd_ccw_req, devlist); cqr = list_entry(l, struct dasd_ccw_req, devlist);
list_del_init(&cqr->devlist); list_del_init(&cqr->devlist);
if (cqr->block) block = cqr->block;
spin_lock_bh(&cqr->block->queue_lock); if (block)
spin_lock_bh(&block->queue_lock);
switch (cqr->status) { switch (cqr->status) {
case DASD_CQR_SUCCESS: case DASD_CQR_SUCCESS:
cqr->status = DASD_CQR_DONE; cqr->status = DASD_CQR_DONE;
...@@ -1172,15 +1174,13 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, ...@@ -1172,15 +1174,13 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
cqr, cqr->status); cqr, cqr->status);
BUG(); BUG();
} }
if (cqr->block)
spin_unlock_bh(&cqr->block->queue_lock);
if (cqr->callback != NULL) if (cqr->callback != NULL)
(cqr->callback)(cqr, cqr->callback_data); (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 * Take a look at the first request on the ccw queue and check
* if it reached its expire time. If so, terminate the IO. * if it reached its expire time. If so, terminate the IO.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册