[SCSI] fix oops on usb storage device disconnect
We fix the oops by enforcing the host state model. There have also been two extra states added: SHOST_CANCEL_RECOVERY and SHOST_DEL_RECOVERY so we can take the model through host removal while the recovery thread is active. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
这个提交包含在:
@@ -68,19 +68,24 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
|
||||
{
|
||||
struct Scsi_Host *shost = scmd->device->host;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (shost->eh_wait == NULL)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (scsi_host_set_state(shost, SHOST_RECOVERY))
|
||||
if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY))
|
||||
goto out_unlock;
|
||||
|
||||
ret = 1;
|
||||
scmd->eh_eflags |= eh_flag;
|
||||
list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
|
||||
scsi_host_set_state(shost, SHOST_RECOVERY);
|
||||
shost->host_failed++;
|
||||
scsi_eh_wakeup(shost);
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,8 +181,8 @@ void scsi_times_out(struct scsi_cmnd *scmd)
|
||||
}
|
||||
|
||||
if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
|
||||
panic("Error handler thread not present at %p %p %s %d",
|
||||
scmd, scmd->device->host, __FILE__, __LINE__);
|
||||
scmd->result |= DID_TIME_OUT << 16;
|
||||
__scsi_done(scmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,8 +201,7 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev)
|
||||
{
|
||||
int online;
|
||||
|
||||
wait_event(sdev->host->host_wait, (sdev->host->shost_state !=
|
||||
SHOST_RECOVERY));
|
||||
wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host));
|
||||
|
||||
online = scsi_device_online(sdev);
|
||||
|
||||
@@ -1441,6 +1445,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
|
||||
static void scsi_restart_operations(struct Scsi_Host *shost)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* If the door was locked, we need to insert a door lock request
|
||||
@@ -1460,7 +1465,11 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
|
||||
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
|
||||
__FUNCTION__));
|
||||
|
||||
scsi_host_set_state(shost, SHOST_RUNNING);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (scsi_host_set_state(shost, SHOST_RUNNING))
|
||||
if (scsi_host_set_state(shost, SHOST_CANCEL))
|
||||
BUG_ON(scsi_host_set_state(shost, SHOST_DEL));
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
wake_up(&shost->host_wait);
|
||||
|
||||
|
在新工单中引用
屏蔽一个用户