From d5da3040d798df4bbb62579b97f8b6b83749da22 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 5 Aug 2010 16:38:31 -0500 Subject: [PATCH] [SCSI] ibmvfc: Fix rport add/delete race resulting in oops Commit 43c8da907ccc656935d1085701f4db83385d8a59 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 Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.c | 8 ++++++++ drivers/scsi/ibmvscsi/ibmvfc.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index bd96cecaa61..a13db590842 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -433,6 +433,9 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, { switch (tgt->action) { case IBMVFC_TGT_ACTION_DEL_RPORT: + if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) + tgt->action = action; + case IBMVFC_TGT_ACTION_DELETED_RPORT: break; default: 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) { tgt_dbg(tgt, "Deleting rport\n"); list_del(&tgt->queue); + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); spin_unlock_irqrestore(vhost->host->host_lock, flags); fc_remote_port_delete(rport); del_timer_sync(&tgt->timer); kref_put(&tgt->kref, ibmvfc_release_tgt); return; + } else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return; } if (rport) { @@ -4297,6 +4304,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) rport = tgt->rport; tgt->rport = NULL; list_del(&tgt->queue); + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); spin_unlock_irqrestore(vhost->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index d7e8dcd9065..af48172112f 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -597,6 +597,7 @@ enum ibmvfc_target_action { IBMVFC_TGT_ACTION_INIT, IBMVFC_TGT_ACTION_INIT_WAIT, IBMVFC_TGT_ACTION_DEL_RPORT, + IBMVFC_TGT_ACTION_DELETED_RPORT, }; struct ibmvfc_target { -- 2.39.3