[Open-FCoE] [RFC PATCH 4/5] libfc: track rogue rports on the disc->rports list

Robert Love robert.w.love at intel.com
Wed Jan 28 20:49:16 UTC 2009


We weren't able to free rogue rports becuase they weren't tracked. This scenario would
happen if an rport state needed to be retried. The rport timer would start and the
rport wasn't maintained by any list or exchange. There was nothing to stop the timer
so if the local port was reset the timer would still exist and fire later with bad
results.

This patch has the rogue rports added to the disc->rports list so when the lport
is destroyed or reset it will cancel the timers and, stop/free each of the rogue
rports.

Signed-off-by: Robert Love <robert.w.love at intel.com>
---

 drivers/scsi/libfc/fc_disc.c  |   23 ++++++++++++++++++++++-
 drivers/scsi/libfc/fc_rport.c |   10 ++++++++++
 2 files changed, 32 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index aa3cb03..42fc0ed 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -138,13 +138,27 @@ static void fc_disc_rport_callback(struct fc_lport *lport,
 	FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event,
 		      rport->port_id);
 
-	if (event == RPORT_EV_CREATED) {
+	switch (event) {
+	case RPORT_EV_CREATED:
 		if (disc) {
 			found = 1;
 			mutex_lock(&disc->disc_mutex);
 			list_add_tail(&rdata->peers, &disc->rports);
 			mutex_unlock(&disc->disc_mutex);
 		}
+		break;
+	case RPORT_EV_FAILED:
+		if (disc) {
+			if (rdata->trans_state == FC_PORTSTATE_ROGUE) {
+				found = 1;
+				mutex_lock(&disc->disc_mutex);
+				list_del(&rdata->peers);
+				mutex_unlock(&disc->disc_mutex);
+			}
+		}
+		break;
+	default:
+		break;
 	}
 
 	if (!found)
@@ -433,6 +447,9 @@ static int fc_disc_new_target(struct fc_disc *disc,
 				dp.ids.node_name = ids->node_name;
 				dp.ids.roles = ids->roles;
 				rport = lport->tt.rport_create(&dp);
+				rdata = RPORT_TO_PRIV(rport);
+				/* Add the rogue rport to the disc list */
+				list_add_tail(&rdata->peers, &disc->rports);
 			}
 			if (!rport)
 				error = -ENOMEM;
@@ -624,6 +641,8 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
 				rdata = RPORT_TO_PRIV(rport);
 				rdata->ops = &fc_disc_rport_ops;
 				rdata->local_port = lport;
+				/* Add the rogue rport to the disc list */
+				list_add_tail(&rdata->peers, &disc->rports);
 				lport->tt.rport_login(rport);
 			} else
 				FC_DBG("Failed to allocate memory for "
@@ -776,6 +795,8 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)
 		rdata = RPORT_TO_PRIV(new_rport);
 		rdata->ops = &fc_disc_rport_ops;
 		kfree(dp);
+		/* Add the rogue rport to the disc list */
+		list_add_tail(&rdata->peers, &disc->rports);
 		lport->tt.rport_login(new_rport);
 	}
 	return;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 918ce9b..13dd606 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -269,11 +269,21 @@ static void fc_rport_work(struct work_struct *work)
 			       "(%6x).\n", ids.port_id);
 			event = RPORT_EV_FAILED;
 		}
+
+		/* Callback with the rogue rport so it can be removed from the disc list */
+		if (rport_ops->event_callback)
+                        rport_ops->event_callback(lport, rport, RPORT_EV_FAILED);
+
+		/* This put should cause the rogue rport to be freed */
 		put_device(&rport->dev);
+
 		rport = new_rport;
 		rdata = RPORT_TO_PRIV(new_rport);
+
+		/* Callback with the real rport so it can be added to the disc list */
 		if (rport_ops->event_callback)
 			rport_ops->event_callback(lport, rport, event);
+
 	} else if ((event == RPORT_EV_FAILED) ||
 		   (event == RPORT_EV_LOGO) ||
 		   (event == RPORT_EV_STOP)) {




More information about the devel mailing list