--- x/drivers/nvme/target/fc.c +++ y/drivers/nvme/target/fc.c @@ -113,6 +113,7 @@ struct nvmet_fc_tgtport { struct nvmet_fc_port_entry *pe; struct kref ref; u32 max_sg_cnt; + int assoc_freed; }; struct nvmet_fc_port_entry { @@ -1271,9 +1272,17 @@ nvmet_fc_portentry_bind(struct nvmet_fc_ static void nvmet_fc_portentry_unbind(struct nvmet_fc_port_entry *pe) { + struct nvmet_fc_port_entry *entry; unsigned long flags; spin_lock_irqsave(&nvmet_fc_tgtlock, flags); + list_for_each_entry(entry, &nvmet_fc_portentry_list, pe_list) { + if (entry == pe) + goto out; + } + spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); + return; +out: if (pe->tgtport) { nvmet_fc_tgtport_put(pe->tgtport); pe->tgtport->pe = NULL; @@ -1414,7 +1423,7 @@ nvmet_fc_register_targetport(struct nvme goto out_free_newrec; } - nvmet_fc_portentry_rebind_tgt(newrec); + //nvmet_fc_portentry_rebind_tgt(newrec); spin_lock_irqsave(&nvmet_fc_tgtlock, flags); list_add_tail(&newrec->tgt_list, &nvmet_fc_target_list); @@ -1474,14 +1483,20 @@ static void __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport) { struct nvmet_fc_tgt_assoc *assoc; + unsigned long flags; + if (tgtport->assoc_freed) + return; + tgtport->assoc_freed = 1; rcu_read_lock(); + spin_lock_irqsave(&tgtport->lock, flags); list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) { if (!nvmet_fc_tgt_a_get(assoc)) continue; nvmet_fc_schedule_delete_assoc(assoc); nvmet_fc_tgt_a_put(assoc); } + spin_unlock_irqrestore(&tgtport->lock, flags); rcu_read_unlock(); } @@ -1643,8 +1658,10 @@ nvmet_fc_unregister_targetport(struct nv nvmet_fc_portentry_unbind_tgt(tgtport); + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); /* terminate any outstanding associations */ __nvmet_fc_free_assocs(tgtport); + spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); flush_workqueue(nvmet_wq); @@ -2917,6 +2934,7 @@ nvmet_fc_remove_port(struct nvmet_port * { struct nvmet_fc_port_entry *pe = port->priv; struct nvmet_fc_tgtport *tgtport = NULL; + struct nvmet_fc_tgtport *next = NULL; unsigned long flags; spin_lock_irqsave(&nvmet_fc_tgtlock, flags); @@ -2926,9 +2944,11 @@ nvmet_fc_remove_port(struct nvmet_port * nvmet_fc_portentry_unbind(pe); - if (tgtport) { + if (tgtport && next) { + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); /* terminate any outstanding associations */ __nvmet_fc_free_assocs(tgtport); + spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); nvmet_fc_tgtport_put(tgtport); }