]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/libfc-ensure-correct-device_pu.diff
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / libfc-ensure-correct-device_pu.diff
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libfc-ensure-correct-device_pu.diff b/src/patches/suse-2.6.27.31/patches.drivers/libfc-ensure-correct-device_pu.diff
new file mode 100644 (file)
index 0000000..ad60ec2
--- /dev/null
@@ -0,0 +1,214 @@
+From: Robert Love <robert.w.love@intel.com>
+Subject: libfc: Ensure correct device_put/get usage (round 2)
+References: 
+
+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 <robert.w.love@intel.com>
+Acked-by: Bernhard Walle <bwalle@suse.de>
+---
+
+ drivers/scsi/libfc/fc_disc.c  |    5 +----
+ drivers/scsi/libfc/fc_lport.c |    5 ++---
+ drivers/scsi/libfc/fc_rport.c |   21 ++++++++++++++-------
+ 3 files changed, 17 insertions(+), 14 deletions(-)
+
+
+--- a/drivers/scsi/libfc/fc_disc.c
++++ b/drivers/scsi/libfc/fc_disc.c
+@@ -81,7 +81,6 @@ struct fc_rport *fc_disc_lookup_rport(co
+               if (rport->port_id == port_id) {
+                       disc_found = 1;
+                       found = rport;
+-                      get_device(&found->dev);
+                       break;
+               }
+       }
+@@ -767,10 +766,8 @@ static void fc_disc_single(struct fc_dis
+               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) {
+--- a/drivers/scsi/libfc/fc_lport.c
++++ b/drivers/scsi/libfc/fc_lport.c
+@@ -908,10 +908,9 @@ static void fc_lport_recv_req(struct fc_
+                       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;
+--- a/drivers/scsi/libfc/fc_rport.c
++++ b/drivers/scsi/libfc/fc_rport.c
+@@ -111,16 +111,11 @@ struct fc_rport *fc_rport_rogue_create(s
+       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);
+-      get_device(&rport->dev);
++      rport->dev.release = fc_rport_rogue_destroy; // XXX: bwalle
+       mutex_init(&rdata->rp_mutex);
+       rdata->local_port = dp->lp;
+@@ -402,9 +397,9 @@ static void fc_rport_timeout(struct work
+       case RPORT_ST_NONE:
+               break;
+       }
+-      put_device(&rport->dev);
+       mutex_unlock(&rdata->rp_mutex);
++      put_device(&rport->dev);
+ }
+ /**
+@@ -531,6 +526,7 @@ out:
+       fc_frame_free(fp);
+ err:
+       mutex_unlock(&rdata->rp_mutex);
++      put_device(&rport->dev);
+ }
+ /**
+@@ -562,6 +558,8 @@ static void fc_rport_enter_plogi(struct 
+       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);
+ }
+ /**
+@@ -631,6 +629,7 @@ out:
+       fc_frame_free(fp);
+ err:
+       mutex_unlock(&rdata->rp_mutex);
++      put_device(&rport->dev);
+ }
+ /**
+@@ -679,6 +678,7 @@ out:
+       fc_frame_free(fp);
+ err:
+       mutex_unlock(&rdata->rp_mutex);
++      put_device(&rport->dev);
+ }
+ /**
+@@ -712,6 +712,8 @@ static void fc_rport_enter_prli(struct f
+       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);
+ }
+ /**
+@@ -777,6 +779,7 @@ out:
+       fc_frame_free(fp);
+ err:
+       mutex_unlock(&rdata->rp_mutex);
++      put_device(&rport->dev);
+ }
+ /**
+@@ -806,6 +809,8 @@ static void fc_rport_enter_rtv(struct fc
+       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);
+ }
+ /**
+@@ -835,6 +840,8 @@ static void fc_rport_enter_logo(struct f
+       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);
+ }