]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nvmet-fc: take tgtport refs for portentry
authorDaniel Wagner <wagi@kernel.org>
Wed, 7 May 2025 12:23:09 +0000 (14:23 +0200)
committerChristoph Hellwig <hch@lst.de>
Tue, 20 May 2025 03:34:26 +0000 (05:34 +0200)
Ensure that the tgtport is not going away as long portentry has a
pointer on it.

Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/target/fc.c

index b8985559d1f14e6729996e1670c19dbe353e3895..254537b93e633cea9746101d9c2389bf08fffcab 100644 (file)
@@ -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);
 
-       /* terminate any outstanding associations */
-       __nvmet_fc_free_assocs(pe->tgtport);
+       if (tgtport) {
+               /* terminate any outstanding associations */
+               __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