Skip to content

Commit

Permalink
[SCSI] ibmvscsi: Fix error path deadlock
Browse files Browse the repository at this point in the history
Fixes a deadlock that can occur if we hit a command timeout
during the virtual adapter initialization. The event done
functions are written with the assumption that no locks are held,
however, when purging requests this is not true. Fix up the
purge function to drop the lock so that the done function
is not called with the lock held, which can cause a deadlock.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Brian King authored and James Bottomley committed Jul 27, 2010
1 parent 0f33ece commit 1117ef8
Showing 1 changed file with 17 additions and 14 deletions.
31 changes: 17 additions & 14 deletions drivers/scsi/ibmvscsi/ibmvscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,23 +474,26 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
*/
static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
{
struct srp_event_struct *tmp_evt, *pos;
struct srp_event_struct *evt;
unsigned long flags;

spin_lock_irqsave(hostdata->host->host_lock, flags);
list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
list_del(&tmp_evt->list);
del_timer(&tmp_evt->timer);
if (tmp_evt->cmnd) {
tmp_evt->cmnd->result = (error_code << 16);
unmap_cmd_data(&tmp_evt->iu.srp.cmd,
tmp_evt,
tmp_evt->hostdata->dev);
if (tmp_evt->cmnd_done)
tmp_evt->cmnd_done(tmp_evt->cmnd);
} else if (tmp_evt->done)
tmp_evt->done(tmp_evt);
free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
while (!list_empty(&hostdata->sent)) {
evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
list_del(&evt->list);
del_timer(&evt->timer);

spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (evt->cmnd) {
evt->cmnd->result = (error_code << 16);
unmap_cmd_data(&evt->iu.srp.cmd, evt,
evt->hostdata->dev);
if (evt->cmnd_done)
evt->cmnd_done(evt->cmnd);
} else if (evt->done)
evt->done(evt);
free_event_struct(&evt->hostdata->pool, evt);
spin_lock_irqsave(hostdata->host->host_lock, flags);
}
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
}
Expand Down

0 comments on commit 1117ef8

Please sign in to comment.