Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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 <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Stefan Weinhuber and committed by
Martin Schwidefsky
03513bcc 11ab244c

+6 -6
+6 -6
drivers/s390/block/dasd.c
··· 1149 1149 { 1150 1150 struct list_head *l, *n; 1151 1151 struct dasd_ccw_req *cqr; 1152 + struct dasd_block *block; 1152 1153 1153 1154 list_for_each_safe(l, n, final_queue) { 1154 1155 cqr = list_entry(l, struct dasd_ccw_req, devlist); 1155 1156 list_del_init(&cqr->devlist); 1156 - if (cqr->block) 1157 - spin_lock_bh(&cqr->block->queue_lock); 1157 + block = cqr->block; 1158 + if (block) 1159 + spin_lock_bh(&block->queue_lock); 1158 1160 switch (cqr->status) { 1159 1161 case DASD_CQR_SUCCESS: 1160 1162 cqr->status = DASD_CQR_DONE; ··· 1174 1172 cqr, cqr->status); 1175 1173 BUG(); 1176 1174 } 1177 - if (cqr->block) 1178 - spin_unlock_bh(&cqr->block->queue_lock); 1179 1175 if (cqr->callback != NULL) 1180 1176 (cqr->callback)(cqr, cqr->callback_data); 1177 + if (block) 1178 + spin_unlock_bh(&block->queue_lock); 1181 1179 } 1182 1180 } 1183 - 1184 - 1185 1181 1186 1182 /* 1187 1183 * Take a look at the first request on the ccw queue and check