Reference counting was barely used and where used
it was incorrect. This patch creates a few simple
policies.
When the rport->dev [e.g. struct device] is initialized
it starts with a refcnt of 1. Whenever we're using the
rport we will increment the count. When we logoff we
should decrement the count to 0 and the 'release'
function will be called. The FC transport provides the
release function for real rports and libfc provides it
for rogue rports. When we switch from a rogue to real
rport we'll decrement the refcnt on the rogue rport
and increment it for the real rport, after we've created
it.
Any externally initiated action on an rport (login,
logoff) will not require the caller to increment and
decrement the refcnt.
For rport_login(), the rport will have just been created
and therefore no other thread would be able to access
this object.
For rport_logoff(), the rport will have been removed
from the list of rports and therefore no other thread
would be able to lookup() this rport.
This patch removes the get_device() from the rport_lookup
function. These are the places where it is called and why
we don't need a reference.
fc_disc_recv_rscn_req() - called for single port RSCNs
the disc mutex is held and
ensures that no other thread
will find this rport.
fc_disc_new_target() - Same. The rport cannot be looked up
so no other thread can free the rport.
This code looks buggy though, we
shouldn't be calling rport_login() on
a 'real' rport, which we could do.
fc_disc_single() - Same. disc mutex protects the list.
fc_lport_recv_req() - Similar, but this time the lport lock
ensures that no incoming requests are
processed until the current request
for an rport has returned.
When the rport layer needs to send a request it will
increment the count so that the EM can be confident that
the rport is present when making the callback. If
fc_remote_port_delete() is called before the response
callback, which is often the case for LOGO commands, the
refcnt will still have a value of 1 becuase we grabbed the
lock before the ctels_send() is called. The exchange would
have been removed and so the callback will be called with
an error code. After processing the error code we'll
decrement the refcnt for the last time and the rport will
be free'd.
Since point-to-point mode is not working this patch
does not consider point-to-point.
Signed-off-by: Robert Love <[EMAIL PROTECTED]>
---
drivers/scsi/libfc/fc_disc.c | 5 +----
drivers/scsi/libfc/fc_lport.c | 5 ++---
drivers/scsi/libfc/fc_rport.c | 21 +++++++++++++--------
3 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index f30ce90..4d96f69 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -96,7 +96,6 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport
*lport,
if (rport->port_id == port_id) {
disc_found = 1;
found = rport;
- get_device(&found->dev);
break;
}
}
@@ -808,10 +807,8 @@ static void fc_disc_single(struct fc_disc *disc, struct
fc_disc_port *dp)
goto out;
rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
- if (rport) {
+ if (rport)
fc_disc_del_target(disc, rport);
- put_device(&rport->dev); /* hold from lookup */
- }
new_rport = fc_rport_rogue_create(dp);
if (new_rport) {
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 28b4642..18f6688 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -896,10 +896,9 @@ static void fc_lport_recv_req(struct fc_lport *lport,
struct fc_seq *sp,
d_id = ntoh24(fh->fh_d_id);
rport = lport->tt.rport_lookup(lport, s_id);
- if (rport) {
+ if (rport)
lport->tt.rport_recv_req(sp, fp, rport);
- put_device(&rport->dev); /* hold from lookup */
- } else {
+ else {
rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_UNAB;
rjt_data.explan = ELS_EXPL_NONE;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 4272196..ced342a 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -115,19 +115,12 @@ struct fc_rport *fc_rport_rogue_create(struct
fc_disc_port *dp)
rport->roles = dp->ids.roles;
rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
/*
- * init the device, so other code can manipulate the rport as if
- * it came from the fc class. We also do an extra get because
- * libfc will free this rport instead of relying on the normal
- * refcounting.
- *
* Note: all this libfc rogue rport code will be removed for
* upstream so it fine that this is really ugly and hacky right now.
*/
device_initialize(&rport->dev);
rport->dev.release = fc_rport_rogue_destroy;
- get_device(&rport->dev);
-
mutex_init(&rdata->rp_mutex);
rdata->local_port = dp->lp;
rdata->trans_state = FC_PORTSTATE_ROGUE;
@@ -403,9 +396,9 @@ static void fc_rport_timeout(struct work_struct *work)
case RPORT_ST_NONE:
break;
}
- put_device(&rport->dev);
mutex_unlock(&rdata->rp_mutex);
+ put_device(&rport->dev);
}
/**
@@ -532,6 +525,7 @@ out:
fc_frame_free(fp);
err:
mutex_unlock(&rdata->rp_mutex);
+ put_device(&rport->dev);
}
/**
@@ -563,6 +557,8 @@ static void fc_rport_enter_plogi(struct fc_rport *rport)
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI,
fc_rport_plogi_resp, rport, lport->e_d_tov))
fc_rport_error(rport, fp);
+ else
+ get_device(&rport->dev);
}
/**
@@ -632,6 +628,7 @@ out:
fc_frame_free(fp);
err:
mutex_unlock(&rdata->rp_mutex);
+ put_device(&rport->dev);
}
/**
@@ -680,6 +677,7 @@ out:
fc_frame_free(fp);
err:
mutex_unlock(&rdata->rp_mutex);
+ put_device(&rport->dev);
}
/**
@@ -713,6 +711,8 @@ static void fc_rport_enter_prli(struct fc_rport *rport)
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI,
fc_rport_prli_resp, rport, lport->e_d_tov))
fc_rport_error(rport, fp);
+ else
+ get_device(&rport->dev);
}
/**
@@ -778,6 +778,7 @@ out:
fc_frame_free(fp);
err:
mutex_unlock(&rdata->rp_mutex);
+ put_device(&rport->dev);
}
/**
@@ -807,6 +808,8 @@ static void fc_rport_enter_rtv(struct fc_rport *rport)
if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV,
fc_rport_rtv_resp, rport, lport->e_d_tov))
fc_rport_error(rport, fp);
+ else
+ get_device(&rport->dev);
}
/**
@@ -836,6 +839,8 @@ static void fc_rport_enter_logo(struct fc_rport *rport)
if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO,
fc_rport_logo_resp, rport, lport->e_d_tov))
fc_rport_error(rport, fp);
+ else
+ get_device(&rport->dev);
}
_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel