[SCSI] ibmvfc: Fix rport add/delete race resulting in oops

Commit 43c8da907c introduced a race
condition which can occur when adding/deleting rports. There are
two possible threads now that can be deleting rports in the ibmvfc
driver, which can result in list_del being called twice, resulting
in an oops. This patch adds a new state to the ibmvfc_target struct
to indicate the target has been removed from the list and is in
the process of being deleted.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
Brian King 2010-08-05 16:38:31 -05:00 committed by James Bottomley
parent 161155519c
commit d5da3040d7
2 changed files with 9 additions and 0 deletions

View file

@ -433,6 +433,9 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt,
{ {
switch (tgt->action) { switch (tgt->action) {
case IBMVFC_TGT_ACTION_DEL_RPORT: case IBMVFC_TGT_ACTION_DEL_RPORT:
if (action == IBMVFC_TGT_ACTION_DELETED_RPORT)
tgt->action = action;
case IBMVFC_TGT_ACTION_DELETED_RPORT:
break; break;
default: default:
if (action == IBMVFC_TGT_ACTION_DEL_RPORT) if (action == IBMVFC_TGT_ACTION_DEL_RPORT)
@ -4193,11 +4196,15 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
tgt_dbg(tgt, "Deleting rport\n"); tgt_dbg(tgt, "Deleting rport\n");
list_del(&tgt->queue); list_del(&tgt->queue);
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT);
spin_unlock_irqrestore(vhost->host->host_lock, flags); spin_unlock_irqrestore(vhost->host->host_lock, flags);
fc_remote_port_delete(rport); fc_remote_port_delete(rport);
del_timer_sync(&tgt->timer); del_timer_sync(&tgt->timer);
kref_put(&tgt->kref, ibmvfc_release_tgt); kref_put(&tgt->kref, ibmvfc_release_tgt);
return; return;
} else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) {
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return;
} }
if (rport) { if (rport) {
@ -4297,6 +4304,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
rport = tgt->rport; rport = tgt->rport;
tgt->rport = NULL; tgt->rport = NULL;
list_del(&tgt->queue); list_del(&tgt->queue);
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT);
spin_unlock_irqrestore(vhost->host->host_lock, flags); spin_unlock_irqrestore(vhost->host->host_lock, flags);
if (rport) if (rport)
fc_remote_port_delete(rport); fc_remote_port_delete(rport);

View file

@ -597,6 +597,7 @@ enum ibmvfc_target_action {
IBMVFC_TGT_ACTION_INIT, IBMVFC_TGT_ACTION_INIT,
IBMVFC_TGT_ACTION_INIT_WAIT, IBMVFC_TGT_ACTION_INIT_WAIT,
IBMVFC_TGT_ACTION_DEL_RPORT, IBMVFC_TGT_ACTION_DEL_RPORT,
IBMVFC_TGT_ACTION_DELETED_RPORT,
}; };
struct ibmvfc_target { struct ibmvfc_target {