From: Hannes Reinecke <hare@suse.de>
To: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: James Bottomley <james.bottomley@hansenpartnership.com>,
Christoph Hellwig <hch@lst.de>,
Johannes Thumshirn <jth@kernel.org>,
linux-scsi@vger.kernel.org, Mike Snitzer <snitzer@redhat.com>,
Martin Wilck <martin.wilck@suse.com>,
Hannes Reinecke <hare@suse.de>, Hannes Reinecke <hare@suse.com>
Subject: [PATCH 01/30] libfc: Revisit kref handling
Date: Fri, 26 Aug 2016 14:01:24 +0200 [thread overview]
Message-ID: <1472212913-39810-2-git-send-email-hare@suse.de> (raw)
In-Reply-To: <1472212913-39810-1-git-send-email-hare@suse.de>
The kref handling in fc_rport is a mess. This patch updates
the kref handling according to the following rules:
- Take a reference whenever scheduling a workqueue
- Take a reference whenever an ELS command is send
- Drop the reference at the end of the workqueue function
- Drop the reference at the end of handling ELS replies
- Take a reference when allocating an rport
- Drop the reference when removing an rport
Signed-off-by: Hannes Reinecke <hare@suse.com>
---
drivers/scsi/libfc/fc_rport.c | 136 ++++++++++++++++++++++++++++++++----------
1 file changed, 105 insertions(+), 31 deletions(-)
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 97aeadd..8909280 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -44,6 +44,19 @@
* path this potential over-use of the mutex is acceptable.
*/
+/*
+ * RPORT REFERENCE COUNTING
+ *
+ * A rport reference should be taken when:
+ * - an rport is allocated
+ * - a workqueue item is scheduled
+ * - an ELS request is send
+ * The reference should be dropped when:
+ * - the workqueue function has finished
+ * - the ELS response is handled
+ * - an rport is removed
+ */
+
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
@@ -242,6 +255,8 @@ static void fc_rport_state_enter(struct fc_rport_priv *rdata,
/**
* fc_rport_work() - Handler for remote port events in the rport_event_queue
* @work: Handle to the remote port being dequeued
+ *
+ * Reference counting: drops kref on return
*/
static void fc_rport_work(struct work_struct *work)
{
@@ -272,8 +287,10 @@ static void fc_rport_work(struct work_struct *work)
kref_get(&rdata->kref);
mutex_unlock(&rdata->rp_mutex);
- if (!rport)
+ if (!rport) {
+ FC_RPORT_DBG(rdata, "No rport!\n");
rport = fc_remote_port_add(lport->host, 0, &ids);
+ }
if (!rport) {
FC_RPORT_DBG(rdata, "Failed to add the rport\n");
lport->tt.rport_logoff(rdata);
@@ -329,7 +346,8 @@ static void fc_rport_work(struct work_struct *work)
FC_RPORT_DBG(rdata, "lld callback ev %d\n", event);
rdata->lld_event_callback(lport, rdata, event);
}
- cancel_delayed_work_sync(&rdata->retry_work);
+ if (cancel_delayed_work_sync(&rdata->retry_work))
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
/*
* Reset any outstanding exchanges before freeing rport.
@@ -381,6 +399,7 @@ static void fc_rport_work(struct work_struct *work)
mutex_unlock(&rdata->rp_mutex);
break;
}
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
/**
@@ -431,10 +450,14 @@ static int fc_rport_login(struct fc_rport_priv *rdata)
* Set the new event so that the old pending event will not occur.
* Since we have the mutex, even if fc_rport_work() is already started,
* it'll see the new event.
+ *
+ * Reference counting: does not modify kref
*/
static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
enum fc_rport_event event)
{
+ struct fc_lport *lport = rdata->local_port;
+
if (rdata->rp_state == RPORT_ST_DELETE)
return;
@@ -442,8 +465,11 @@ static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
fc_rport_state_enter(rdata, RPORT_ST_DELETE);
- if (rdata->event == RPORT_EV_NONE)
- queue_work(rport_event_queue, &rdata->event_work);
+ kref_get(&rdata->kref);
+ if (rdata->event == RPORT_EV_NONE &&
+ !queue_work(rport_event_queue, &rdata->event_work))
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+
rdata->event = event;
}
@@ -496,15 +522,22 @@ out:
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: schedules workqueue, does not modify kref
*/
static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
{
+ struct fc_lport *lport = rdata->local_port;
+
fc_rport_state_enter(rdata, RPORT_ST_READY);
FC_RPORT_DBG(rdata, "Port is Ready\n");
- if (rdata->event == RPORT_EV_NONE)
- queue_work(rport_event_queue, &rdata->event_work);
+ kref_get(&rdata->kref);
+ if (rdata->event == RPORT_EV_NONE &&
+ !queue_work(rport_event_queue, &rdata->event_work))
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+
rdata->event = RPORT_EV_READY;
}
@@ -515,13 +548,17 @@ static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
* Locking Note: Called without the rport lock held. This
* function will hold the rport lock, call an _enter_*
* function and then unlock the rport.
+ *
+ * Reference counting: Drops kref on return.
*/
static void fc_rport_timeout(struct work_struct *work)
{
struct fc_rport_priv *rdata =
container_of(work, struct fc_rport_priv, retry_work.work);
+ struct fc_lport *lport = rdata->local_port;
mutex_lock(&rdata->rp_mutex);
+ FC_RPORT_DBG(rdata, "Port timeout, state %s\n", fc_rport_state(rdata));
switch (rdata->rp_state) {
case RPORT_ST_FLOGI:
@@ -547,6 +584,7 @@ static void fc_rport_timeout(struct work_struct *work)
}
mutex_unlock(&rdata->rp_mutex);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
/**
@@ -556,6 +594,8 @@ static void fc_rport_timeout(struct work_struct *work)
*
* Locking Note: The rport lock is expected to be held before
* calling this routine
+ *
+ * Reference counting: does not modify kref
*/
static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
{
@@ -602,11 +642,14 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
*
* Locking Note: The rport lock is expected to be held before
* calling this routine
+ *
+ * Reference counting: increments kref when scheduling retry_work
*/
static void fc_rport_error_retry(struct fc_rport_priv *rdata,
struct fc_frame *fp)
{
unsigned long delay = msecs_to_jiffies(FC_DEF_E_D_TOV);
+ struct fc_lport *lport = rdata->local_port;
/* make sure this isn't an FC_EX_CLOSED error, never retry those */
if (PTR_ERR(fp) == -FC_EX_CLOSED)
@@ -619,7 +662,9 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata,
/* no additional delay on exchange timeouts */
if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
delay = 0;
- schedule_delayed_work(&rdata->retry_work, delay);
+ kref_get(&rdata->kref);
+ if (!schedule_delayed_work(&rdata->retry_work, delay))
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
return;
}
@@ -740,6 +785,8 @@ bad:
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: increments kref when sending ELS
*/
static void fc_rport_enter_flogi(struct fc_rport_priv *rdata)
{
@@ -758,18 +805,21 @@ static void fc_rport_enter_flogi(struct fc_rport_priv *rdata)
if (!fp)
return fc_rport_error_retry(rdata, fp);
+ kref_get(&rdata->kref);
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI,
fc_rport_flogi_resp, rdata,
- 2 * lport->r_a_tov))
+ 2 * lport->r_a_tov)) {
fc_rport_error_retry(rdata, NULL);
- else
- kref_get(&rdata->kref);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
}
/**
* fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode
* @lport: The local port that received the PLOGI request
* @rx_fp: The PLOGI request frame
+ *
+ * Reference counting: drops kref on return
*/
static void fc_rport_recv_flogi_req(struct fc_lport *lport,
struct fc_frame *rx_fp)
@@ -824,8 +874,7 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
* RPORT wouldn;t have created and 'rport_lookup' would have
* failed anyway in that case.
*/
- if (lport->point_to_multipoint)
- break;
+ break;
case RPORT_ST_DELETE:
mutex_unlock(&rdata->rp_mutex);
rjt_data.reason = ELS_RJT_FIP;
@@ -969,6 +1018,8 @@ fc_rport_compatible_roles(struct fc_lport *lport, struct fc_rport_priv *rdata)
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: increments kref when sending ELS
*/
static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
{
@@ -995,12 +1046,13 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
}
rdata->e_d_tov = lport->e_d_tov;
+ kref_get(&rdata->kref);
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
fc_rport_plogi_resp, rdata,
- 2 * lport->r_a_tov))
+ 2 * lport->r_a_tov)) {
fc_rport_error_retry(rdata, NULL);
- else
- kref_get(&rdata->kref);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
}
/**
@@ -1108,6 +1160,8 @@ err:
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: increments kref when sending ELS
*/
static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
{
@@ -1151,11 +1205,12 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
fc_host_port_id(lport->host), FC_TYPE_ELS,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+ kref_get(&rdata->kref);
if (!lport->tt.exch_seq_send(lport, fp, fc_rport_prli_resp,
- NULL, rdata, 2 * lport->r_a_tov))
+ NULL, rdata, 2 * lport->r_a_tov)) {
fc_rport_error_retry(rdata, NULL);
- else
- kref_get(&rdata->kref);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
}
/**
@@ -1230,6 +1285,8 @@ err:
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: increments kref when sending ELS
*/
static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
{
@@ -1247,12 +1304,13 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
return;
}
+ kref_get(&rdata->kref);
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
fc_rport_rtv_resp, rdata,
- 2 * lport->r_a_tov))
+ 2 * lport->r_a_tov)) {
fc_rport_error_retry(rdata, NULL);
- else
- kref_get(&rdata->kref);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
}
/**
@@ -1262,15 +1320,16 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
* @lport_arg: The local port
*/
static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *lport_arg)
+ void *rdata_arg)
{
- struct fc_lport *lport = lport_arg;
+ struct fc_rport_priv *rdata = rdata_arg;
+ struct fc_lport *lport = rdata->local_port;
FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did,
"Received a LOGO %s\n", fc_els_resp_type(fp));
- if (IS_ERR(fp))
- return;
- fc_frame_free(fp);
+ if (!IS_ERR(fp))
+ fc_frame_free(fp);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
/**
@@ -1279,6 +1338,8 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: increments kref when sending ELS
*/
static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
{
@@ -1291,8 +1352,10 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
if (!fp)
return;
- (void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
- fc_rport_logo_resp, lport, 0);
+ kref_get(&rdata->kref);
+ if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
+ fc_rport_logo_resp, rdata, 0))
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
/**
@@ -1359,6 +1422,8 @@ err:
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
+ *
+ * Reference counting: increments kref when sending ELS
*/
static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
{
@@ -1375,12 +1440,13 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
fc_rport_error_retry(rdata, fp);
return;
}
+ kref_get(&rdata->kref);
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC,
fc_rport_adisc_resp, rdata,
- 2 * lport->r_a_tov))
+ 2 * lport->r_a_tov)) {
fc_rport_error_retry(rdata, NULL);
- else
- kref_get(&rdata->kref);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
}
/**
@@ -1494,6 +1560,8 @@ out:
* The ELS opcode has already been validated by the caller.
*
* Locking Note: Called with the lport lock held.
+ *
+ * Reference counting: does not modify kref
*/
static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
{
@@ -1561,6 +1629,8 @@ reject:
* @fp: The request frame
*
* Locking Note: Called with the lport lock held.
+ *
+ * Reference counting: does not modify kref
*/
static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
{
@@ -1605,6 +1675,8 @@ static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
* @rx_fp: The PLOGI request frame
*
* Locking Note: The rport lock is held before calling this function.
+ *
+ * Reference counting: increments kref on return
*/
static void fc_rport_recv_plogi_req(struct fc_lport *lport,
struct fc_frame *rx_fp)
@@ -1919,6 +1991,8 @@ drop:
*
* Locking Note: The rport lock is expected to be held before calling
* this function.
+ *
+ * Reference counting: drops kref on return
*/
static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
{
--
1.8.5.6
next prev parent reply other threads:[~2016-08-26 12:02 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-26 12:01 [PATCH 00/30] FCoE VN2VN fixes Hannes Reinecke
2016-08-26 12:01 ` Hannes Reinecke [this message]
2016-08-26 13:37 ` [PATCH 01/30] libfc: Revisit kref handling Johannes Thumshirn
2016-08-26 12:01 ` [PATCH 02/30] libfc: additional debugging messages Hannes Reinecke
2016-08-26 12:01 ` [PATCH 03/30] libfc: spurious I/O error under high load Hannes Reinecke
2016-08-26 12:01 ` [PATCH 04/30] libfc: Do not login if the port is already started Hannes Reinecke
2016-08-26 12:01 ` [PATCH 05/30] libfc: use configured lport R_A_TOV when sending Hannes Reinecke
2016-08-26 12:01 ` [PATCH 06/30] libfc: use configured e_d_tov for remote port state Hannes Reinecke
2016-08-26 12:01 ` [PATCH 07/30] libfc: do not overwrite DID_TIME_OUT status Hannes Reinecke
2016-08-26 12:01 ` [PATCH 08/30] libfc: use error code for fc_rport_error() Hannes Reinecke
2016-08-26 12:01 ` [PATCH 09/30] libfc: Send LS_RJT responses on frame allocation Hannes Reinecke
2016-08-26 12:01 ` [PATCH 10/30] libfc: don't advance state machine for incoming FLOGI Hannes Reinecke
2016-08-26 12:01 ` [PATCH 11/30] libfc: Fixup disc_mutex handling Hannes Reinecke
2016-08-26 12:01 ` [PATCH 12/30] libfc: Do not drop down to FLOGI for fc_rport_login() Hannes Reinecke
2016-08-26 12:01 ` [PATCH 13/30] libfc: Implement RTV responder Hannes Reinecke
2016-08-26 12:01 ` [PATCH 14/30] libfc: Rework PRLI handling Hannes Reinecke
2016-08-26 12:01 ` [PATCH 15/30] libfc: Return LS_RJT_BUSY for PRLI in status PLOGI Hannes Reinecke
2016-08-26 12:01 ` [PATCH 16/30] libfc: Clarify ramp-down messages Hannes Reinecke
2016-08-26 12:01 ` [PATCH 17/30] libfc: sanitize E_D_TOV and R_A_TOV setting Hannes Reinecke
2016-08-26 12:01 ` [PATCH 18/30] libfc: safeguard against invalid exchange index Hannes Reinecke
2016-08-26 12:01 ` [PATCH 19/30] libfc: quarantine timed out xids Hannes Reinecke
2016-08-26 12:01 ` [PATCH 20/30] libfc: don't fail sequence abort for completed Hannes Reinecke
2016-08-26 12:01 ` [PATCH 21/30] libfc: Do not drop out-of-order frames Hannes Reinecke
2016-08-26 12:01 ` [PATCH 22/30] libfc: reset timeout on queue full Hannes Reinecke
2016-08-26 12:01 ` [PATCH 23/30] libfc: wait for E_D_TOV when out-of-order sequence is received Hannes Reinecke
2016-08-26 12:01 ` [PATCH 24/30] fcoe: Use kfree_skb() instead of kfree() Hannes Reinecke
2016-08-26 12:01 ` [PATCH 25/30] fcoe: set default TC priority Hannes Reinecke
2016-08-26 12:01 ` [PATCH 26/30] fcoe: inhibit writing invalid values into the 'enabled' Hannes Reinecke
2016-08-26 12:01 ` [PATCH 27/30] fcoe: correct sending FIP VLAN packets on VLAN 0 Hannes Reinecke
2016-08-26 12:01 ` [PATCH 28/30] fcoe: FIP debugging Hannes Reinecke
2016-08-26 12:01 ` [PATCH 29/30] fcoe: filter out frames from invalid vlans Hannes Reinecke
2016-08-26 12:01 ` [PATCH 30/30] fcoe: make R_A_TOV and E_D_TOV configurable Hannes Reinecke
2016-08-26 13:48 ` [PATCH 00/30] FCoE VN2VN fixes Johannes Thumshirn
2016-08-31 2:46 ` Martin K. Petersen
2016-08-31 7:25 ` Johannes Thumshirn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1472212913-39810-2-git-send-email-hare@suse.de \
--to=hare@suse.de \
--cc=hare@suse.com \
--cc=hch@lst.de \
--cc=james.bottomley@hansenpartnership.com \
--cc=jth@kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=martin.wilck@suse.com \
--cc=snitzer@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).