mirror of
https://github.com/torvalds/linux
synced 2024-09-23 12:56:39 +00:00
[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:
parent
161155519c
commit
d5da3040d7
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue