[Open-FCoE] [RFC][PATCH 2/3] libfc: Track rogue ports

Abhijeet Joglekar abjoglek at cisco.com
Mon Feb 16 19:13:54 UTC 2009


libfc: Track rogue ports

Rogue ports are currently not tracked on any list (both to name server and
to other peers). The only reference to them is through any outstanding
exchanges pending on the rogue ports. If a module is removed while a retry
is set on a rogue port (say a Plogi retry for instance), this retry is not
cancelled because there is no reference to the rogue port in the discovery
rports list. Thus the local port can clean itself up, delete the exchange
pool, and then the rogue port timeout can fire and try to start up another
exchange.

This patch tracks the regular rogue port in the disc->rports list, and the
name server rogue port in the lport->dns_rp variable. Current assumptions
are:

1) Whenever a rogue port is created, it is immediately tracked in the
disc->rports or lport->dns_rp

2) When the rogue port goes to ready, it is removed from the list, and the
real scsi_transport_fc rport is added to the list

3) The removal of the rogue from the list is done in the fc_rport_work() in
discovery callback.

4) The removal of a real remote port from the list is also done in the
fc_rport_work() in discovery callback. This treats both remote and rogue
ports the same, instead of having to make checks at multiple places while
doing list_del to check if its a rogue or real port.

5) Thus ports are added early to the list (right when they are created)
and before calling rport_login, and are removed late from the list
(fc_rport_work context).

Signed-off-by: Abhijeet Joglekar <abjoglek at cisco.com>

Signed-off-by: Abhijeet Joglekar <abjoglek at cisco.com>
---
 drivers/scsi/libfc/fc_disc.c  |   33 +++++++++++++++++----------------
 drivers/scsi/libfc/fc_lport.c |    1 +
 drivers/scsi/libfc/fc_rport.c |    3 +++
 3 files changed, 21 insertions(+), 16 deletions(-)


diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 5431b20..b90a59f 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -101,7 +101,6 @@ void fc_disc_stop_rports(struct fc_disc *disc)
 	mutex_lock(&disc->disc_mutex);
 	list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
 		rport = PRIV_TO_RPORT(rdata);
-		list_del(&rdata->peers);
 		lport->tt.rport_logoff(rport);
 	}
 
@@ -123,23 +122,30 @@ static void fc_disc_rport_callback(struct fc_lport *lport,
 {
 	struct fc_rport_libfc_priv *rdata = rport->dd_data;
 	struct fc_disc *disc = &lport->disc;
-	int found = 0;
 
 	FC_DISC_DBG("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_LOGO:
+	case RPORT_EV_FAILED:
+	case RPORT_EV_STOP:
+		mutex_lock(&disc->disc_mutex);
+		list_del(&rdata->peers);
+		mutex_unlock(&disc->disc_mutex);
+		break;
+	default:
+		break;
+
 	}
 
-	if (!found)
-		FC_DISC_DBG("The rport (%6x) is not maintained "
-			    "by the discovery layer\n", rport->port_id);
 }
 
 /**
@@ -239,7 +245,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
 			rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
 			if (rport) {
 				rdata = rport->dd_data;
-				list_del(&rdata->peers);
 				lport->tt.rport_logoff(rport);
 			}
 			fc_disc_single(disc, dp);
@@ -304,7 +309,6 @@ static void fc_disc_restart(struct fc_disc *disc)
 
 	list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
 		rport = PRIV_TO_RPORT(rdata);
-		list_del(&rdata->peers);
 		lport->tt.rport_logoff(rport);
 	}
 
@@ -431,6 +435,7 @@ static int fc_disc_new_target(struct fc_disc *disc,
 			rdata = rport->dd_data;
 			rdata->ops = &fc_disc_rport_ops;
 			rdata->rp_state = RPORT_ST_INIT;
+			list_add_tail(&rdata->peers, &disc->rports);
 			lport->tt.rport_login(rport);
 		}
 	}
@@ -445,8 +450,7 @@ static int fc_disc_new_target(struct fc_disc *disc,
 static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport)
 {
 	struct fc_lport *lport = disc->lport;
-	struct fc_rport_libfc_priv *rdata = rport->dd_data;
-	list_del(&rdata->peers);
+
 	lport->tt.rport_logoff(rport);
 }
 
@@ -618,6 +622,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
 				rdata = rport->dd_data;
 				rdata->ops = &fc_disc_rport_ops;
 				rdata->local_port = lport;
+				list_add_tail(&rdata->peers, &disc->rports);
 				lport->tt.rport_login(rport);
 			} else
 				printk(KERN_WARNING "libfc: Failed to allocate "
@@ -757,7 +762,6 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
 static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)
 {
 	struct fc_lport *lport;
-	struct fc_rport *rport;
 	struct fc_rport *new_rport;
 	struct fc_rport_libfc_priv *rdata;
 
@@ -766,15 +770,12 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)
 	if (dp->ids.port_id == fc_host_port_id(lport->host))
 		goto out;
 
-	rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
-	if (rport)
-		fc_disc_del_target(disc, rport);
-
 	new_rport = lport->tt.rport_create(dp);
 	if (new_rport) {
 		rdata = new_rport->dd_data;
 		rdata->ops = &fc_disc_rport_ops;
 		kfree(dp);
+		list_add_tail(&rdata->peers, &disc->rports);
 		lport->tt.rport_login(new_rport);
 	}
 	return;
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 274ca39..7d2588c 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -1285,6 +1285,7 @@ static void fc_lport_enter_dns(struct fc_lport *lport)
 
 	rdata = rport->dd_data;
 	rdata->ops = &fc_lport_rport_ops;
+	lport->dns_rp = rport;
 	lport->tt.rport_login(rport);
 	return;
 
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index fc13a40..92615fb 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -259,6 +259,9 @@ static void fc_rport_work(struct work_struct *work)
 			       " memory for rport (%6x)\n", ids.port_id);
 			event = RPORT_EV_FAILED;
 		}
+		if (rport_ops->event_callback)
+			rport_ops->event_callback(lport, rport,
+						  RPORT_EV_FAILED);
 		put_device(&rport->dev);
 		rport = new_rport;
 		rdata = new_rport->dd_data;





More information about the devel mailing list