Commit 596cba55 authored by Daniel Wagner's avatar Daniel Wagner Committed by Christoph Hellwig
Browse files

nvmet-fc: take tgtport refs for portentry



Ensure that the tgtport is not going away as long portentry has a
pointer on it.

Signed-off-by: default avatarDaniel Wagner <wagi@kernel.org>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent bbccbf79
Loading
Loading
Loading
Loading
+39 −5
Original line number Diff line number Diff line
@@ -1257,6 +1257,7 @@ nvmet_fc_portentry_bind(struct nvmet_fc_tgtport *tgtport,
{
	lockdep_assert_held(&nvmet_fc_tgtlock);

	nvmet_fc_tgtport_get(tgtport);
	pe->tgtport = tgtport;
	tgtport->pe = pe;

@@ -1276,8 +1277,10 @@ nvmet_fc_portentry_unbind(struct nvmet_fc_port_entry *pe)
	unsigned long flags;

	spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
	if (pe->tgtport)
	if (pe->tgtport) {
		nvmet_fc_tgtport_put(pe->tgtport);
		pe->tgtport->pe = NULL;
	}
	list_del(&pe->pe_list);
	spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
}
@@ -1295,8 +1298,10 @@ nvmet_fc_portentry_unbind_tgt(struct nvmet_fc_tgtport *tgtport)

	spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
	pe = tgtport->pe;
	if (pe)
	if (pe) {
		nvmet_fc_tgtport_put(pe->tgtport);
		pe->tgtport = NULL;
	}
	tgtport->pe = NULL;
	spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
}
@@ -1319,6 +1324,9 @@ nvmet_fc_portentry_rebind_tgt(struct nvmet_fc_tgtport *tgtport)
	list_for_each_entry(pe, &nvmet_fc_portentry_list, pe_list) {
		if (tgtport->fc_target_port.node_name == pe->node_name &&
		    tgtport->fc_target_port.port_name == pe->port_name) {
			if (!nvmet_fc_tgtport_get(tgtport))
				continue;

			WARN_ON(pe->tgtport);
			tgtport->pe = pe;
			pe->tgtport = tgtport;
@@ -2888,12 +2896,17 @@ nvmet_fc_add_port(struct nvmet_port *port)
	list_for_each_entry(tgtport, &nvmet_fc_target_list, tgt_list) {
		if ((tgtport->fc_target_port.node_name == traddr.nn) &&
		    (tgtport->fc_target_port.port_name == traddr.pn)) {
			if (!nvmet_fc_tgtport_get(tgtport))
				continue;

			/* a FC port can only be 1 nvmet port id */
			if (!tgtport->pe) {
				nvmet_fc_portentry_bind(tgtport, pe, port);
				ret = 0;
			} else
				ret = -EALREADY;

			nvmet_fc_tgtport_put(tgtport);
			break;
		}
	}
@@ -2909,11 +2922,21 @@ static void
nvmet_fc_remove_port(struct nvmet_port *port)
{
	struct nvmet_fc_port_entry *pe = port->priv;
	struct nvmet_fc_tgtport *tgtport = NULL;
	unsigned long flags;

	spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
	if (pe->tgtport && nvmet_fc_tgtport_get(pe->tgtport))
		tgtport = pe->tgtport;
	spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);

	nvmet_fc_portentry_unbind(pe);

	if (tgtport) {
		/* terminate any outstanding associations */
	__nvmet_fc_free_assocs(pe->tgtport);
		__nvmet_fc_free_assocs(tgtport);
		nvmet_fc_tgtport_put(tgtport);
	}

	kfree(pe);
}
@@ -2922,10 +2945,21 @@ static void
nvmet_fc_discovery_chg(struct nvmet_port *port)
{
	struct nvmet_fc_port_entry *pe = port->priv;
	struct nvmet_fc_tgtport *tgtport = pe->tgtport;
	struct nvmet_fc_tgtport *tgtport = NULL;
	unsigned long flags;

	spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
	if (pe->tgtport && nvmet_fc_tgtport_get(pe->tgtport))
		tgtport = pe->tgtport;
	spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);

	if (!tgtport)
		return;

	if (tgtport && tgtport->ops->discovery_event)
		tgtport->ops->discovery_event(&tgtport->fc_target_port);

	nvmet_fc_tgtport_put(tgtport);
}

static ssize_t