Prevent opening multiple RMPP MAD transaction sessions at responder side
with the same TID, GID/LID, class.

Could happen if RMPP requests are retried while response is in progress.

Signed-off-by: Jack Morgenstein <[EMAIL PROTECTED]>

Index: openib_branch1.0/drivers/infiniband/core/mad.c
===================================================================
--- openib_branch1.0.orig/drivers/infiniband/core/mad.c
+++ openib_branch1.0/drivers/infiniband/core/mad.c
@@ -1038,6 +1038,102 @@ int ib_send_mad(struct ib_mad_send_wr_pr
        return ret;
 }
 
+static inline int is_rmpp_data(struct ib_mad *mad)
+{
+       struct ib_rmpp_mad *r;
+
+       if (!ib_is_mad_class_rmpp(mad->mad_hdr.mgmt_class))
+               return 0;
+
+       r = (struct ib_rmpp_mad *)mad;
+       return (ib_get_rmpp_flags(&r->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE) &&
+              r->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA;
+}
+
+static inline int send_has_same_class(struct ib_mad_send_wr_private *mwr1,
+                                struct ib_mad_send_wr_private *mwr2)
+{
+       return (((struct ib_mad *)(mwr1->send_buf.mad))->mad_hdr.mgmt_class ==
+               ((struct ib_mad *)(mwr2->send_buf.mad))->mad_hdr.mgmt_class);
+}
+
+static int send_has_same_gid(struct ib_mad_agent_private *agent,
+                            struct ib_mad_send_wr_private *lwr,
+                            struct ib_mad_send_wr_private *swr)
+{
+       struct ib_ah_attr sattr, lattr;
+       u8 lmethod = ((struct ib_mad *)(lwr->send_buf.mad))->mad_hdr.method;
+       u8 smethod = ((struct ib_mad *)(swr->send_buf.mad))->mad_hdr.method;
+       u8 lmc;
+
+       /* one is a response mad, other is not */
+       if ((lmethod & IB_MGMT_METHOD_RESP) != (smethod & IB_MGMT_METHOD_RESP))
+               return 0;
+
+       /* need to compare GIDs/LIDs */
+       if (ib_query_ah(swr->send_buf.ah, &sattr) ||
+           ib_query_ah(lwr->send_buf.ah, &lattr))
+               /* No AH data. Assume not equal, to avoid false positives. */
+               return 0;
+
+       if (!(smethod & IB_MGMT_METHOD_RESP)) {
+               /* Is not a response */
+               if (!(lattr.ah_flags & IB_AH_GRH) &&
+                   !(sattr.ah_flags & IB_AH_GRH)) {
+                       /* no GIDs, compare src_path_bits */
+                       if (ib_get_cached_lmc(agent->agent.device,
+                                             agent->agent.port_num,
+                                             &lmc))
+                               return 0;
+                       return (!lmc || !((sattr.src_path_bits ^
+                                          lattr.src_path_bits) &
+                                         ((1 << lmc) - 1)));
+               }
+               if ((lattr.ah_flags & IB_AH_GRH) && (sattr.ah_flags & 
IB_AH_GRH))
+                       return lattr.grh.sgid_index == sattr.grh.sgid_index;
+               return 0;
+       }
+
+       /* comparing send responses */
+       if (!(lattr.ah_flags & IB_AH_GRH) && !(sattr.ah_flags & IB_AH_GRH))
+               /* No GIDs. Compare LIDs */
+               return (sattr.dlid && (lattr.dlid == sattr.dlid));
+       if ((lattr.ah_flags & IB_AH_GRH) && (sattr.ah_flags & IB_AH_GRH))
+               /* check if GIDs are equal */
+               return (!memcmp(lattr.grh.dgid.raw, sattr.grh.dgid.raw, 16));
+       /* one has GID, other does not.  Assume different dest */
+       return 0;
+}
+
+static int check_dup_send_mad(struct ib_mad_agent_private *agent,
+                             struct ib_mad_send_wr_private *send_wr)
+{
+       struct ib_mad_send_wr_private *t;
+
+       if (!is_rmpp_data(send_wr->send_buf.mad))
+               return 0;
+       list_for_each_entry(t, &agent->wait_list, agent_list) {
+               if (t->tid == send_wr->tid &&
+                   send_has_same_class(t, send_wr) &&
+                   send_has_same_gid(agent, t, send_wr))
+                       return 1;
+       }
+
+       /*
+        * It's possible to send a duplicate mad before we've
+        * been notified that the first send has completed
+        */
+       list_for_each_entry(t, &agent->send_list, agent_list) {
+               if (is_rmpp_data(t->send_buf.mad) &&
+                   t->tid == send_wr->tid && send_has_same_class(t, send_wr) &&
+                   send_has_same_gid(agent, t, send_wr)) {
+                       /* Verify request has not been canceled */
+                       return (send_wr->status == IB_WC_SUCCESS) ?  1 : 0;
+               }
+       }
+       return 0;
+}
+
 /*
  * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated
  *  with the registered client
@@ -1102,6 +1198,12 @@ int ib_post_send_mad(struct ib_mad_send_
                /* Reference MAD agent until send completes */
                atomic_inc(&mad_agent_priv->refcount);
                spin_lock_irqsave(&mad_agent_priv->lock, flags);
+               if (check_dup_send_mad(mad_agent_priv, mad_send_wr)) {
+                       /* Duplicate send request */
+                       spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+                       atomic_dec(&mad_agent_priv->refcount);
+                       return -EBUSY;
+               }
                list_add_tail(&mad_send_wr->agent_list,
                              &mad_agent_priv->send_list);
                spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to