mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-28 11:43:25 +02:00
115 lines
5.1 KiB
Diff
115 lines
5.1 KiB
Diff
From: Robert Love <robert.w.love@intel.com>
|
|
Subject: [FcOE] Improve fc_lport.c locking comment block
|
|
References: bnc #459142
|
|
|
|
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
|
Acked-by: Bernhard Walle <bwalle@suse.de>
|
|
---
|
|
|
|
drivers/scsi/libfc/fc_lport.c | 76 ++++++++++++++++++++++++------------------
|
|
1 file changed, 45 insertions(+), 31 deletions(-)
|
|
|
|
|
|
--- a/drivers/scsi/libfc/fc_lport.c
|
|
+++ b/drivers/scsi/libfc/fc_lport.c
|
|
@@ -18,34 +18,51 @@
|
|
*/
|
|
|
|
/*
|
|
- * General locking notes:
|
|
+ * PORT LOCKING NOTES
|
|
*
|
|
- * The lport and rport blocks both have mutexes that are used to protect
|
|
- * the port objects states. The main motivation for this protection is that
|
|
- * we don't want to be preparing a request/response in one context while
|
|
- * another thread "resets" the port in question. For example, if the lport
|
|
- * block is sending a SCR request to the directory server we don't want
|
|
- * the lport to be reset before we fill out the frame header's port_id. The
|
|
- * problem is that a reset would cause the lport's port_id to reset to 0.
|
|
- * If we don't protect the lport we'd spew incorrect frames.
|
|
- *
|
|
- * At the time of this writing there are two primary mutexes, one for the
|
|
- * lport and one for the rport. Since the lport uses the rport and makes
|
|
- * calls into that block the rport should never make calls that would cause
|
|
- * the lport's mutex to be locked. In other words, the lport's mutex is
|
|
- * considered the outer lock and the rport's lock is considered the inner
|
|
- * lock. The bottom line is that you can hold a lport's mutex and then
|
|
- * hold the rport's mutex, but not the other way around.
|
|
- *
|
|
- * The only complication to this rule is the callbacks from the rport to
|
|
- * the lport's rport_callback function. When rports become READY they make
|
|
- * a callback to the lport so that it can track them. In the case of the
|
|
- * directory server that callback might cause the lport to change its
|
|
- * state, implying that the lport mutex would need to be held. This problem
|
|
- * was solved by serializing the rport notifications to the lport and the
|
|
- * callback is made without holding the rport's lock.
|
|
+ * These comments only apply to the 'port code' which consists of the lport,
|
|
+ * disc and rport blocks.
|
|
*
|
|
- * lport locking notes:
|
|
+ * MOTIVATION
|
|
+ *
|
|
+ * The lport, disc and rport blocks all have mutexes that are used to protect
|
|
+ * those objects. The main motivation for these locks is to prevent from
|
|
+ * having an lport reset just before we send a frame. In that scenario the
|
|
+ * lport's FID would get set to zero and then we'd send a frame with an
|
|
+ * invalid SID. We also need to ensure that states don't change unexpectedly
|
|
+ * while processing another state.
|
|
+ *
|
|
+ * HEIRARCHY
|
|
+ *
|
|
+ * The following heirarchy defines the locking rules. A greater lock
|
|
+ * may be held before acquiring a lesser lock, but a lesser lock should never
|
|
+ * be held while attempting to acquire a greater lock. Here is the heirarchy-
|
|
+ *
|
|
+ * lport > disc, lport > rport, disc > rport
|
|
+ *
|
|
+ * CALLBACKS
|
|
+ *
|
|
+ * The callbacks cause complications with this scheme. There is a callback
|
|
+ * from the rport (to either lport or disc) and a callback from disc
|
|
+ * (to the lport).
|
|
+ *
|
|
+ * As rports exit the rport state machine a callback is made to the owner of
|
|
+ * the rport to notify success or failure. Since the callback is likely to
|
|
+ * cause the lport or disc to grab its lock we cannot hold the rport lock
|
|
+ * while making the callback. To ensure that the rport is not free'd while
|
|
+ * processing the callback the rport callbacks are serialized through a
|
|
+ * single-threaded workqueue. An rport would never be free'd while in a
|
|
+ * callback handler becuase no other rport work in this queue can be executed
|
|
+ * at the same time.
|
|
+ *
|
|
+ * When discovery succeeds or fails a callback is made to the lport as
|
|
+ * notification. Currently, succesful discovery causes the lport to take no
|
|
+ * action. A failure will cause the lport to reset. There is likely a circular
|
|
+ * locking problem with this implementation.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * LPORT LOCKING
|
|
*
|
|
* The critical sections protected by the lport's mutex are quite broad and
|
|
* may be improved upon in the future. The lport code and its locking doesn't
|
|
@@ -54,9 +71,9 @@
|
|
*
|
|
* The strategy is to lock whenever processing a request or response. Note
|
|
* that every _enter_* function corresponds to a state change. They generally
|
|
- * change the lports state and then sends a request out on the wire. We lock
|
|
+ * change the lports state and then send a request out on the wire. We lock
|
|
* before calling any of these functions to protect that state change. This
|
|
- * means that the entry points into the lport block to manage the locks while
|
|
+ * means that the entry points into the lport block manage the locks while
|
|
* the state machine can transition between states (i.e. _enter_* functions)
|
|
* while always staying protected.
|
|
*
|
|
@@ -68,9 +85,6 @@
|
|
* Retries also have to consider the locking. The retries occur from a work
|
|
* context and the work function will lock the lport and then retry the state
|
|
* (i.e. _enter_* function).
|
|
- *
|
|
- * The implication to all of this is that each lport can only process one
|
|
- * state at a time.
|
|
*/
|
|
|
|
#include <linux/timer.h>
|